/* =========================================================================
   CSS Cascade Layers — explizite Cascade-Ordnung für strukturiertes Styling.
   Spätere Layer haben Vorrang (außer bei !important, das genau umgekehrt
   funktioniert). Aktuell deklariert für künftige Refactorings — neue Styles
   können ohne Specificity-Wars in eine entsprechende Layer kommen, statt
   !important zu missbrauchen.
   - reset:      Browser-Defaults reset/normalize
   - base:       Typografie, Color-Vars, html/body
   - components: Sections, Hero, Cards, Lightbox, Header
   - mobile:     Mobile @media Override-Block
   - utilities:  Helper-Klassen, .visually-hidden, etc.
   ========================================================================= */
@layer reset, base, components, mobile, utilities;

/* =========================================================================
   Reduced Motion — User-Setting im OS/Browser ("Reduce Motion") respektieren.
   Killt Animationen und Transitions weitgehend, lässt Funktionalität intakt.
   Wichtig für Vestibulär-Empfindliche und User mit aktiviertem iOS/macOS-
   Zugänglichkeits-Setting.
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* =========================================================================
   View Transitions API — Same-Document Smooth-Crossfade beim Anchor-Sprung.
   Browser ohne Support (Firefox aktuell, ältere Safari) ignorieren das
   einfach. Auf Chrome/Edge/Safari TP gibt's einen butterweichen Übergang
   beim Section-Wechsel ohne JS.
   ========================================================================= */
@view-transition {
    navigation: auto;
}

/* Reduce-Motion: View-Transitions ebenfalls killen, sonst werden Animationen
   trotz prefers-reduced-motion: reduce auf den ::view-transition Layern aktiv. */
@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*),
    ::view-transition-old(*),
    ::view-transition-new(*) {
        animation: none !important;
    }
}

/* Visually-hidden Helper — Inhalt für Screen Reader sichtbar, optisch
   ausgeblendet. Für a11y-Texte (z. B. "Hauptinhalt überspringen") in
   semantischen Elementen, ohne das Layout zu beeinflussen. */
.visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Fonts */
@font-face {
    font-family: 'Apfel Grotezk Fett';
    src: url('./Fonts/ApfelGrotezk-Fett.woff2') format('woff2'),
        url('./Fonts/ApfelGrotezk-Fett.woff') format('woff');
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Apfel Grotezk Satt';
    src: url('./Fonts/ApfelGrotezk-Satt.woff2') format('woff2'),
        url('./Fonts/ApfelGrotezk-Satt.woff') format('woff');
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Apfel Grotezk';
    src: url('./Fonts/ApfelGrotezk-Regular.woff2') format('woff2'),
        url('./Fonts/ApfelGrotezk-Regular.woff') format('woff');
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

/* Mittel = Medium-Schnitt zwischen Regular und Fett */
@font-face {
    font-family: 'Apfel Grotezk Mittel';
    src: url('./Fonts/ApfelGrotezk-Mittel.woff2') format('woff2'),
        url('./Fonts/ApfelGrotezk-Mittel.woff') format('woff');
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

/* ----------------------------------------------------------------------
   Metrisch angepasste Fallback-Schriften.
   Greifen NUR, wenn die Adobe Fonts (Typekit) per DSGVO-Einwilligung
   abgelehnt oder nicht geladen werden — dann erbt jeder Text-Stack statt
   der nackten System-Generik diese auf die System-Schrift abgestimmte
   Variante. `size-adjust` wurde gegen die echten Adobe-Schnitte gemessen
   (Zeichenbreite Adobe / System), damit die Laufweite — und damit alle
   manuell gesetzten Zeilenumbrüche und Spaltenhöhen — exakt erhalten
   bleiben. line-height ist überall unitless, der Zeilenabstand bleibt also
   ohnehin konstant; die Breite ist der entscheidende Hebel.
     • acumin-variable  ~ Arial   (Adobe = 98.8 % der Arial-Breite)
     • neulis-sans      ~ Arial   (Adobe = 108.5 %)
     • eskorte-latin    ~ Georgia (Adobe = 103.9 %)
   ---------------------------------------------------------------------- */
@font-face {
    font-family: 'acumin-fb';
    src: local('Arial'), local('Helvetica Neue'), local('Roboto');
    size-adjust: 98.8%;
}
@font-face {
    font-family: 'neulis-fb';
    src: local('Arial'), local('Helvetica Neue'), local('Roboto');
    size-adjust: 108.5%;
}
@font-face {
    font-family: 'eskorte-fb';
    src: local('Georgia'), local('Times New Roman');
    size-adjust: 103.9%;
}

/* Kein scrollbar-gutter mehr: reservierter Platz ist bei ueberlagernden
   Leisten (Safari) als heller Streifen dauerhaft sichtbar. Stattdessen aendert
   der Intro-Loader das Layout gar nicht mehr — er sperrt das Scrollen ueber
   abgefangene Eingaben (siehe introLoader in script.js). Die Leiste bleibt
   dadurch die ganze Zeit unveraendert, nichts springt und nichts blitzt auf. */

html {
    scroll-behavior: smooth;
    /* 0 = Section.top landet direkt am Viewport.top. Kein „Peek" des
       vorherigen Section-Contents durch die backdrop-blurred Pill mehr.
       Header-Clearance wird stattdessen über das interne section padding-top
       erreicht (jetzt 110px statt 80px). */
    scroll-padding-top: 0;
    -webkit-tap-highlight-color: transparent;
}

a, button, .hamburger, .scroll-top-btn,
.lightbox-close, .lightbox-prev, .lightbox-next,
.bento-grid .card:not(.no-zoom) img,
.hero-scroll-arrow {
    touch-action: manipulation;
}

:root {
    --col-primary: #4E47E0;
    --col-secondary: #67EEF5;
    --col-accent: #C240A6;
    --col-offblack: #100C1A;
    --col-offwhite: #FEFDFF;

    --border-radius-l: 27px;
    --border-radius-m: 27px;
    --grid-gap: 11px;
    --container-width: 1440px;
    /* Container Side-Padding — wird per Breakpoint überschrieben.
       Sections und Hero-Overlay leiten ihre Mindest-Margin von dieser
       Variable ab → kein Element ragt je bis an den Bildschirmrand. */
    --container-pad: 88px;

    --font-size-h-small: 1.5rem;
    --col-error: #F44336;
}

/* Style */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    background-color: var(--col-offwhite);
    color: var(--col-offblack);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
    overscroll-behavior: none;
}

/* =====================================================================
   Tastatur-Fokus: nur bei Keyboard-Navigation (nicht bei Mausklick)
   sichtbar. col-accent hebt den aktuell fokussierten Trefferbereich
   deutlich hervor — ohne Maus-Nutzer mit Outlines zu nerven.
   ===================================================================== */
:focus {
    outline: none;
}

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

/* Bei runden/pillförmigen Elementen den Outline-Radius angleichen */
.nf-btn:focus-visible,
.hero-pill:focus-visible,
.lightbox-prev:focus-visible,
.lightbox-next:focus-visible,
.lightbox-close:focus-visible {
    border-radius: 999px;
}

/* Typografie */
p {
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 10pt;
    line-height: 14pt;
    font-variation-settings: "wdth" 75;
}

h1,
h2,
h3,
h4,
h5,
h6 {
    font-kerning: normal;
}

h1,
h4 {
    font-family: 'Apfel Grotezk Satt', sans-serif;
    font-weight: 400;
}

#downloads h2 {
    padding-left: 30px;
}

#members h3 {
    margin-bottom: 20px;
}

/* scroll-margin-top: 0 — Section.top landet exakt am Viewport.top.
   Kein Vor-Section-Peek durch das backdrop-blur der Pill. H1-Clearance
   wird stattdessen über das interne section padding-top (110px) erreicht. */
#start,
#lebenslauf,
#members,
#event-branding,
#social-media,
#logo-design,
#downloads {
    scroll-margin-top: 0;
}

h3 {
    font-family: 'Apfel Grotezk Mittel', sans-serif;
    font-weight: 400;
    font-size: 1.8rem;
    color: var(--col-offblack);
}

h4,
h5 {
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: var(--font-size-h-small);
}

h5 {
    font-weight: 700;
}

h2 {
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-weight: 300;
    font-size: 2.2rem;
    text-transform: uppercase;
    color: var(--col-primary);
}

h1 {
    font-family: 'Apfel Grotezk Satt', sans-serif !important;
    font-weight: 400 !important;
    font-size: 3.5rem;
    color: var(--col-primary);
}

.section-title h1 {
    text-decoration: none;
}

img {
    max-width: 100%;
    height: auto;
    display: block;
    object-fit: cover;
}

/* Grid */
.container {
    max-width: var(--container-width);
    margin: 0 auto;
    padding: 0 var(--container-pad);
    position: relative;
}

.bento-grid {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: var(--grid-gap);
    margin-bottom: 40px;
}

.bento-grid:last-child {
    margin-bottom: 0;
}

.card {
    border-radius: var(--border-radius-l);
    overflow: hidden;
    background-color: var(--col-offwhite);
    padding: 30px;
    display: flex;
    flex-direction: column;
}

.card.dark {
    background-color: var(--col-primary);
    color: var(--col-offwhite);
}

.card.offwhite {
    background-color: var(--col-offwhite);
}

.card.no-padding {
    padding: 0;
}

/* Device-Mockup (Social-Media): Bildecken an die abgerundeten Geraete-Ecken
   anpassen, damit die rechteckigen Ecken nicht ueberstehen. Prozentwerte
   gleichen das Seitenverhaeltnis (1171x2400) aus, sodass die Ecken kreisfoermig
   bleiben und mit der Breite skalieren (entspricht ~190px im Original).
   Hohe Spezifitaet + !important schlagen die Mobile-Regel `.card.no-padding img`.
   Radius per Pixel-Analyse des soliden Geraetekoerpers gemessen: ~202px / 1171px
   ~ 17.3% (vertikal 8.45% gleicht das Seitenverhaeltnis aus -> kreisfoermig). */
.card.no-padding img.device-mockup {
    border-radius: 17.3% / 8.45% !important;
}

/* Die zugehoerige Karte hat overflow:visible und wirft beim Hover einen
   box-shadow, der der Border-Box (= ihrem border-radius) folgt. Damit der
   Schatten dem runden Geraet folgt und nicht mit den eckigeren Standard-27px
   ueber die Bildecken hinaussteht, bekommt die Karte denselben Radius wie das
   Bild. Karte und Bild haben dieselbe Box (image fuellt die padding-lose Card)
   -> gleiche Prozentwerte ergeben deckungsgleiche Ecken. */
#social-media .sm-left .card {
    border-radius: 17.3% / 8.45% !important;
}

/* Navigation */
header {
    position: sticky;
    top: 0;
    z-index: 1000;
    margin-bottom: -120px;
    opacity: 0;
    transform: translateY(-100%);
    transition: opacity 0.4s ease, transform 0.4s ease;
    pointer-events: none;
}

header.header--visible {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.nav-pill {
    padding: 0 30px;
    height: 90px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    position: relative;
    z-index: auto;
    color: var(--col-offwhite);
}

.hamburger {
    display: none;
}

.logo {
    display: flex;
    align-items: center;
    text-decoration: none;
    align-self: flex-end;
    height: 70px;
}

.logo img {
    height: 100%;
    width: auto;
}

.main-nav {
    margin: 0;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    pointer-events: none;
}

.main-nav ul {
    pointer-events: auto;
    display: flex;
    list-style: none;
    background-color: #4E47E0d9;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    padding: 0 40px;
    height: 50px;
    align-items: center;
    border-radius: 27px;
    width: 100%;
    justify-content: space-between;
}

/* Container für SVG-Filter-Definitionen (#nav-glass) — nimmt keinen Platz ein */
.svg-filters {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
    pointer-events: none;
}

/* Liquid-Glass-Nav (Desktop).
   - Inset-Highlight oben = beleuchtete Glaskante, dunkle Unterkante = Dicke
   - html.lg-glass (nur Chromium, siehe script.js): url(#nav-glass) bricht den
     Hintergrund per SVG-Displacement.
   - Tönung überall gleich 85 % (#4E47E0d9): darunter fällt der Kontrast der
     offwhite Nav-Schrift über hellen Sections unter WCAG AA (4.5:1). Damit die
     Verzerrung durch die 85 % trotzdem sichtbar bleibt, verstärkt
     contrast(2.5) den Hintergrund vorher. Unkritisch für die Lesbarkeit:
     Worst Case bleibt ein weißer Hintergrund, heller als Weiß wird nichts.
   - blur(2px) statt 12px lässt die Verzerrung erkennbar, saturate(180%) lässt
     Farben dahinter leuchten. */
@media (min-width: 992px) {
    .main-nav ul {
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, 0.36),
            inset 0 -1px 0 rgba(16, 12, 26, 0.12);
    }
    html.lg-glass .main-nav ul {
        backdrop-filter: url(#nav-glass) blur(2px) contrast(2.5) saturate(180%);
    }
}
@media (min-width: 992px) and (prefers-reduced-transparency: reduce) {
    html.lg-glass .main-nav ul {
        backdrop-filter: blur(12px);
    }
}

.main-nav a {
    font-family: 'Apfel Grotezk Fett', sans-serif;
    color: var(--col-offwhite);
    text-decoration: none;
    font-weight: normal;
    font-size: 1.1rem;
    position: relative;
    transition: color 0.3s;
    white-space: nowrap;
}

@media (hover: hover) {
    .main-nav a:hover {
        color: var(--col-secondary);
    }
}

.main-nav a.nav-highlight {
    color: var(--col-accent);
}

.main-nav a.active::after {
    content: '';
    position: absolute;
    bottom: -4px;
    left: 0;
    width: 100%;
    height: 2.5px;
    background-color: currentColor;
    border-radius: 1.25px;
}

/* Hero-Sektion */
#start {
    padding: 0 !important;
    margin: 0 !important;
    width: auto;
    margin-inline: calc(50% - 50vw) !important;
    height: calc(100svh + 30px);
    overflow: hidden;
    display: block;
    line-height: 0;
    font-size: 0;
    position: relative;
}

#start img {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
    /* right top: bei schmalen Desktop-Viewports (992-1199 portrait, z. B.
       iPad Pro hochkant) wird das Bild nach rechts ausgerichtet — Kai sitzt
       im rechten Drittel des Hero-Bildes, würde bei "center" rechts
       abgeschnitten werden. Bei vollem Desktop (≥1440) passt das Bild
       exakt → object-position hat dann keinen Effekt. */
    object-position: right top;
}

.hero-overlay {
    position: absolute;
    top: 28%;
    left: calc(max((100vw - var(--container-width)) / 2, 0px) + var(--container-pad));
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    z-index: 2;
    width: max-content;
}

.hero-overlay h1 {
    color: var(--col-primary);
    font-family: 'Apfel Grotezk Satt', sans-serif;
    font-size: clamp(4rem, 7vw, 8rem);
    line-height: 1.0;
}

.hero-pill {
    background-color: var(--col-primary);
    color: white;
    padding: 10px 30px;
    border-radius: 50px;
    font-family: 'Apfel Grotezk', sans-serif;
    font-size: clamp(1.15rem, 1.8vw, 1.8rem);
    font-weight: 400;
    line-height: normal;
    text-align: center;
    box-sizing: border-box;
}

@keyframes hero-arrow-bounce {
    0%, 100% { transform: rotate(180deg) translateY(0); }
    50%      { transform: rotate(180deg) translateY(-10px); }
}

.hero-scroll-arrow {
    transform: rotate(180deg);
    z-index: 2;
    transition: transform 0.3s;
    line-height: 0;
    animation: hero-arrow-bounce 1.8s ease-in-out infinite;
}

.hero-scroll-arrow--desktop {
    position: absolute;
    bottom: 60px;
    left: calc(max((100vw - var(--container-width)) / 2, 0px) + var(--container-pad));
}

.hero-scroll-arrow--mobile {
    position: relative;
    align-self: flex-start;
    display: none;
}

#start .hero-scroll-arrow img {
    width: 50px;
    height: auto;
    transition: opacity 0.3s;
    object-fit: contain;
}

.hero-scroll-arrow .icon-hover {
    position: absolute;
    top: 0;
    left: 0;
    opacity: 0;
}

@media (hover: hover) {
    .hero-scroll-arrow:hover .icon-default {
        opacity: 0;
    }

    .hero-scroll-arrow:hover .icon-hover {
        opacity: 1;
    }

    .hero-scroll-arrow:hover {
        transform: rotate(180deg) translateY(8px);
        animation-play-state: paused;
    }
}

/* =======================================================
   Intro & Start Grid
   ======================================================= */
/* Hinweis: Die früheren .intro-*/#intro-start CSS-Regeln (Intro-Section
   die nie/nicht mehr existiert) wurden entfernt — waren ~50 Zeilen Dead
   Code. Falls ihr je wieder eine Intro-Section braucht, neu definieren. */

/* Backgrounds und Sections */
.section-wrapper-offwhite {
    background-color: var(--col-offwhite);
    border-radius: 0;
    /* padding-top: 110px statt 80px — schafft Innen-Buffer, damit das H1
       unter der 90px-Pill landet, ohne dass wir einen Anchor-Offset
       brauchen (der sonst den Vor-Section-Peek erzeugen würde). */
    padding: 110px 40px 80px 40px;
    /* margin-bottom: 40px entfernt — war auf offwhite-zu-offwhite ohnehin
       unsichtbar, addierte aber 40px zur Inter-Section-Lücke. Vorher waren
       200px Gesamt-Gap (40 margin + 80+80 padding), jetzt 160px. */
    margin-bottom: 0;
    width: auto;
    margin-inline: calc(50% - 50vw);
    /* Inner content fluchtet mit Container-Content; max() garantiert
       dass Padding NIE unter --container-pad fällt — sonst würde bei
       schmalen Viewports der calc negativ → Section-Content edge-to-edge. */
    padding-left: max(var(--container-pad), calc((100vw - var(--container-width)) / 2 + var(--container-pad)));
    padding-right: max(var(--container-pad), calc((100vw - var(--container-width)) / 2 + var(--container-pad)));
}

.section-title,
#downloads h2 {
    margin-bottom: 10px;
    display: flex;
    align-items: baseline;
    gap: 10px;
}

#members h3,
#event-branding h3,
#social-media h3,
#logo-design h3 {
    margin-top: 0;
    margin-bottom: 20px;
}

/* Lebenslauf */
#lebenslauf {
    padding-top: 110px;
    padding-bottom: 80px;
}

/* Harmonisiertes padding-top: 160px für ALLE navigablen Sections (Desktop).
   Sicherer Buffer unter der 90px-Header-Pill für alle Title-Layout-Varianten
   (nur-H1 vs H1+H2-Baseline-Flex). Beim Nav-Klick landet jede Section auf
   derselben Y-Position — kein springender Anchor-Landing-Punkt mehr.

   Hintergrund: Vorher hatten nur #members/#event-branding diesen 160px-
   Override (weil dort die H1+H2-Baseline-Flex die H1 visuell höher zog).
   Die gleiche Struktur in #social-media/#logo-design wurde vergessen, und
   #lebenslauf/#downloads hatten andere Werte (110/80px) — Ergebnis war,
   dass beim Nav-Klick die jeweilige Section unterschiedlich hoch landete.

   Mobile-Override (40px) bei @media (max-width: 991px) für #lebenslauf,
   #members, #event-branding, #social-media, #logo-design bleibt erhalten
   und überschreibt diesen Desktop-Wert via Mobile-Media-Query. */
#lebenslauf,
#members,
#event-branding,
#social-media,
#logo-design {
    padding-top: 160px !important;
}

#lebenslauf .section-title {
    margin-bottom: 10px;
}

.cv-block {
    margin-bottom: 50px;
}

.cv-block:last-child {
    margin-bottom: 0;
}

.cv-block h3 {
    font-size: 1.8rem;
    /* margin-bottom: 2px (statt 20px wie bei anderen Sections), weil die
       erste .cv-entry bereits 18px padding-top hat (für die Hover-Bg-Pille).
       Effektiver Visual-Abstand h3 → erster Text = 2 + 18 = 20px, matcht
       damit den Rhythmus der anderen Section-h3s (z. B. #members h3 → Card-
       Kante = 20px). */
    margin-bottom: 2px;
}

.cv-timeline {
    display: flex;
    flex-direction: column;
}

.cv-entry {
    display: flex;
    gap: 11px;
    /* Horizontale Padding + negative Margin: Hover-Bg extendet leicht über
       den Content hinaus, visuell bleibt das Layout aber identisch. */
    padding: 18px 14px;
    margin: 0 -14px;
    /* Alle Ecken abgerundet → jede Reihe wirkt wie eine eigene Pill/Card. */
    border-radius: 8px;
    transition: background-color 0.2s ease;
}

/* Hover nur auf Geräten mit echtem Hover-Pointer (Maus/Trackpad) — auf Touch
   würde der Hover-State nach Tap "sticky" bleiben bis man irgendwo anders
   tippt, was die UX kaputt macht. */
@media (hover: hover) {
    .cv-entry:hover {
        background-color: #f1f2f4;
    }
}
.cv-entry:focus-within {
    background-color: #f1f2f4;
}

@media (prefers-reduced-motion: reduce) {
    .cv-entry { transition: none; }
}

.cv-date {
    width: 175px;
    flex-shrink: 0;
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 0.95rem;
    /* Vorher #999 (Kontrast 2.81) → failt WCAG AA. Jetzt #6B6B6B (4.65) → passt AA. */
    color: #6B6B6B;
    padding-top: 2px;
    transition: color 0.2s ease;
}

/* Hover: linker Label-Text in Brand-Lila. */
@media (hover: hover) {
    .cv-entry:hover .cv-date {
        color: var(--col-primary);
    }
}
.cv-entry:focus-within .cv-date {
    color: var(--col-primary);
}

.cv-details {
    flex: 1;
}

.cv-details strong {
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 1rem;
    font-weight: 700;
    color: var(--col-offblack);
    margin-bottom: 2px;
}

.cv-details p {
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 1rem;
    line-height: 1.5;
    color: #555;
    font-variation-settings: "wdth" 100;
    margin: 0;
}

/* Downloads */
.downloads-wrapper {
    background-color: var(--col-offwhite);
    /* padding-top: 160px matcht alle anderen Sections (siehe Z. 581-600),
       damit beim Nav-Klick auf #downloads die H1 auf derselben Y-Position
       landet wie bei den anderen Section-Anchors. */
    padding: 160px 40px 80px 40px;
    border-radius: 0;
    grid-column: span 12;
    width: auto;
    margin-inline: calc(50% - 50vw);
    padding-left: max(var(--container-pad), calc((100vw - var(--container-width)) / 2 + var(--container-pad)));
    padding-right: max(var(--container-pad), calc((100vw - var(--container-width)) / 2 + var(--container-pad)));
}

.download-card {
    grid-column: span 6;
    background-color: #f1f2f4;
    padding: 20px;
    border-radius: 27px;
    position: relative;
    min-height: auto;
    display: flex;
    flex-direction: column;
    gap: 20px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
}

.download-card h3 {
    /* Negative margin-bottom kompensiert die flex-gap (20px) → effektiver
       h3→p-Gap = 8px, Text-to-Text ≈ 20px (analog zum CV-h3-Abstand).
       Der nachfolgende p→Button-Gap bleibt unverändert bei 20px, da nur
       h3.margin-bottom verschoben wird. */
    margin-bottom: -12px;
}

.download-card p {
    color: var(--col-offblack);
    font-size: 1rem;
    line-height: 1.6;
    margin-bottom: 0;
}

.download-btn {
    font-family: 'Apfel Grotezk Fett', sans-serif;
    background-color: var(--col-primary);
    color: var(--col-offwhite);
    border: none;
    padding: 10px 25px 14px 25px;
    /* 9999px > halbe Button-Höhe in jedem Breakpoint → echte Pill-Form
       (Browser clampt automatisch auf height/2). Funktioniert konsistent
       auf Desktop, Mobile, Tablet ohne pro-Viewport-Anpassung. */
    border-radius: 9999px;
    font-size: 1.6rem;
    cursor: pointer;
    transition: transform 0.2s, background-color 0.3s;
    width: 100%;
    position: relative;
    z-index: 2;
    box-shadow: 0 4px 10px rgba(16, 12, 26, 0.4);
    display: flex;
    justify-content: center;
    align-items: center;
}

@media (hover: hover) {
    .download-btn:hover {
        background-color: var(--col-primary);
        color: var(--col-secondary);
        transform: translateY(-2px);
    }
}

/* Footer */
.footer-bg-wrapper {
    background-color: transparent;
    overflow: hidden;
    margin-top: calc(var(--border-radius-l) * -1);
    position: relative;
    z-index: 10;
}

footer#footer-kontakt {
    background-color: var(--col-primary);
    color: var(--col-offwhite);
    padding: 110px 0 110px 0;
    margin-top: 0;
    border-radius: var(--border-radius-l) var(--border-radius-l) 0 0;
    position: relative;
    text-align: left;
}

/* Footer-Bottom-Fill: ein dünner Streifen direkt unter dem Footer in derselben
   Farbe wie der Footer. Erweitert den visuellen Footer-Bereich um die Safe-
   Area-Inset-Bottom + Reserve-Höhe, sodass der Bereich zwischen Footer-Edge
   und Viewport-Bottom (auf iPhone Safari mit viewport-fit=cover die Home-
   Indicator-Region) NICHT mehr Cyan, sondern Lila ist. */
.footer-bottom-fill {
    background-color: var(--col-primary);
    height: calc(env(safe-area-inset-bottom, 0px) + 80px);
    margin: 0;
    padding: 0;
    pointer-events: none;
}

.footer-layout {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 40px;
}

.footer-text-area {
    flex: 1;
    width: 100%;
}

.footer-text-area h1 {
    color: var(--col-offwhite);
    margin-bottom: 10px;
}

footer#footer-kontakt :not(h1) {
    font-variation-settings: "wdth" 75;
}

.footer-columns {
    display: flex;
    gap: 40px;
    width: fit-content;
}

.footer-col-left {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 30px;
}

.footer-col-right {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 30px;
}

.footer-col-left p,
.footer-col-right p {
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 1rem;
    line-height: 1.6;
    margin-bottom: 0;
    opacity: 1;
}

.footer-contact-list {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.footer-contact-item {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 1rem;
    line-height: 1.6;
    color: var(--col-offwhite);
}

.footer-icon,
.footer-icon-wrap {
    flex-shrink: 0;
}

.footer-contact-link {
    text-decoration: none;
    transition: color 0.3s;
}

@media (hover: hover) {
    .footer-contact-link:hover {
        color: var(--col-secondary);
    }
}

.footer-icon {
    width: 18px;
    height: 18px;
}

.footer-icon-wrap {
    position: relative;
    width: 18px;
    height: 18px;
    line-height: 0;
}

.footer-icon-wrap .icon-hover {
    position: absolute;
    top: 0;
    left: 0;
    opacity: 0;
    transition: opacity 0.3s;
}

.footer-icon-wrap .icon-default {
    transition: opacity 0.3s;
}

@media (hover: hover) {
    .footer-contact-link:hover .icon-default {
        opacity: 0;
    }

    .footer-contact-link:hover .icon-hover {
        opacity: 1;
    }
}

.footer-col-right a {
    color: var(--col-offwhite);
    text-decoration: none;
    transition: opacity 0.3s;
}

@media (hover: hover) {
    .footer-col-right a:hover {
        color: var(--col-secondary);
        opacity: 1;
    }
}

.footer-legal-links {
    margin-top: 20px;
    display: flex;
    gap: 25px;
}

.footer-legal-links a {
    color: var(--col-offwhite);
    opacity: 0.6;
    text-decoration: none;
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 0.85rem;
    transition: opacity 0.3s;
}

@media (hover: hover) {
    .footer-legal-links a:hover {
        color: var(--col-secondary);
        opacity: 1;
    }
}

.scroll-top-btn {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    width: 164px;
    height: auto;
    background-color: transparent;
    border-radius: 0;
    text-decoration: none;
    transition: transform 0.3s;
    box-shadow: none;
    flex-shrink: 0;
    margin-left: 40px;
    margin-top: 0;
}

.scroll-top-btn img {
    width: 50px;
    height: auto;
    object-fit: contain;
    transition: opacity 0.3s;
}

.scroll-top-btn .icon-hover {
    position: absolute;
    opacity: 0;
}

@media (hover: hover) {
    .scroll-top-btn:hover .icon-default {
        opacity: 0;
    }

    .scroll-top-btn:hover .icon-hover {
        opacity: 1;
    }

    .scroll-top-btn:hover {
        transform: translateY(-5px);
    }
}

/* Animationen & Image Utils */
.section-title img,
#downloads h2 img {
    height: 1em;
    margin-left: 10px;
}

#downloads h2 {
    color: var(--col-offblack);
    margin-bottom: 20px;
    display: flex;
    align-items: baseline;
    gap: 10px;
}

/* Section Utilities */
.section-transparent {
    background-color: transparent;
}

.section-gap {
    padding-top: 110px;
    padding-bottom: 80px;
}

/* Corporate Design Section */
.cd-logo-cards .card {
    background-color: #f1f2f4;
    border-radius: var(--border-radius-l);
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 60px 40px;
    aspect-ratio: 1;
    overflow: hidden;
}

/* Logo-SVGs haben nur viewBox, kein explicit width/height. Ohne max-width
   würden sie ihre natürliche Pixelgröße nehmen und auf engen Cards (Mobile
   ~120px Content-Breite) horizontal überschießen — das Adlersignet wurde
   rechts angeschnitten. max-width 100% lässt das SVG proportional in die
   Card skalieren, height auto bewahrt aspect-ratio. */
.cd-logo-cards .card img {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
}

.cd-color-cards .color-card {
    border-radius: var(--border-radius-l);
    padding: 20px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    aspect-ratio: 1;
}

.color-vals {
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 0.8rem;
    line-height: 1.4;
    margin-top: auto;
}

.color-vals .val-row {
    display: flex;
    justify-content: space-between;
    border-bottom: 1px dotted rgba(255, 255, 255, 0.4);
    padding-bottom: 2px;
    margin-bottom: 2px;
}

.color-vals .val-row:last-child {
    border-bottom: none;
    margin-bottom: 0;
}

/* :not(:last-child) — sonst gewinnt diese Regel (gleiche Spezifitaet, spaeter
   im Code) gegen .val-row:last-child und die letzte Zeile bekommt wieder
   eine Linie (gelbe Kachel, CMYK). */
.color-vals.dark-text .val-row:not(:last-child) {
    border-bottom: 1px dotted rgba(0, 0, 0, 0.2);
}

.cd-text {
    -webkit-hyphens: auto;
    hyphens: auto;
    word-wrap: break-word;
    overflow-wrap: break-word;
    /* Optischer Randausgleich (Vorgaben Punkt 4): Satzzeichen ragen leicht
       über die Kante hinaus, damit das Auge den Rand als gerader wahrnimmt.
       Funktioniert in Safari zuverlässig, Chromium-Browsern (noch) nicht
       durchgängig — ist als Progressive Enhancement ungefährlich. */
    hanging-punctuation: first last allowed-end;
}

/* Utility-Klasse: hält Wörter/Phrasen als unbrechbare Einheit zusammen.
   Verwendung für Eigennamen mit internen Bindestrichen (Down-Sportlerfestival,
   ID-1-Format) oder Schriftnamen, wo Mehr-Wort-&nbsp;-Sequenzen umständlich
   wären. Plus: deaktiviert hyphens für Wörter wie "eigener" oder "dabei",
   die durch hyphens:auto sonst auto-getrennt würden. */
.nowrap {
    white-space: nowrap;
    -webkit-hyphens: none;
    hyphens: none;
}

.cd-text p {
    font-variation-settings: "wdth" 100;
    /* Vorgaben Punkt 6: Hurenkinder vermeiden — keine Schluss-Zeile mit nur
       1-2 kurzen Wörtern. text-wrap: pretty (Chrome 117+, Safari 17.5+)
       optimiert Zeilenumbrüche browserseitig zugunsten ausgewogener Schluss-
       Zeilen. Älterer Browser fallen graceful auf normales Wrapping zurück. */
    text-wrap: pretty;
}

/* Desktop: hartkodierte Umbrüche aus Portfolio-PDF (siehe <br> + &shy; im
   HTML). Auto-Hyphenation und text-wrap: pretty werden deaktiviert, damit
   der Browser keine zusätzlichen Trennstriche einfügt oder die Umbrüche
   verschiebt. Mobile (< 992px) behält Auto-Hyphenation und Pretty-Wrap, da
   die <br> dort via .cd-text br { display: none } ausgeblendet werden. */
@media (min-width: 992px) {
    .cd-text {
        -webkit-hyphens: manual;
        hyphens: manual;
    }
    /* Fließtext-Override für Desktop: 11.5pt + leicht erhöhter Zeilenabstand.
       PDF-Ratio 14/10 = 1.4 ergäbe 16.1pt — wir gehen auf 17pt (Ratio ~1.48),
       leicht über PDF-Ratio, gibt etwas mehr Luft.
       Spezifität .cd-text p (0,0,1,1) gewinnt gegen globales p {
       font-size: 10pt; line-height: 14pt } (0,0,0,1). Die Inline-Styles auf
       den <div class="cd-text" style="font-size: 14pt; line-height: 1.4">
       sind damit jetzt obsolet — werden aber gelassen, weil Cleanup separate
       Refactor wäre. Mobile (< 992px) bleibt bei globaler p-Regel (10pt). */
    .cd-text p {
        /* Fluid-Type: skaliert linear zwischen 7pt @ 992px und 11.5pt @ 1440px.
           Verhindert ungewollte Browser-Wraps in den hartkodierten <br>-Zeilen
           auf schmaleren Desktop-Viewports.

           Spalten-Math (cd-text spannt 2 von 6 inner-cols bzw. 2 von 12 outer):
             • 992px Viewport:  Container 816px → 12-Col à 57.92px → cd-text 126.83px
             • 1200px Viewport: Container 1024px → 12-Col à 75.25px → cd-text 161.5px
             • 1440px Viewport: Container 1264px → 12-Col à 95.25px → cd-text 201.5px

           Längste EN-Zeile „vocational school was a new" (17 chars bold + 10 regular):
             • em-Breite ≈ 13.1em (Acumin Regular ~0.46em, Bold ~0.50em)
             • Bei 9.625pt @ 1200px (alte Clamp): ~168px Bedarf → Überlauf um ~6px ❌
             • Bei 9.09pt @ 1200px (neue Clamp): ~159px Bedarf → passt knapp ✓

           clamp(min, fluid, max):
             • min  7pt:      Untergrenze bei 992px (knappe Fits für längste Zeilen)
             • fluid:         linearer Anstieg von 7pt → 11.5pt zwischen 992 und 1440px
             • max  11.5pt:   Obergrenze ab 1440px

           Slope 4.5pt/448px statt 3.5pt/448px → aggressiveres Schrumpfen bei
           schmalen Viewports, damit auch lange Zeilen mit Bold-Anteilen fitten.

           Letter-spacing -0.005em → minimal komprimiert, gibt nochmal ~0.13em
           pro Zeile zurück (bei 27 chars ~3.5px Reserve bei 12px Font).

           line-height als Ratio 1.48 (statt absolut 17pt), damit der Zeilen-
           abstand proportional zur Schrift mitskaliert. */
        font-size: clamp(7pt, calc(7pt + 4.5pt * (100vw - 992px) / 448px), 11.5pt);
        line-height: 1.48;
        letter-spacing: -0.005em;
        text-wrap: auto;
    }
}

.cd-text > p + p {
    margin-top: 1em;
}

.cd-text strong {
    /* InDesign-typisches „Bold" = 700 (Acumin Bold). 800 (Extra Bold)
       wirkte gegenüber der PDF-Vorlage zu klobig. */
    font-weight: 700;
}

/* Trennstrich-Span: sichtbar an PDF-Zeilenenden auf Desktop. Mobile (wo
   die hartkodierten <br> via .cd-text br { display: none } verschwinden)
   blenden wir auch den Bindestrich aus, damit das Wort „Seitenwechsel"
   statt „Seiten-wechsel" fließt. Ersetzt das frühere &shy;-Konstrukt,
   das bei vorgelagertem <br> nie als sichtbarer Trennstrich rendert. */
.cd-hy {
    /* Default: sichtbar (inline) */
}
@media (max-width: 991px) {
    .cd-hy { display: none; }
}

/* =========================================================================
   Grid-Layout-Toggle (Debug): „Standard" vs „12-Raster 1:1"
   ---------------------------------------------------------------------------
   Standard (Default): cd-text in WBM-Section sitzt auf inner-grid cols 4-5
   (direkt neben Logo-Karten, nur Gutter dazwischen).

   1:1 InDesign: cd-text wird auf cols 5-6 verschoben → Spalte 4 bleibt als
   sichtbarer Gap leer, analog zum InDesign-Layout der Portfolio-PDF.

   Override via !important nötig, weil die Position als inline-style auf
   dem Element gesetzt ist (`grid-column: 4 / span 2`).
   ========================================================================= */
/* =========================================================================
   PDF-Image-Match: Bild-Container auf PDF-Aspect-Ratios gelockt (Default).
   ---------------------------------------------------------------------------
   Maße extrahiert aus Portfolio_Kai_Schnubel.pdf (pdfplumber, A4 Landscape):

     Section            Bild                PDF (pt)    aspect (w/h)
     Corporate Design   Plakat Tourismus    226 × 333   226/333 (Portrait)
     Event-Branding     DSF-Plakat          226 × 319   ✓ File-Aspect matcht
     Social-Media       Device-Stack        169 × 347   169/347 (Portrait)
     Social-Media       Blogartikel ×3      107 × 134   107/134 (Portrait)
     Logo Design        Ladenfront          226 × 298   226/298 (Portrait)
     Logo Design        Tasse               224 × 145   224/145 (Landscape!)

   Selektoren via src*="..." statt alt*="...", weil mehrere Bilder mit
   überlappenden alt-Texten existieren können (z.B. Medaille-SVG-Overlay im
   Event-Branding mit alt="Medaille Down-Sportlerfestival").
   ========================================================================= */

/* Plakat Tourismus (Corporate Design): align-self stretch nimmt Row-Höhe,
   die durch andere Cells in derselben Row bestimmt wird → mit aspect-ratio
   gibt das Container seine eigene Höhe vor. img bleibt object-fit: cover
   (File-Aspect 1.48 matcht Container 1.47 nahezu exakt). */
#corporate-design .typo-img {
    aspect-ratio: 226 / 333;
    align-self: start;
}

/* Device-Stack (Social-Media, sm-left): PDF zeigt schmales Hochformat
   (169×347pt, h/w 2.05). File Device_3.png ist 1171×2400 = h/w 2.0496 → delta
   nur 0.18% zur PDF. Explizit locken für Konsistenz mit Logo-Design-Regeln. */
#social-media .card.no-padding:has(img[src*="Device_3"]) {
    aspect-ratio: 169 / 347;
}

/* Blogartikel-Cards (Social-Media, sm-col × 3): PDF zeigt 3 Phone-Mockups
   je 107×134pt (h/w 1.25). Files 1080×1350 = h/w 1.25 → delta 0.18%.
   src*="Blogartikel" matcht alle 3 Episode-Files (Episode 2/3/4). */
#social-media .card.no-padding:has(img[src*="Blogartikel"]) {
    aspect-ratio: 107 / 134;
}

/* Blogartikel-Cards Spaltenbreite: PDF zeigt die Phone-Mockups als ~2/12 Cols
   breit (107pt vs Device 169pt vs Page-Usable 701pt). Layout:
       Device(1-3)  Gap(4)  Blog1(5-6)  Blog2(7-8)  Blog3(9-10)  Empty(11-12)
   Col 4 bleibt leer = 1-Col-Gap zwischen Device und erstem Blogartikel
   (matcht PDF-Spacing: 68pt Gap zwischen Device-Stack und Phone 1). */
#social-media .sm-col {
    grid-column: span 2 !important;
}
/* Erstes sm-col explizit auf col 5, damit col 4 als Gap leer bleibt.
   :nth-child(2), weil 1. Kind das sm-left (Device) ist. */
#social-media .sm-col:nth-child(2) {
    grid-column: 5 / span 2 !important;
}

/* Ladenfront (Logo Design): flex: 1 + position: absolute → Bild folgt
   Container-Höhe, die durch Sibling-Stretching definiert wird. Lock auf
   PDF-Aspect macht Höhe deterministisch. */
#logo-design .card.no-padding:has(img[src*="Ladenfront"]) {
    aspect-ratio: 226 / 298;
    flex: 0 0 auto;
}

/* Tasse (Logo Design): Web-File ist Portrait (1894×2400, h/w 1.27), PDF
   zeigt aber Landscape-Crop (h/w 0.65). object-fit: cover croppt vertikal,
   d.h. Tassen-Oberkante/Unterkante werden beschnitten. */
#logo-design .card.no-padding:has(img[src*="Tasse"]) {
    aspect-ratio: 224 / 145;
    flex: 0 0 auto;
}

/* =========================================================================
   Lightbox Styles
   ========================================================================= */
/* Registriert, damit der Wert als Pixelzahl auslesbar ist. */
@property --lb-versatz {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}

.lightbox {
    /* Weg, den ein Bild beim Wechsel zur Seite zurueklegt. Bewusst klein: die
       Bewegung soll die Richtung andeuten, nicht das Bild verschieben.
       Registriert (siehe @property oben), damit getComputedStyle den Wert in
       Pixeln liefert — lightbox.js rechnet damit. */
    --lb-versatz: 44px;
    /* Off-State: vollständig transparent + ohne Blur. Beim Öffnen transitioned
       das Element zum On-State (siehe .lightbox.show + @starting-style unten).
       Beim Schließen läuft dieselbe Transition rückwärts → cinematic fade-out. */
    display: none;
    position: fixed;
    z-index: 9999;
    left: 0;
    top: 0;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
    background-color: rgba(0, 0, 0, 0);
    -webkit-backdrop-filter: blur(0) saturate(100%);
            backdrop-filter: blur(0) saturate(100%);
    cursor: zoom-out;
    opacity: 0;
    align-items: center;
    justify-content: center;
    /* 0.85s cinematic — bewusst langsam, damit Blur + Tint sichtbar einrollen
       statt nur kurz aufblitzen. Easing identisch zur restlichen Reveal-Familie.
       `display 0.85s allow-discrete` hält das Element während des Close-
       Übergangs sichtbar (display:flex bleibt aktiv) und switcht erst am
       Transition-Ende auf display:none. Modern: Chrome 117+ / Firefox 129+ /
       Safari 17.5+ — ältere Browser fallen sauber auf instant-show zurück. */
    transition:
        background-color 0.85s cubic-bezier(0.16, 1, 0.3, 1),
        -webkit-backdrop-filter 0.85s cubic-bezier(0.16, 1, 0.3, 1),
        backdrop-filter 0.85s cubic-bezier(0.16, 1, 0.3, 1),
        opacity 0.85s cubic-bezier(0.16, 1, 0.3, 1),
        display 0.85s allow-discrete;
    /* touch-action: none — Browser-Default-Gesten (native Pinch, Pan,
       Back-Swipe) komplett deaktiviert. JS handelt Pinch-Zoom, Pan und
       Swipe-Navigation eigenständig über touch-Events. Native Pinch-Zoom
       würde auf fixed-positioned-Elementen auf iOS Safari ohnehin nur die
       Page zoomen, nicht das Bild. */
    touch-action: none;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}

/* GPU-beschleunigtes Transform fürs gezoomte/gepannte Bild — verhindert
   ruckelige Repaints während Pinch/Pan. touch-action: none auf dem Bild
   selbst (zusätzlich zur .lightbox-Regel) verhindert, dass iOS Safari
   bei Pinch direkt auf das img-Element die native Zoom-Geste anwendet
   und unsere JS-Handler übergeht. */
.lightbox-content {
    transform-origin: 50% 50%;
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}

.lightbox-content,
.lightbox-prev img,
.lightbox-next img,
.lightbox-close img {
    -webkit-user-drag: none;
    -webkit-touch-callout: none;
    pointer-events: auto;
}

/* On-State: tint + blur + opacity 1. Beim .show-Add wird die Transition aus
   .lightbox auf diese Zielwerte angewendet → cinematic einblenden. Beim
   .show-Remove läuft dieselbe Transition zurück zum Off-State → cinematic
   ausblenden.

   Tint-Opacity 0.85: starke Abdunklung, max. Fokus aufs Bild. Blur ist jetzt
   nur noch subtil wahrnehmbar — saturate(150%) hält gerade so viel Farb-
   Information im Hintergrund, dass die Schicht nicht völlig flach wirkt. */
.lightbox.show {
    display: flex;
    opacity: 1;
    background-color: rgba(0, 0, 0, 0.85);
    /* Von 20px auf 10px reduziert: unter einer 85% deckenden schwarzen
       Flaeche ist der Unterschied kaum zu sehen, der Aufwand beim
       Zusammensetzen jedes Frames aber halbiert. */
    -webkit-backdrop-filter: blur(10px) saturate(130%);
            backdrop-filter: blur(10px) saturate(130%);
}

/* @starting-style: liefert den Initial-State beim ersten Render mit .show
   (sonst würde das Element direkt im End-Zustand erscheinen, weil
   .lightbox.show als „aktueller Stil" gilt und keine Transition triggert).
   Browser-Support seit Chrome 117 / Firefox 129 / Safari 17.5 — älter:
   einfacher Instant-Show ohne Fade-in. */
@starting-style {
    .lightbox.show {
        opacity: 0;
        background-color: rgba(0, 0, 0, 0);
        -webkit-backdrop-filter: blur(0) saturate(100%);
                backdrop-filter: blur(0) saturate(100%);
    }
}

html:has(.lightbox.show) {
    overflow: hidden;
}

/* =========================================================================
   Lightbox-Ueberblendung — der Beschnitt-Effekt stammt von Skiper UI
   "Shadcn ClipPath Carousal" (skiper-ui.com/v1/skiper54), eigener Nachbau
   in CSS. Uebernommen ist die Idee: das ankommende Bild oeffnet sich aus
   einem oben und unten beschnittenen Streifen auf volle Hoehe, statt hart
   aufzutauchen. Kein Skalieren — das Bild bleibt in jeder Phase pixelgenau.

   Anders als in der Vorlage liegen die Slides nicht nebeneinander: zu sehen
   ist immer nur das aktuelle Bild, Vorgaenger und Nachfolger blenden sich
   aus und ein. Alle Slides liegen deshalb deckungsgleich in der Mitte.
   ========================================================================= */
.lightbox-track {
    position: absolute;
    inset: 0;
    /* Klicks auf die freie Flaeche sollen die Lightbox schliessen — die Spur
       selbst darf sie deshalb nicht abfangen, nur das aktive Bild. */
    pointer-events: none;
}

.lb-slide {
    position: absolute;
    top: 50%;
    left: 50%;
    margin: 0;
    line-height: 0;
    pointer-events: none;
    opacity: 0;
    /* Ruhelage: ueber die eigene Breite zentriert. Seitliche Versaetze
       (Ziehen, Richtungsandeutung) schreibt lightbox.js direkt in
       style.translate — NICHT ueber eine Custom Property. Aenderungen an
       einer nicht registrierten Variablen loesen in Chromium keinen
       Uebergang aus, der Wert wuerde springen statt zu gleiten. */
    translate: -50% -50%;
    clip-path: inset(14% 0 round 22px);
    transition:
        opacity 0.34s ease,
        translate 0.4s cubic-bezier(0.16, 1, 0.3, 1),
        clip-path 0.45s cubic-bezier(0.16, 1, 0.3, 1);
}

.lb-slide.is-current {
    opacity: 1;
    clip-path: inset(0 round 22px);
    z-index: 2;
    pointer-events: auto;
    cursor: grab;
}

/* will-change NUR auf dem aktiven Bild — es ist das einzige, das gezoomt und
   geschoben wird. Auf .lightbox-content allgemein waeren es so viele
   Dauer-Ebenen wie Bilder (grosse Texturen im Grafikspeicher), und genau das
   hat das Blaettern frueher ausgebremst. */
.lb-slide.is-current .lightbox-content {
    will-change: transform;
}

/* Bilder ohne eigene Masse — SVG mit reinem viewBox — haetten in der
   schrumpfenden Slide-Box keine Breite und fielen auf ihr Padding zusammen
   (die globale Regel img{max-width:100%} bezieht sich dann auf eine Box,
   deren Breite wiederum vom Bild abhaengt). Eine konkrete Breite loest die
   Abhaengigkeit auf; SVG skaliert ohnehin verlustfrei. */
.lb-slide img[src$=".svg"].lightbox-content {
    width: min(74vw, 900px);
}

/* Beim Oeffnen soll das Bild sofort dastehen, statt sich erst aufzublenden
   (lightbox.js nimmt die Klasse nach zwei Frames wieder weg). */
.lightbox-track.ist-stumm .lb-slide {
    transition: none;
}

.lightbox.zieht,
.lightbox.zieht .lb-slide {
    cursor: grabbing;
}

.lightbox-content {
    display: block;
    /* Laesst links und rechts Platz fuer die Pfeile (40px Abstand + 60px
       Durchmesser). */
    max-width: 84vw;
    max-height: 86vh;
    width: auto;
    height: auto;
    object-fit: contain;
}

@media (max-width: 991px) {
    .lightbox {
        --lb-versatz: 34px;
    }
    .lb-slide {
        clip-path: inset(9% 0 round 18px);
    }
    .lb-slide.is-current {
        clip-path: inset(0 round 18px);
    }
    .lightbox-content {
        max-width: 90vw;
        max-height: 80vh;
    }
    .lb-slide img[src$=".svg"].lightbox-content {
        width: 90vw;
    }
}

@media (prefers-reduced-motion: reduce) {
    .lightbox {
        --lb-versatz: 0px;
    }
    .lb-slide {
        transition: opacity 0.2s ease;
        clip-path: inset(0 round 22px);
    }
}

.lightbox-counter {
    position: absolute;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
    color: #fff;
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.5px;
    padding: 6px 14px;
    background: rgba(0, 0, 0, 0.45);
    border-radius: 999px;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    pointer-events: none;
    user-select: none;
}

.lightbox-spinner {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    margin: -22px 0 0 -22px;
    border: 3px solid rgba(255, 255, 255, 0.18);
    border-top-color: rgba(255, 255, 255, 0.85);
    border-radius: 50%;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.18s ease;
    animation: lb-spin 0.8s linear infinite;
}

.lightbox.is-loading .lightbox-spinner {
    opacity: 1;
}

@keyframes lb-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .lightbox-spinner { animation: none; }
}

/* =========================================================================
   Scroll Fade-in für Bento-Grid-Karten (IntersectionObserver-basiert via JS)
   ---------------------------------------------------------------------------
   Desktop: translateY(54px) + blur(4px) → translateY(0) + blur(0). Rein
            vertikale Bewegung, kein Scale → Elemente schieben sich von unten
            nach oben, ohne aus der Mitte zu wachsen.
   Mobile:  zusätzlich scale(0.94) → Tiefen-Effekt aus der Mitte heraus, weil
            die Cards auf kleinen Screens stärker dominieren und ein leichter
            Pop besser wirkt.
   ========================================================================= */
.fade-in-up {
    opacity: 0;
    transform: translateY(54px);
    /* Schritt 1 gegen Ruckler: 10px -> 4px. Ein Weichzeichner muss in jedem
       Einzelbild neu gerechnet werden, die Kosten steigen mit dem Radius. */
    filter: blur(4px);
    transition: opacity 0.95s cubic-bezier(0.16, 1, 0.3, 1),
                transform 0.95s cubic-bezier(0.16, 1, 0.3, 1),
                filter 0.95s cubic-bezier(0.16, 1, 0.3, 1);
}
/* will-change NUR waehrend der Einblendung (Klasse kommt/geht per script.js).
   Vorher stand es dauerhaft auf allen .fade-in-up — das hielt rund 20 GPU-
   Ebenen mit blur-Filter am Leben, auch wenn nichts animierte. */
.fade-in-up.anim-armed {
    will-change: opacity, transform, filter;
}
/* Hero-Bild: gleiche Idee, der Blur ueber das grosse Bild ist der teuerste
   Effekt der Seite — die Ebene existiert nur waehrend der Einblendung. */
#start picture img.hero-armed {
    will-change: opacity, filter;
}

.fade-in-up.in-view {
    opacity: 1;
    transform: translateY(0);
    filter: blur(0);
}

/* Mobile: deutlicher Scale-from-Center (6%-Scale-Effekt) zusätzlich zur
   Translate-Bewegung — Cards „poppen" sichtbar aus der Mitte heraus, was
   auf kleinen Screens, wo Cards stärker dominieren, gut funktioniert.
   Beide Keyframes (Start + Ende) müssen scale haben, damit der Browser
   sauber zwischen den Transforms interpolieren kann. */
@media (max-width: 991px) {
    .fade-in-up {
        transform: translateY(54px) scale(0.94);
    }
    .fade-in-up.in-view {
        transform: translateY(0) scale(1);
    }
}

@media (prefers-reduced-motion: reduce) {
    .fade-in-up,
    .fade-in-up.in-view {
        opacity: 1 !important;
        transform: none !important;
        filter: none !important;
        transition: none !important;
    }
}

/* =========================================================================
   Skeleton-Screens für lazy-loaded Bento-Bilder
   ----
   Solange ein Bento-Bild noch nicht decodiert/sichtbar ist, zeigt seine
   Card einen pulsierenden Gradient-Placeholder. Verschwindet sobald das
   Bild ge'load't ist (JS toggled die Klasse) oder sobald `complete + naturalWidth`
   beim Page-Load bereits erfüllt ist (Browser hat das Bild schon im Cache).
   Wirkt premium auf langsamen Verbindungen, statt leerer Karten.
   ========================================================================= */
.bento-grid .card.skeleton {
    position: relative;
    overflow: hidden;
}
.bento-grid .card.skeleton img {
    opacity: 0;
}
.bento-grid .card.skeleton::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        90deg,
        rgba(78, 71, 224, 0.06) 0%,
        rgba(78, 71, 224, 0.16) 50%,
        rgba(78, 71, 224, 0.06) 100%
    );
    background-size: 200% 100%;
    animation: skeleton-pulse 1.4s ease-in-out infinite;
    pointer-events: none;
    z-index: 1;
}
/* Platzhalter-Puls nur fuer Karten im Bild (.is-near per script.js) —
   sonst laufen unten auf der Seite dauerhaft Animationen mit. */
.card.skeleton:not(.is-near)::after {
    animation-play-state: paused;
}

@keyframes skeleton-pulse {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}
/* Sobald das Bild geladen ist: Skeleton-Pseudo + Image-Opacity-Hide raus,
   Bild fadet in (300ms ease). */
.bento-grid .card.skeleton-loaded::after {
    display: none;
}
.bento-grid .card.skeleton-loaded img {
    opacity: 1;
    transition: opacity 0.3s ease;
}
@media (prefers-reduced-motion: reduce) {
    .bento-grid .card.skeleton::after { animation: none; }
    .bento-grid .card.skeleton-loaded img { transition: none; }
}


/* =========================================================================
   Logo-Schimmer — Rest des frueheren Bento-Glow (Prinzip nach React Bits
   "Magic Bento", eigener Nachbau). Nur noch der Farbverlauf unter dem Cursor,
   ohne leuchtenden Rand, und nur auf den Logo-Karten ([data-glow]).
   script.js (logoGlow) setzt pro Karte:
     --bglow   Intensitaet 0..1, aus dem Abstand Zeiger <-> Karte
     --bx/--by Zeigerposition in Kartenkoordinaten = Mittelpunkt des Verlaufs
   Der Verlauf ist background-image der Karte und liegt damit UNTER dem Logo.
   Bei --bglow:0 vollstaendig transparent.
   ========================================================================= */
@media (hover: hover) and (pointer: fine) {
    html.logo-glow [data-glow] {
        background-image: radial-gradient(circle at var(--bx, 50%) var(--by, 50%),
            rgba(78, 71, 224, calc(0.10 * var(--bglow, 0))),
            rgba(78, 71, 224, 0) 60%);
    }
}


/* =========================================================================
   Letter-by-Letter Reveal-Animation — generisch für alle H1/H2.
   Hero-H1 startet sofort beim Page-Load; Section-Titles werden per
   IntersectionObserver getriggert wenn sie im Viewport sichtbar werden
   (siehe script.js).
   - .brand-letter:        Default-Zustand (unsichtbar, vor-positioniert)
   - .brand-intro .brand-letter: Animation läuft (parent hat .brand-intro)
   - Stagger via inline animation-delay (per JS, Letter-Index × 50ms)
   - Reduced-Motion: kein Stagger, einfach instant sichtbar
   ========================================================================= */
.brand-intro {
    overflow: hidden;
}
.brand-letter {
    display: inline-block;
    opacity: 0;
    transform: translateY(0.4em);
}
.brand-intro .brand-letter {
    animation: brand-reveal 0.55s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes brand-reveal {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Hero-Pille: Slide-Up + Fade-In als Einheit, exakt wie die Section-H2.
   GATED hinter dem Letter-Reveal der Hero-H1 (.brand-intro): die Pille
   bleibt unsichtbar, bis "Kai Schnubel" einblendet — also auch während des
   Intro-Loaders. Delay nach derselben Formel wie bei der H2:
   (11 Buchstaben - 1) × 50ms + 150ms = 650ms. */
.hero-pill.pill-intro {
    opacity: 0;
    transform: translateY(0.4em);
}
.hero-overlay h1.brand-intro ~ .hero-pill.pill-intro {
    animation: brand-reveal 0.6s cubic-bezier(0.16, 1, 0.3, 1) 0.65s forwards;
}

/* Pill-Rotator: Titel und Spitznamen ("Wortakrobat" …) wechseln in der Hero-Pille.
   Alle Begriffe liegen gestapelt in derselben Grid-Zelle → Breite = längster
   Begriff (der Titel), Pill-Breite bleibt also wie ohne Rotator. Kürzere
   Begriffe sitzen zentriert.
   Wechsel mit derselben Animation wie die H1 (brand-reveal, Buchstabe für
   Buchstabe), aber 1,5× so schnell: 33ms Versatz, 0.367s pro Buchstabe.
   script.js zerlegt jeden Begriff in .pill-letter mit --i = Buchstaben-Index.
   Der alte Begriff blendet kurz aus (.is-leaving), der neue startet danach
   (.is-entering, 0.167s Vorlauf). Werte synchron zu heroPillRotator.
   Der erste Begriff steht beim Laden ohne Buchstaben-Animation da — die Pille
   selbst blendet ja schon als Einheit ein (.pill-intro).
   overflow clippt die Buchstaben unten wie bei der H1 (.brand-intro). */
.pill-rotator {
    display: inline-grid;
    vertical-align: top;
    overflow: hidden;
    /* Luft für Unterlängen (g, p) innerhalb der Clip-Box, ohne Zeilenhöhe zu ändern */
    padding-block: 0.12em;
    margin-block: -0.12em;
}
.pill-rotator__item {
    grid-area: 1 / 1;
    justify-self: center;
    white-space: nowrap;
    opacity: 0;
}
.pill-rotator__item.is-current {
    opacity: 1;
}
.pill-rotator__item.is-leaving {
    transition: opacity 0.167s ease;
}
.pill-letter {
    display: inline-block;
}
.pill-rotator__item.is-entering .pill-letter {
    opacity: 0;
    transform: translateY(0.4em);
    animation: brand-reveal 0.367s cubic-bezier(0.16, 1, 0.3, 1) forwards;
    animation-delay: calc(0.167s + var(--i, 0) * 33ms);
}
html.anim-off .pill-rotator__item,
html.anim-off .pill-letter {
    transition: none !important;
    animation: none !important;
}
html.anim-off .pill-rotator__item.is-entering .pill-letter {
    opacity: 1;
    transform: none;
}
@media (prefers-reduced-motion: reduce) {
    .pill-rotator__item,
    .pill-letter {
        transition: none !important;
        animation: none !important;
    }
    .pill-rotator__item.is-entering .pill-letter {
        opacity: 1;
        transform: none;
    }
}

/* Section-H2: gleicher Slide-Up-Stil wie die Hero-Pille, aber statt Fixed-
   Delay wird --h2-delay per JS gesetzt — basiert auf der Letter-Anzahl der
   Section-H1, sodass die H2 immer EXAKT nach Ende der H1-Letter-Animation
   startet (statt einer pauschalen Wartezeit). h2-anim-init hält die H2
   default unsichtbar (von JS gesetzt → kein No-JS-Schaden), h2-anim-show
   wird vom IntersectionObserver getriggert wenn die Section im View ist. */
.section-title h2.h2-anim-init {
    opacity: 0;
    transform: translateY(0.4em);
}
.section-title h2.h2-anim-show {
    animation: brand-reveal 0.6s cubic-bezier(0.16, 1, 0.3, 1) var(--h2-delay, 1s) forwards;
}

@media (prefers-reduced-motion: reduce) {
    .brand-letter,
    .brand-intro .brand-letter,
    .hero-pill.pill-intro,
    .section-title h2.h2-anim-init,
    .section-title h2.h2-anim-show {
        opacity: 1 !important;
        transform: none !important;
        animation: none !important;
    }
}

/* =========================================================================
   Animation-Off-Toggle (html.anim-off)
   ---------------------------------------------------------------------------
   Deaktiviert alle Reveal-Animationen:
   - Hero-Bild-Fade (animation: hero-image-reveal) — siehe Inline-CSS
   - H1/H2-Letter-Reveal (animation: brand-reveal)
   - Hero-Pill-Reveal (animation: brand-reveal mit Delay)
   - Scroll-Fade-in für Bento-Blöcke + h3 + cv-blocks (.fade-in-up)
   - Pre-Animation-Hide (.js-anim .bento-grid>*, etc.) — wird via Inline-CSS
     ebenfalls überschrieben.
   Setzt alles auf sofort sichtbaren End-State. */
html.anim-off .brand-letter,
html.anim-off .brand-intro .brand-letter,
html.anim-off .hero-pill.pill-intro,
html.anim-off .section-title h2.h2-anim-init,
html.anim-off .section-title h2.h2-anim-show,
html.anim-off .fade-in-up,
html.anim-off .fade-in-up.in-view {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
    /* will-change: auto neutralisiert das GPU-Compositing-Layer, das durch
       die Base-Regel .fade-in-up { will-change: opacity, transform, filter }
       angelegt wird. Ohne diesen Reset zeichnet der Browser auch im neutralen
       Zustand eine eigene Compositing-Surface — und deren Sub-Pixel-Kanten
       können bei vollflächigen Sections (z.B. .section-wrapper-offwhite,
       .downloads-wrapper mit margin-inline: calc(50% - 50vw)) als feine
       graue Hairlines zwischen den Sections sichtbar werden. */
    will-change: auto !important;
}

/* Lang-Toggle-Button: Circle-FAB unten-links, zeigt jeweils die Ziel-Sprache
   („EN" wenn aktuell DE, „DE" wenn aktuell EN). Sichtbar Desktop + Mobile. */
#lang-toggle {
    position: fixed;
    /* Gestackt über dem #anim-toggle in der unteren rechten Ecke:
       16px Bottom-Offset + 44px Button-Höhe + 12px Gap = 72px. */
    bottom: calc(env(safe-area-inset-bottom, 0px) + 72px);
    right: 16px;
    z-index: 9500;
    background-color: var(--col-primary);  /* Lila #4E47E0 — Brand-Primärfarbe */
    color: var(--col-offwhite);
    border: none;
    border-radius: 50%;
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
    transition: opacity 0.4s ease, transform 0.4s ease,
                box-shadow 0.18s ease-out,
                background-color 0.18s ease-out;
    -webkit-tap-highlight-color: transparent;
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.5px;
    /* Default: bei scrollY=0 versteckt (Hero clean). body.scrolled fadet ein. */
    opacity: 0;
    transform: translateY(8px);
    pointer-events: none;
}
body.scrolled #lang-toggle {
    opacity: 1;
    transform: none;
    pointer-events: auto;
}
@media (hover: hover) {
    body.scrolled #lang-toggle:hover {
        transform: translateY(-2px);
        box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
    }
}
#lang-toggle:focus-visible {
    outline: 2px solid var(--col-primary);
    outline-offset: 3px;
}

/* Anim-Toggle-Button: Circle-FAB unten-rechts mit Sparkles-Icon.
   X-Overlay im SVG wird via CSS bei html.anim-off eingeblendet — signalisiert
   „Animationen deaktiviert". Farbschema:
     • Animationen AN (nicht durchgestrichen): Brand-Lila (col-primary)
     • Animationen AUS (X durchgestrichen): Schwarz (col-offblack)
   Sichtbar auf Desktop UND Mobile. */
#anim-toggle {
    position: fixed;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 16px);
    right: 16px;
    z-index: 9500;
    background-color: var(--col-primary);
    color: var(--col-offwhite);
    border: none;
    border-radius: 50%;
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
    transition: opacity 0.4s ease, transform 0.4s ease,
                box-shadow 0.18s ease-out,
                background-color 0.18s ease-out;
    -webkit-tap-highlight-color: transparent;
    /* Default: bei scrollY=0 versteckt (siehe #lang-toggle). */
    opacity: 0;
    transform: translateY(8px);
    pointer-events: none;
}
body.scrolled #anim-toggle {
    opacity: 1;
    transform: none;
    pointer-events: auto;
}
#anim-toggle svg {
    display: block;
    pointer-events: none;
}
#anim-toggle svg .slash {
    opacity: 0;
    transition: opacity 0.18s ease-out;
}
/* Animationen aus → X-Overlay erscheint, Background wechselt zu Schwarz */
html.anim-off #anim-toggle {
    background-color: var(--col-offblack);
}
html.anim-off #anim-toggle svg .slash {
    opacity: 1;
}
@media (hover: hover) {
    body.scrolled #anim-toggle:hover {
        transform: translateY(-2px);
        box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
    }
}

/* Nav-Preference-Row: zwei runde FAB-Buttons (Sprache + Animation) als
   Burger-Menü-Eintrag im Mobile-Layout. Default versteckt — auf Desktop sind
   die persistenten FAB-Buttons in den Ecken aktiv, hier wäre redundant.
   Sichtbarmachung in der Mobile-Media-Query weiter unten. */
.nav-pref-row { display: none; }
/* Focus-Outline: liegt durch outline-offset auf dem Page-Background (offwhite),
   nicht auf dem Button. Lila contrastiert sauber mit offwhite — unabhängig
   davon, ob Button-BG aktuell lila oder schwarz ist. */
#anim-toggle:focus-visible {
    outline: 2px solid var(--col-primary);
    outline-offset: 3px;
}

/* =========================================================================
   Verlaufs-Text (Technik nachgebaut nach React Bits "Gradient Text")
   ---------------------------------------------------------------------------
   Kern: Farbverlauf als Textfuellung via background-clip: text, dreifach
   breiter Hintergrund, dessen Position animiert wird. Die erste Farbe steht
   am Ende nochmal — sonst springt der Verlauf beim Zyklusende (Hinweis aus
   der Vorlage). Statt eines JS-Zeitgebers reicht eine CSS-Animation mit
   direction: alternate (dort "yoyo").
   Farben: Lila -> Cyan -> Lila.
   Gilt NUR fuer H1 (Hero + Section-Titel). H2, H3 und die Hero-Pille bleiben
   ohne Verlauf in ihrer normalen Farbe.
   --gt-cyan ist eine abgedunkelte Variante von --col-secondary (#67EEF5) und
   gilt NUR hier — die Markenfarbe selbst bleibt unveraendert.
   Kontrast: #0E9AA7 erreicht auf offwhite ca. 3.4:1, reicht also fuer grosse
   Schrift (WCAG AA ab 3:1).
   Aktiv nur mit html.gradient-on (Umschalter #gradient-toggle).
   ========================================================================= */
html.gradient-on {
    /* abgedunkeltes Cyan, nur fuer den Verlaufs-Text */
    --gt-cyan: #0E9AA7;
}

/* Waehrend des Letter-Reveals: Ein transform auf den Buchstaben-Spans
   zerlegt die geclippte Flaeche des Eltern-Elements. Deshalb traegt hier
   jeder Buchstabe seinen eigenen Ausschnitt des Verlaufs: script.js setzt
   --gt-w (Breite der H1) an der H1 und --gt-x (Abstand des Buchstabens zur
   linken H1-Kante) am Span. So liegen alle Ausschnitte nahtlos nebeneinander
   und entsprechen exakt dem Startbild des Verlaufs an der H1 (Position 0%). */
html.gradient-on .section-title h1:not(.letters-done) .brand-letter,
html.gradient-on .hero-overlay h1:not(.letters-done) .brand-letter {
    background-image: linear-gradient(to right,
        var(--col-primary), var(--gt-cyan), var(--col-primary));
    background-size: calc(var(--gt-w, 0px) * 3) 100%;
    background-repeat: no-repeat;
    background-position: calc(var(--gt-x, 0px) * -1) 50%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

/* Nach dem Letter-Reveal: Verlauf wandert am Eltern-Element. */
html.gradient-on .section-title h1.letters-done,
html.gradient-on .hero-overlay h1.letters-done {
    background-image: linear-gradient(to right,
        var(--col-primary), var(--gt-cyan), var(--col-primary));
    background-size: 300% 100%;
    background-repeat: repeat;
    background-position: 0% 50%;
    -webkit-background-clip: text;
    background-clip: text;
    animation: gradient-text 14s ease-in-out infinite alternate;
}
/* Textfarbe transparent — auch fuer die Letter-Spans, sonst ueberdecken sie
   die geclippte Flaeche des Eltern-Elements. */
html.gradient-on .section-title h1.letters-done,
html.gradient-on .section-title h1.letters-done *,
html.gradient-on .hero-overlay h1.letters-done,
html.gradient-on .hero-overlay h1.letters-done * {
    color: transparent;
}
/* Buchstaben-Spans neutralisieren: ein transform (auch translateY(0) aus dem
   forwards-Fill) auf Kindern zerlegt die geclippte Flaeche des Eltern-Elements
   — die Schrift verschwindet dann fast komplett. */
html.gradient-on h1.letters-done .brand-letter {
    animation: none !important;
    transform: none !important;
    opacity: 1 !important;
}
@keyframes gradient-text {
    from { background-position: 0% 50%; }
    to   { background-position: 100% 50%; }
}
/* Bei anim-off / Reduced-Motion: Verlauf bleibt, aber steht still. */
html.anim-off.gradient-on .section-title h1.letters-done,
html.anim-off.gradient-on .hero-overlay h1.letters-done {
    animation: none;
    background-position: 35% 50%;
}
@media (prefers-reduced-motion: reduce) {
    html.gradient-on .section-title h1.letters-done,
    html.gradient-on .hero-overlay h1.letters-done {
        animation: none;
        background-position: 35% 50%;
    }
}

/* Verlaufs-Animation nur fuer Elemente im Bild (Klasse .gt-run per script.js).
   Ausserhalb pausiert sie — sonst zeichnet der Browser dauerhaft mehrere
   Ueberschriften neu, auch weit ausserhalb des Sichtbereichs. */
html.gradient-on .section-title h1.letters-done:not(.gt-run),
html.gradient-on .hero-overlay h1.letters-done:not(.gt-run) {
    animation-play-state: paused;
}

/* Waehrend der Intro-Loader laeuft: Verlaufs-Animation anhalten. Sie
   animiert background-position, das zeichnet der Browser in jedem Bild neu
   und kostet genau dann Leistung, wenn der Loader fluessig laufen soll. */
html.intro-active.gradient-on .section-title h1.letters-done,
html.intro-active.gradient-on .hero-overlay h1.letters-done {
    animation-play-state: paused;
}

/* Effekt-Umschalter html.fx-lite: Einblendungen ohne Weichzeichner.
   Bewegung und Deckkraft bleiben, nur der teure filter faellt weg. */
html.fx-lite .fade-in-up,
html.fx-lite .fade-in-up.in-view,
html.fx-lite #start picture img {
    filter: none !important;
}

/* Umschalter fuer die Effektstaerke: vierter FAB (128 + 44 + 12 = 184). */
#fx-toggle {
    position: fixed;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 184px);
    right: 16px;
    z-index: 9500;
    background-color: var(--col-offblack);
    color: var(--col-offwhite);
    border: none;
    border-radius: 50%;
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
    transition: transform 0.18s ease-out, box-shadow 0.18s ease-out, opacity 0.2s ease;
    -webkit-tap-highlight-color: transparent;
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    opacity: 0.55;
}
html.fx-lite #fx-toggle { opacity: 1; }
@media (hover: hover) {
    #fx-toggle:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25); }
}
#fx-toggle:focus-visible { outline: 2px solid var(--col-primary); outline-offset: 3px; }
@media (max-width: 991px) { #fx-toggle { display: none !important; } }

/* Umschalter fuer den Verlaufs-Text: dritter FAB ueber #lang-toggle
   (72 + 44 + 12 = 128). */
#gradient-toggle {
    position: fixed;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 128px);
    right: 16px;
    z-index: 9500;
    background-color: var(--col-accent);
    color: var(--col-offwhite);
    border: none;
    border-radius: 50%;
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
    transition: transform 0.18s ease-out, box-shadow 0.18s ease-out, opacity 0.2s ease;
    -webkit-tap-highlight-color: transparent;
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 0.95rem;
    font-weight: 600;
    opacity: 0.55;
}
html.gradient-on #gradient-toggle { opacity: 1; }
@media (hover: hover) {
    #gradient-toggle:hover {
        transform: translateY(-2px);
        box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
    }
}
#gradient-toggle:focus-visible {
    outline: 2px solid var(--col-primary);
    outline-offset: 3px;
}
@media (max-width: 991px) {
    #gradient-toggle { display: none !important; }
}

@keyframes zoom {
    from {
        transform: scale(0.95);
        opacity: 0;
    }
    to {
        transform: scale(1);
        opacity: 1;
    }
}

.lightbox-close {
    position: absolute;
    top: 20px;
    right: 40px;
    width: 60px;
    display: flex;
    justify-content: center;
    align-items: center;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 10000;
    line-height: 0;
}

.lightbox-close img {
    width: 35px;
    height: 35px;
    transition: opacity 0.3s;
}

.lightbox-close .icon-hover {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    opacity: 0;
}

@media (hover: hover) {
    .lightbox-close:hover .icon-default {
        opacity: 0;
    }

    .lightbox-close:hover .icon-hover {
        opacity: 1;
    }
}

.bento-grid .card img {
    cursor: zoom-in;
}

/* Hinweis: Hover-Animation lief vorher auf dem <img> (scale 1.025).
   Wurde auf Card-Level migriert (siehe Unified Hover-Block weiter unten),
   damit Bilder, Color-Cards und Typo-Cards mit demselben "ganzes Element
   schwebt"-Feel auftreten. Easing + Shadow sind identisch zu den
   Farbfeldern. */

.bento-grid .card.no-zoom img {
    cursor: default;
    transform: none !important;
    filter: none !important;
}

/* =============================================================
   Unified Card-Hover für ALLE Bento-Cards
   (Bilder + Farbfelder + Schriftbilder)
   =============================================================
   Scale + Drop-Shadow auf der KOMPLETTEN CARD (statt nur am img),
   damit das "ganzes Element schwebt"-Feel der Farbfelder einheitlich
   auf Bilder, Color- und Typo-Cards überträgt.

   - overflow:visible damit Scale + Drop-Shadow nicht geclipped wird
   - position:relative für z-index-Stacking-Context
   - transition: cubic-bezier(0.22, 1, 0.36, 1) — sanftes ease-out
   - border-radius zusätzlich aufs img (für die Bild-Cards), damit das
     Bild auch dann rounded corners zeigt, wenn die Card overflow:visible
     ist und der Card-border-radius nicht mehr clippt */

#members .card.no-padding,
#members .cd-logo-cards .card,
#event-branding .card.no-padding,
#social-media .sm-left .card,
#social-media .sm-col .card.no-padding,
#logo-design .card.no-padding,
.cd-color-cards .color-card,
.typo-cards .card {
    overflow: visible;
    position: relative;
    /* box-shadow statt filter:drop-shadow auf Hover (siehe Regel unten) —
       drop-shadow folgt der sichtbaren Pixel-Maske und rendert bei Cards mit
       transparentem Background + rounded image anders als bei Cards mit
       solidem Background (Anti-Aliasing/Edge-Cutoff weichen subtil ab).
       box-shadow folgt durchgängig der Border-Box (incl. border-radius)
       → konsistente Shadow-Form über alle Card-Typen.
       Selbes Easing für transform + box-shadow → Schatten läuft synchron
       mit dem Scale (vorher: `filter 0.4s ease` lagged hinter dem
       `transform cubic-bezier`-Sprung). */
    transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1),
                box-shadow 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

#members .card.no-padding img,
#members .cd-logo-cards .card img,
#event-branding .card.no-padding img,
#social-media .sm-left .card img,
#social-media .sm-col .card.no-padding img,
#logo-design .card.no-padding img {
    border-radius: var(--border-radius-l);
}

/* Typo-Card-Body-Text: text-wrap: balance gleicht die Zeilenlaengen aus
   (einheitlicher Flattersatz mit sehr aehnlich langen Zeilen statt kurzer
   Schlusszeile). Greift, weil die breite Spalte (max-width 92% am <p>) die
   Zeilenzahl auf <=6 haelt — Chromium balanciert nur bis ~6 Zeilen. Aeltere
   Browser fallen graceful auf normales Wrapping zurueck (no harm). */
.typo-cards .card p {
    text-wrap: balance;
}

@media (hover: hover) {
    #members .card.no-padding:hover,
    #members .cd-logo-cards .card:hover,
    #event-branding .card.no-padding:hover,
    #social-media .sm-left .card:hover,
    #social-media .sm-col .card.no-padding:hover,
    #logo-design .card.no-padding:hover,
    .cd-color-cards .color-card:hover,
    .typo-cards .card:hover {
        transform: scale(1.05);
        /* Layered Shadow (Material-Design-Pattern) — unifiziert die optische
           Stärke über stark unterschiedliche Card-Größen (Logos ~300px,
           Color-Cards ~200px, Plakat-Image ~600px hoch). Eine einzelne
           absolute Shadow (z.B. 0 12px 24px) wirkt auf kleinen Cards
           proportional viel zu groß (24px Blur = 12% der Cardbreite) und auf
           großen viel zu subtil (4%) — daher der wahrgenommene Strength-
           Unterschied. Zwei Layer balancieren das:
             • Contact-Shadow (0 4px 12px @ 0.10): tight, sitzt direkt unter
               der Card, dominiert kleine Cards nicht, bleibt aber präsent.
             • Ambient-Shadow (0 22px 48px @ 0.18): wide+soft, schafft Tiefe
               bei großen Cards, wird auf kleinen sanft ausgewaschen.
           Zusammen ergibt sich eine kohärentere Wahrnehmung über alle Sizes. */
        box-shadow:
            0 4px 12px rgba(16, 12, 26, 0.10),
            0 22px 48px rgba(16, 12, 26, 0.18);
        z-index: 2;
    }
}

img[src$=".svg"].lightbox-content {
    background-color: var(--col-offwhite);
    padding: 30px;
}

img[src*="Device_3"].lightbox-content,
img[src*="device_3"].lightbox-content {
    background-color: transparent;
    box-shadow: none;
}

img[src*="medaille"].lightbox-content {
    background-color: transparent;
    box-shadow: none;
    padding: 0;
}

.lightbox-prev,
.lightbox-next {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background-color: var(--col-primary);
    border: none;
    cursor: pointer;
    z-index: 10001;
    -webkit-user-select: none;
    user-select: none;
    padding: 16px;
    line-height: 0;
    border-radius: 50%;
    transition: background-color 0.3s;
}

.lightbox-prev img,
.lightbox-next img {
    width: 28px;
    height: 28px;
    transition: opacity 0.3s;
}

.lightbox-prev img {
    transform: rotate(-90deg);
}

.lightbox-next img {
    transform: rotate(90deg);
}

.lightbox-prev .icon-hover,
.lightbox-next .icon-hover {
    position: absolute;
    top: 16px;
    left: 16px;
    opacity: 0;
}

@media (hover: hover) {
    .lightbox-prev:hover .icon-default,
    .lightbox-next:hover .icon-default {
        opacity: 0;
    }

    .lightbox-prev:hover .icon-hover,
    .lightbox-next:hover .icon-hover {
        opacity: 1;
    }
}

.lightbox-prev {
    left: 40px;
}

.lightbox-next {
    right: 40px;
}

/* =========================================================================
   Tastatur-Navigation Highlight
   ========================================================================= */
*:focus-visible {
    outline: none !important;
}

/* =========================================================================
   Website Login Overlay
   ========================================================================= */
body.locked {
    overflow: hidden !important;
}

#login-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    background-color: var(--col-primary);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 99999;
    transition: opacity 0.3s ease;
}

html.is-unlocked body.locked {
    overflow: auto !important;
}

html.is-unlocked #login-overlay {
    display: none !important;
}

.login-box {
    background-color: var(--col-offwhite);
    padding: 40px;
    border-radius: var(--border-radius-l);
    text-align: center;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
    display: flex;
    flex-direction: column;
    gap: 15px;
    align-items: center;
    width: 90%;
    max-width: 400px;
}

.login-box h2 {
    margin: 0;
    color: var(--col-primary);
    font-family: 'Apfel Grotezk Satt', sans-serif;
    font-weight: 400;
    text-transform: none;
    width: 100%;
    text-align: center;
    font-size: clamp(2rem, 9vw, 2.4rem);
    line-height: 1.1;
    white-space: nowrap;
}

.login-box p {
    margin-bottom: 10px;
    color: var(--col-offblack);
    width: 100%;
    text-align: center;
}

.login-box input {
    width: 100%;
    height: 45px;
    border-radius: 27px;
    border: 2px solid var(--col-primary);
    padding: 0 20px;
    font-family: inherit;
    color: var(--col-primary);
    outline: none;
    text-align: center;
    font-size: 1.1rem;
}

@keyframes shake {
    0%, 100% { transform: translateX(0); }
    20%, 60% { transform: translateX(-8px); }
    40%, 80% { transform: translateX(8px); }
}

.login-box input.error-shake {
    border-color: var(--col-accent);
    animation: shake 0.4s ease-in-out;
}

.login-box button {
    background-color: var(--col-primary);
    color: var(--col-offwhite);
    border: none;
    padding: 12px 30px;
    border-radius: 27px;
    font-family: 'Apfel Grotezk Fett', sans-serif;
    font-size: 1.2rem;
    cursor: pointer;
    transition: transform 0.2s, background-color 0.3s, color 0.3s;
    width: 100%;
}

@media (hover: hover) {
    .login-box button:hover {
        color: var(--col-secondary);
        transform: translateY(-2px);
    }
}

/* =========================================================================
   Tablet Breakpoints
   ========================================================================= */
@media (max-width: 1024px) {
    .footer-layout {
        flex-direction: column;
        align-items: center;
        text-align: center;
    }

    .footer-columns {
        flex-direction: column;
        gap: 40px;
    }

    .footer-col-left,
    .footer-col-right {
        align-items: center;
    }

    .footer-text-area {
        padding-left: 0;
    }

    .scroll-top-btn {
        margin-left: 0;
        margin-top: 40px;
    }

    .download-card {
        grid-column: span 12;
        margin-bottom: 20px;
    }
}

/* Desktop: 3 gleich breite Spalten — jede sm-col enthält Karte + Text.
   grid-column: span 4 wird via inline style auf jedem .sm-col gesetzt. */

/* =========================================================================
   Mobile + Tablet Breakpoints
   ----
   Bis einschließlich 991 px (Bootstrap-"lg"-Breakpoint) gilt das einspaltige
   Mobile-Layout. Damit ist der gesamte Tablet-Bereich (576–991 px) abgedeckt
   und das 12-Spalten-Bento-Grid wird erst ab ≥992 px aktiv, wo es wirklich
   genug Platz hat (sonst Spalten unter 50 px Breite, unleserlich).

   Innerhalb dieses Blocks gibt es einen weiteren `@media (max-width: 600px)`-
   Block für Phone-spezifische Tweaks (kleinere Schrift, engere Paddings),
   die auf Tablets ungewollt wären.
   ========================================================================= */
@media (max-width: 991px) {

    /* WebKit-Quirk: overflow-x:hidden auf body deaktiviert viewport-fit=cover-Edge-to-Edge teilweise.
       Stattdessen overflow-x via overflow-clip auf html — schränkt 100vh/100lvh nicht ein. */
    html {
        overflow-x: clip;
        /* html-Background = Cyan, matcht das Hero-Image-Background.
           Body-bg wechselt dynamisch zwischen Cyan und Lila per JS basierend
           auf Hero-Sichtbarkeit (siehe script.js: heroBgObserver). */
        background-color: #D4EDF3 !important;
        /* Mobile-Header (fixed, ~80px hoch inkl. Safe-Area-Inset) muss
           ähnlich wie Desktop kompensiert werden. scroll-padding-top: 90px
           lässt das Anchor-Ziel unter den Header rutschen. iOS Safari
           interpretiert negative scroll-margin-top nicht zuverlässig,
           Section.top landet am Viewport.top, Header-Clearance kommt vom
           internen section padding-top (100px), kein Vor-Section-Peek. */
        scroll-padding-top: 0 !important;
    }

    /* Mobile-Anchor-Targets: scroll-margin-top auf 0 (kein negativer
       Compensator nötig auf Mobile — scroll-padding-top: 90px reicht). */
    #start,
    #lebenslauf,
    #members,
    #event-branding,
    #social-media,
    #logo-design,
    #downloads {
        scroll-margin-top: 0 !important;
    }
    html, body {
        width: 100vw !important;
        max-width: 100vw !important;
        overflow-x: clip !important;
        overscroll-behavior-y: none;
        margin: 0 !important;
        padding: 0 !important;
    }

    /* =====================================================================
       Safe-Area-Coloring — Scroll-Dynamic
       =====================================================================
       iOS Safari (viewport-fit=cover) sampelt body-bg-color für Notch (oben)
       und Home-Indicator (unten). Beide kriegen also dieselbe Farbe.
       Lösung: bg-color wechselt je nach Scroll-Position via JS-toggle der
       Klasse `.scrolled-past-hero` (siehe heroBgObserver in script.js):
         • Hero sichtbar → cyan  (matcht Hero-Image im Notch)
         • Hero raus     → lila  (matcht Footer im Home-Indicator)
       Da Hero und Footer nie gleichzeitig sichtbar sind, sieht der User die
       Naht nicht — der jeweils sichtbare Safe-Area-Bereich matcht immer.
    */
    body {
        min-height: 100vh !important;
        min-height: 100lvh !important;
        position: relative;
        background-color: #D4EDF3;
        transition: background-color 0.4s ease;
    }
    body.scrolled-past-hero {
        background-color: var(--col-primary);
    }

    /* Burger-Menü offen: alles lila + Transition aus, damit der Wechsel
       beim Öffnen/Schließen ohne Fade synchron mit dem Overlay passiert. */
    body.nav-open {
        background-color: var(--col-primary) !important;
        transition: none !important;
    }

    main {
        margin: 0 !important;
        padding: 0 !important;
    }

    /* Hero Section – Full-Bleed Portrait.
       Strategie (vereinfacht, jetzt wo das Bild solid #D4EDF3 Hintergrund hat):
         1. Höhe = 100vh / 100lvh (Browser-native, kein JS-Override)
         2. html- und body-Background = #D4EDF3 → Falls iOS die Layout-Viewport
            unter Safe-Area positioniert, füllt der html/body-bg den Notch-
            und Home-Indicator-Bereich in der GLEICHEN Farbe wie das Bild
            → optisch durchgehend, keine Naht. */
    #start {
        width: 100vw !important;
        max-width: 100vw !important;
        margin-left: calc(50% - 50vw) !important;
        margin-top: 0 !important;
        margin-bottom: 0 !important;
        padding: 0 !important;

        /* Höhe = maximale Bildschirm-Höhe (URL-Bars eingeklappt).
           Damit füllt der Hero auf iOS Safari den Screen edge-to-edge,
           auch nachdem die URL-Bars beim Scrollen kollabieren.
           Reihenfolge: Fallback → moderner Wert. lvh = "large viewport
           height", konstant (kein Layout-Shift bei URL-Bar-Collapse). */
        height: 100vh !important;       /* fallback (iOS < 15.4) */
        height: 100lvh !important;      /* iOS 15.4+ : full-screen height */
        min-height: 100vh !important;
        min-height: 100lvh !important;
        max-height: 100vh !important;
        max-height: 100lvh !important;

        overflow: hidden !important;
        position: relative !important;
        top: 0 !important;
        background-color: #D4EDF3 !important;
    }

    /* Sektionen UNTER der Hero brauchen einen expliziten weißen Background,
       damit der Body-Background (#D4EDF3) nicht in sie reinblutet. */
    #lebenslauf,
    #members,
    #event-branding,
    #social-media,
    #logo-design,
    #downloads {
        background-color: var(--col-offwhite) !important;
        position: relative;
        z-index: 1;
    }

    #start picture,
    #start picture img {
        width: 100% !important;
        height: 100% !important;
        display: block !important;
        margin: 0 !important;
        padding: 0 !important;
    }

    #start picture img {
        object-fit: cover !important;
        object-position: center center !important;
    }

    /* Picture/img füllen das ganze Hero (= 100svh). Kein gesonderter Override
       für die Bildhöhe nötig, da Hero selbst schon 100svh hoch ist. */

    /* Headline auf gleicher Y-Höhe wie der Hamburger-Button.
       Beide kommen auf safe-area-top + 15px:
         - Hamburger via .nav-pill padding-top
         - Headline via .hero-overlay top
       So fluchten beide Top-Kanten exakt. */
    .hero-overlay {
        position: absolute !important;
        top: calc(env(safe-area-inset-top, 0px) + 15px) !important;
        bottom: auto !important;
        left: calc(env(safe-area-inset-left, 0px) + 24px) !important;
        right: auto !important;
        /* Breite = H1-Schnubel-Breite, von JS in --hero-overlay-w gesetzt.
           Fallback: auto (Pre-JS-Render zeigt natürliche Breite kurz).
           max-width verhindert Overflow auf extrem schmalen Viewports. */
        width: var(--hero-overlay-w, auto) !important;
        max-width: calc(100vw - 48px) !important;
        transform: none !important;
        /* align-items: stretch → Pill nimmt komplette Overlay-Breite ein
           (= Schnubel-Breite) und der Pill-Text wrappt auf 2 Zeilen. */
        align-items: stretch !important;
        gap: 10px !important;
        padding-bottom: 0 !important;
        z-index: 2 !important;
    }

    /* Sicherheitsregel: nav-pill berücksichtigt safe-area-inset-top explizit,
       damit Hamburger-Top synchron mit hero-overlay-Top steht. */
    .nav-pill {
        padding-top: calc(var(--safe-top, env(safe-area-inset-top, 0px)) + 15px) !important;
    }

    .hero-overlay h1 {
        color: var(--col-primary) !important;
        font-size: clamp(2.8rem, 13vw, 4.2rem) !important;
        line-height: 0.95 !important;
    }

    .hero-pill {
        position: static !important;
        width: 100% !important;
        padding: 6px 14px !important;
        /* font-size skaliert mit Viewport, damit DE-Variante
           "Mediengestalter Digital & Print" in jedem Mobile-Viewport in die
           "Schnubel"-Breite (= Overlay-Breite via JS) auf 1 Zeile passt.
           Ratio ~0.22 × H1-font-size (analog zu Desktop-Pill-Proportion). */
        font-size: clamp(0.72rem, 2.5vw, 1.05rem) !important;
        letter-spacing: -0.005em !important;
        white-space: nowrap !important;
        text-align: center !important;
        box-sizing: border-box !important;
        border-radius: 50px !important;
    }

    .hero-scroll-arrow--desktop {
        display: none !important;
    }

    .hero-scroll-arrow--mobile {
        display: block !important;
        position: relative !important;
        align-self: flex-start !important;
        z-index: 3 !important;
        width: 38px !important;
        height: 38px !important;
    }

    #start .hero-scroll-arrow--mobile img {
        display: block !important;
        width: 100% !important;
        height: auto !important;
    }

    /* Typografie */
    h1 { font-size: 2.2rem !important; }
    h2 { font-size: 1.3rem !important; margin-top: 0 !important; }
    h3 {
        font-size: 1.3rem !important;   /* matcht h2 auf Mobile */
        margin-top: 0 !important;
        margin-bottom: 0 !important;
        /* Tightes Line-Height (war 1.5 vom body geerbt → ~5px Halb-Leading
           über dem Text). Damit das h3 visuell so dicht an die section-title
           rückt wie die h2 an die h1 im Flex-Gap. */
        line-height: 1.1 !important;
    }

    /* Symmetrie um h3: Browser-Default-Margins der angrenzenden <p>
       neutralisieren, damit der Rhythmus rein über Flex-Gaps läuft. */
    .cd-text > p:first-of-type { margin-top: 0 !important; }
    .cd-text > p:last-of-type { margin-bottom: 0 !important; }

    .section-title {
        flex-direction: column !important;
        gap: 4px !important;
        /* h2→h3-Margin etwas großzügiger als der h1→h2-Flex-Gap (4px),
           damit h3 als Sub-Heading optisch klar von der section-title
           absetzt. ~12% mehr Atem als h1→h2. */
        margin-bottom: 7px !important;
    }

    .section-title h1,
    .section-title h2 { line-height: 1.0 !important; }

    .h2-dash { display: none !important; }

    /* (Intro-Section Mobile-Regeln entfernt — siehe Desktop-Block oben.) */

    /* Sections – Padding & Spacing
       padding-top: 100px statt 64px — analog zur Desktop-Erhöhung auf 110:
       schafft Innen-Buffer, damit das H1 unter dem ~84px hohen Mobile-Header
       (position: fixed) sichtbar landet, ohne Vor-Section-Peek. */
    #members,
    .section-wrapper-offwhite,
    .downloads-wrapper,
    #social-media,
    #logo-design {
        padding-left: 24px !important;
        padding-right: 24px !important;
        padding-top: 100px !important;
        padding-bottom: 64px !important;
        width: 100% !important;
        margin-left: 0 !important;
        transform: none !important;
    }

    .section-gap {
        padding-top: 100px !important;
        padding-bottom: 64px !important;
    }

    #lebenslauf {
        padding-top: 100px !important;
        padding-bottom: 64px !important;
    }

    /* Bento-Grid & Cards */
    .bento-grid { gap: 20px !important; }

    .card {
        padding: 20px !important;
        border-radius: 18px !important;
    }

    .card.no-padding { padding: 0 !important; }

    .card img,
    .card.no-padding img {
        border-radius: 18px !important;
    }

    .bento-grid {
        display: flex !important;
        flex-direction: column !important;
        align-items: stretch !important;
        gap: 20px !important;
    }

    .bento-grid > div {
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
        align-items: stretch !important;
        gap: 20px !important;
    }

    .bento-grid div[style*="grid-template-columns"] {
        display: flex !important;
        flex-direction: column !important;
        align-items: stretch !important;
        justify-content: flex-start !important;
        width: 100% !important;
        gap: 20px !important;
        flex: 0 0 auto !important;
    }

    #members .bento-grid div.cd-color-cards[style] {
        display: grid !important;
        grid-template-columns: repeat(3, 1fr) !important;
        gap: 20px !important;
    }

    /* Wrapper auflösen, damit alle 5 Color-Cards direkt im 3-Spalten-Grid fließen */
    #members .cd-color-cards > div {
        display: contents !important;
    }

    #members .cd-color-cards .color-vals {
        font-size: 0.8rem !important;
        width: 100% !important;
    }
    #members .cd-color-cards .color-card,
    #members .cd-color-cards .card {
        padding: 14px !important;
        aspect-ratio: 1 !important;
        min-height: 0 !important;
        height: auto !important;
        justify-content: flex-end !important;
        align-self: start !important;
    }
    #members .cd-color-cards .color-vals .val-row {
        display: block !important;
        text-align: left !important;
        padding-bottom: 4px !important;
        margin-bottom: 4px !important;
    }
    /* Labels (HEX/RGB/CMYK) auf Mobile ausblenden — nur Werte anzeigen.
       Cards werden so visuell aufgeräumt, Werte passen ohne Wrap rein. */
    #members .cd-color-cards .color-vals .val-row span:first-child {
        display: none !important;
    }
    #members .cd-color-cards .color-vals .val-row span:last-child {
        font-size: 0.8rem !important;
        line-height: 1.3 !important;
        font-weight: 500 !important;
        white-space: nowrap !important;
        font-variation-settings: "wdth" 75 !important;
    }
    #members .cd-color-cards .color-vals .val-row:last-child {
        border-bottom: none !important;
        padding-bottom: 0 !important;
        margin-bottom: 0 !important;
    }

    .typo-header-left { order: 1 !important; }
    .typo-cards { order: 2 !important; gap: 20px !important; }
    .typo-desc { order: 3 !important; }
    .typo-header-right { order: 4 !important; }
    .typo-img { order: 5 !important; }

    #members .card[style*="aspect-ratio"] { aspect-ratio: auto !important; }

    /* Wort-Bild-Marke (Seitenwechsel) auf Mobile (≤991px):
       Vertikaler Stack — Ladenfront → Tasse → Logo SVG → cd-text.
       Auf 375px-Viewport war das 2-Spalten-Layout (Ladenfront | Tasse+Logo)
       zu eng gedrängt; Cards wurden squished, Proportionen unklar. */
    #logo-design > .bento-grid {
        display: flex !important;
        flex-direction: column !important;
        gap: 20px !important;
    }

    #logo-design > .bento-grid > div {
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
        gap: 20px !important;
    }

    /* Ladenfront: portrait Aspect, behält das Storefront-Format aus dem File. */
    #logo-design > .bento-grid > div:nth-child(1) .card.no-padding {
        aspect-ratio: 1813 / 2400 !important;
        flex: none !important;
        height: auto !important;
        overflow: hidden !important;
        position: relative !important;
    }
    #logo-design > .bento-grid > div:nth-child(1) .card.no-padding > picture > img {
        position: absolute !important;
        top: 0 !important;
        left: 0 !important;
        width: 100% !important;
        height: 100% !important;
        object-fit: cover !important;
    }

    /* Tasse: 1:1 quadratisch — Mobile-friendly Crop des Portrait-Files. */
    #logo-design > .bento-grid > div:nth-child(2) > .card.no-padding:nth-child(1) {
        aspect-ratio: 1 / 1 !important;
        flex: none !important;
        height: auto !important;
        overflow: hidden !important;
        position: relative !important;
    }
    #logo-design > .bento-grid > div:nth-child(2) > .card.no-padding:nth-child(1) > picture > img {
        position: absolute !important;
        top: 0 !important;
        left: 0 !important;
        width: 100% !important;
        height: 100% !important;
        object-fit: cover !important;
        object-position: center 35% !important;
    }

    /* Logo SVG: landscape Card mit zentriertem Wort-Bild-Marke-SVG. */
    #logo-design > .bento-grid > div:nth-child(2) > .card.no-padding:nth-child(2) {
        aspect-ratio: 16 / 9 !important;
        flex: none !important;
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
    }
    #logo-design > .bento-grid > div:nth-child(2) > .card.no-padding:nth-child(2) > img {
        position: static !important;
        width: 65% !important;
        height: auto !important;
        max-height: 75% !important;
        object-fit: contain !important;
    }

    .cd-text br { display: none; }

    /* Text als eingefärbte Card — visuell getrennt von Bildern.
       Typografie nach Portfolio-Typografie-Vorgaben.pdf (Section 2, 3, 11):
       - Silbentrennung: hyphens auto + -ms-prefix für ältere Edge.
       - hyphenate-limit-chars 6 3 3: Trennen erst bei Wörtern ≥6 Buchstaben,
         min. 3 Zeichen vor + nach dem Bindestrich (matcht InDesign-Setup).
       - Explizite Defaults für text-align/word-spacing/letter-spacing:
         keine künstliche Stauchung/Sperrung, sauberer Flattersatz.
       - hanging-punctuation kommt von der base .cd-text-Rule (Z. 1032),
         text-wrap: pretty von .cd-text p (Z. 1041) — beide auf Mobile aktiv.
       - Eigennamen wie "Frankfurt am Main" sind im HTML per &nbsp; gegen
         Zeilen-Splits geschützt (siehe index.html). */
    .cd-text {
        font-size: 0.9rem !important;
        background-color: #f1f2f4 !important;
        padding: 24px !important;
        border-radius: 18px !important;
        -webkit-hyphens: auto;
        -ms-hyphens: auto;
        hyphens: auto;
        hyphenate-limit-chars: 6 3 3;
        text-align: left;
        word-spacing: normal;
        letter-spacing: normal;
        word-wrap: break-word;
        overflow-wrap: break-word;
    }

    .cd-text > p:not(:first-of-type) { margin-top: 14px !important; }

    /* Logo-Cards als 2-up Mikro-Bento (statt vertikalem Stack) */
    .bento-grid .cd-logo-cards {
        display: grid !important;
        grid-template-columns: 1fr 1fr !important;
        grid-auto-flow: row !important;
        gap: 20px !important;
        flex-direction: unset !important;
    }


    /* Social-Media auf Mobile: alle Elemente volle Rasterbreite, vertikal gestapelt.
       Das allgemeine .bento-grid flex-column-Layout übernimmt; nur Seitenverhältnisse fixieren. */
    #social-media .sm-col .card,
    #social-media .sm-left .card {
        aspect-ratio: auto !important;
        height: auto !important;
        align-self: start !important;
    }
    #social-media .sm-col .card img,
    #social-media .sm-left .card img {
        width: 100% !important;
        height: auto !important;
        object-fit: contain !important;
    }

    /* Print & Merchandise: erstes Bild full-width, danach 2-up */
    .merch-images {
        display: grid !important;
        grid-template-columns: 1fr 1fr !important;
        grid-auto-rows: min-content !important;
        align-content: start !important;
        gap: 20px !important;
        flex-direction: unset !important;
        margin: 0 !important;
        height: auto !important;
        min-height: 0 !important;
    }

    .merch-images > .card:first-child { grid-column: 1 / -1 !important; aspect-ratio: 1.687 / 1 !important; }
    .merch-images > .card:nth-child(n+2) { aspect-ratio: 1 / 1 !important; }

    /* Print & Merchandise auf Mobile:
       Das Standard-Mobile-Layout (Z. 1652-1660) gibt jedem inner-grid-div
       einen 20px-Gap. Bei merch-images↔cd-text ist das durch die graue
       Card-Optik der cd-text optisch zu prominent.
       Strategie: Gap auf 0 setzen → cd-text legt sich flush an die
       Bildreihe an. Die interne padding:24px der Gray-Box gibt dem Text
       Atemraum. So entsteht eine visuelle Einheit Bilder↔Text-Card,
       wie auch bei .sm-col in Social-Media. */
    #event-branding .bento-grid > div > div[style*="grid-template-columns"] {
        gap: 0 !important;
        row-gap: 0 !important;
        column-gap: 0 !important;
    }
    #event-branding .merch-images {
        margin: 0 !important;
        padding: 0 !important;
    }
    /* ~ (allgemeiner Geschwister-Selektor) statt + (direkter Nachbar):
       Die cd-text-Boxen DE und EN sind beide Geschwister von .merch-images,
       aber EN ist NACH DE im DOM. Mit `+ .cd-text` würde nur DE getroffen
       (= direkter Nachbar). Im EN-Modus ist DE display:none, kriegt aber
       trotzdem das margin-top — sichtbar wirkt es nur, wenn die getroffene
       Box auch die aktive ist. Mit `~` matchen beide cd-text-Boxen, also
       greift der Abstand sprachunabhängig. */
    #event-branding .merch-images ~ .cd-text {
        margin-top: 20px !important;
    }


    /* Abstand zwischen Plakat-Bild und Text.
       HINWEIS: Früher stand hier zusätzlich `display: block !important`.
       Das wurde entfernt, weil es die Critical-CSS Lang-Toggle-Regel
       (display:none auf der inaktiven Sprache) ausgehebelt hat → Mobile
       zeigte beide Sprachen gleichzeitig. cd-text ist als <div> ohnehin
       per Default display:block, das !important war überflüssig. */
    #event-branding .bento-grid > div:first-child > div[style*="grid-template-columns"] > .cd-text,
    #event-branding .bento-grid > div:first-child .cd-text {
        margin-top: 20px !important;
    }

    #event-branding .bento-grid > div:first-child > div[style*="grid-template-columns"] > div:first-child {
        margin-bottom: 0 !important;
    }

    /* Lebenslauf / CV */
    .cv-block { margin-bottom: 40px; }

    .cv-entry {
        padding: 18px 12px;
        margin: 0 -12px;
        flex-direction: column;
        gap: 6px;
    }

    .cv-date {
        font-size: 0.75rem !important;
        width: auto;
    }

    .cv-details strong {
        font-size: 0.95rem;
        font-variation-settings: "wdth" 75 !important;
    }

    .cv-details p {
        font-size: 0.9rem;
        font-variation-settings: "wdth" 75 !important;
        line-height: 1.5;
    }

    /* Downloads */
    .download-card {
        padding: 20px !important;
        min-height: auto !important;
        margin-bottom: 0 !important;
        gap: 20px !important;
    }

    .download-card p {
        font-variation-settings: "wdth" 75 !important;
    }

    .download-btn {
        font-size: 1rem !important;
        padding: 8px 20px 11px 20px !important;
    }

    /* Lightbox: alle Buttons als gleich große blaue Kreise (54px) */
    .lightbox-close,
    .lightbox-prev,
    .lightbox-next {
        width: 54px !important;
        height: 54px !important;
        padding: 0 !important;
        background-color: var(--col-primary) !important;
        border-radius: 50% !important;
        display: flex !important;
        justify-content: center !important;
        align-items: center !important;
        box-sizing: border-box !important;
    }
    .lightbox-close { top: 10px !important; right: 15px !important; }
    .lightbox-prev { left: 15px !important; }
    .lightbox-next { right: 15px !important; }

    .lightbox-close img,
    .lightbox-prev img,
    .lightbox-next img {
        width: 20px !important;
        height: 20px !important;
    }

    /* Navigation (Header) */
    .nav-pill { padding: 10px 15px !important; }
    .logo { height: 40px !important; }
    /* HINWEIS: kein .main-nav a-Override hier — würde die Mobile-Menü-Styles
       (line 2151+: font-size: 3rem) mit !important kaputtmachen. Tap-Targets
       müssen ≥ 44 px sein, mit 1rem-Font + 8px-Padding waren's nur 33 px. */

    /* Color Cards */
    .color-card { border-radius: 15px !important; }
    .val-row span { font-size: 0.75rem !important; }

    /* Layout overrides */
    /* body overflow-x bewusst auf clip statt hidden — verhindert horizontales Scrollen,
       lässt aber viewport-fit=cover-Layout (100lvh) korrekt durchlaufen. */
    body { overflow-x: clip; }
    .container { padding: 0; width: 100%; max-width: 100%; }
    /* Footer-Padding matcht Section-Padding (24px), damit Kontakt-H1, Adresse,
       Impressum-Link etc. exakt mit „Downloads", Portfolio-Card-Edge usw.
       fluchten. Vorher 20px → 4px Versatz nach links sichtbar. */
    footer .container { padding: 0 24px; }

    .section-wrapper-offwhite,
    .downloads-wrapper {
        width: 100vw;
        margin-left: 50%;
        transform: translateX(-50%);
        padding: 60px 40px;
        border-radius: 0;
    }

    header {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        z-index: 1000;
        margin-bottom: 0;
        /* Mobile-Header nutzt nur Opacity-Fade (kein Transform-Slide), weil
           visualViewport-Pinning bereits inline transform setzt — wäre sonst
           Konflikt. Default versteckt, .header--visible fadet ein. */
        opacity: 0;
        transform: none;
        transition: opacity 0.4s ease;
        pointer-events: none;
    }
    header.header--visible {
        opacity: 1;
        pointer-events: auto;
    }

    .nav-pill {
        height: auto;
        flex-direction: row;
        flex-wrap: wrap;
        /* --safe-top wird via JS einmal beim Load eingefroren, weil Chrome
           Mobile env(safe-area-inset-top) bei URL-Bar-Collapse dynamisch
           ändert → Hamburger würde sonst beim Scrollen wandern. */
        padding: calc(var(--safe-top, env(safe-area-inset-top, 0px)) + 15px) 20px 15px;
        gap: 0;
        justify-content: space-between;
        width: 100vw;
        margin-left: 50%;
        transform: translateX(-50%);
        border-radius: 0;
        pointer-events: none;
    }

    .logo {
        margin-bottom: 0;
        height: 50px;
        order: 1;
        flex: 0 0 auto;
        margin-right: auto;
        pointer-events: auto;
    }

    .hamburger {
        position: relative;
        display: flex !important;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        gap: 5px;
        width: 54px !important;
        height: 54px !important;
        min-width: 54px !important;
        min-height: 54px !important;
        max-width: 54px !important;
        max-height: 54px !important;
        box-sizing: border-box !important;
        padding: 12px !important;
        flex: 0 0 54px !important;
        /* Glass-Effect wie die Desktop-Nav-Pill: col-primary mit 85 % Alpha
           plus 12 px Backdrop-Blur. */
        background-color: #4E47E0d9;
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        border-radius: 50% !important;
        border: none;
        cursor: pointer;
        z-index: 1002;
        order: 2;
        pointer-events: auto;
        margin-left: auto;
        font-size: 0;
        line-height: 0;
        transition: background-color 0.3s ease;
    }

    .hamburger.open {
        background: rgba(254, 253, 255, 0.12);
    }

    .hamburger span {
        width: 22px;
        height: 4px;
        background: var(--col-offwhite);
        border-radius: 0;
        transition: all 0.4s ease;
        position: relative;
        transform-origin: center;
    }

    .hamburger-close-icon {
        position: absolute;
        top: 50%;
        left: 50%;
        width: 22px;
        height: 22px;
        transform: translate(-50%, -50%) scale(0.6);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.3s ease, transform 0.3s ease;
    }

    .hamburger.open span { opacity: 0 !important; }

    .hamburger.open .hamburger-close-icon {
        opacity: 1;
        transform: translate(-50%, -50%) scale(1);
    }

    /* Fullscreen-Overlay-Menü — muss exakt so groß sein wie die Hero (die per JS
       auf die volle Display-Höhe gesetzt wird), sonst bleibt unten ein Streifen
       Hero sichtbar. Daher dieselbe Höhen-Fallback-Kette wie #start. */
    /* Menü deckt KOMPLETTEN Viewport inkl. Notch + Bottom ab. Beim Öffnen
       färbt das die Notch und den URL-Bar-Bereich in der Menü-Farbe (lila)
       — gewünschter Effekt für volle Menu-Coverage.
       WICHTIG: clip-path sorgt dafür, dass im geschlossenen Zustand die Notch-
       und Bottom-Safe-Area-Regionen aus dem Menü weggeschnitten sind. Bei
       Schließ-Animationen (opacity 1→0) wird der clip-path SOFORT angewandt
       (kein Transition) → iOS Safari sampelt instant das html-Background
       (Cyan, durch .nav-open-Pre-Warm bereits gesetzt) und kann seinen
       URL-Bar-Lerp ohne 0.35 s Verzögerung durch die Menü-Fade-Out starten.
       Beim Öffnen ist das Menü ohnehin opacity 0 — clip-path-Snapping nicht
       sichtbar. */
    .main-nav {
        position: fixed !important;
        top: 0 !important;
        left: 0 !important;
        right: 0 !important;
        bottom: 0 !important;
        width: 100vw !important;
        height: 100vh !important;
        height: 100lvh !important;
        height: 100dvh !important;
        margin: 0 !important;
        padding: calc(env(safe-area-inset-top, 0px) + 110px) 28px calc(env(safe-area-inset-bottom, 0px) + 60px) !important;
        /* background-color NUR im .open-Zustand setzen — sonst würde iOS
           den statischen CSS-Hintergrund auch im hidden-Zustand für
           UI-Tönungs-Sampling nutzen. */
        background-color: transparent;
        /* Notch + Bottom-Safe-Area weggeschnitten → iOS sampelt dort nicht
           das (fadende) Menü, sondern direkt das html-bg dahinter. */
        clip-path: inset(env(safe-area-inset-top, 0px) 0 env(safe-area-inset-bottom, 0px) 0);
        display: flex !important;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        z-index: 1001;
        opacity: 0;
        visibility: hidden;
        pointer-events: none;
        transform: none;
        transition: opacity 0.35s ease, visibility 0s linear 0.35s, background-color 0.35s ease;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }

    .main-nav.open {
        opacity: 1;
        visibility: visible;
        pointer-events: auto;
        background-color: var(--col-primary);
        /* Im geöffneten Zustand: Menü deckt alles inkl. Safe-Area ab. */
        clip-path: inset(0 0 0 0);
        transition: opacity 0.35s ease, visibility 0s linear 0s, background-color 0.35s ease;
    }

    body.nav-open { overflow: hidden; }

    /* Bei offenem Burger-Menü: html- und body-Background SCHLAGARTIG auf
       col-primary schalten (KEIN CSS-Transition!), damit iOS Safari sofort
       den finalen Lila-Wert sampelt und seinen internen URL-Bar-Lerp ohne
       Umwege starten kann. Ein CSS-Transition würde Zwischenfarben
       (Cyan→Lila Mischtöne) erzeugen, die iOS dann fälschlich als
       Tönungsfarbe interpretiert → sichtbar falsche Farbe + zusätzliche
       Verzögerung (CSS-Transition + iOS-Lerp aufaddiert). */
    html.nav-open,
    html.nav-open body,
    body.nav-open {
        background-color: var(--col-primary) !important;
        /* Gradient (Cyan-Top + Lila-Bottom) überschreiben → bei offenem Menü
           soll der ganze Viewport in Menü-Farbe (Lila) tauchen. */
        background-image: none !important;
    }


    .main-nav ul {
        flex-direction: column;
        flex-wrap: nowrap;
        justify-content: center;
        align-items: center;
        height: auto;
        padding: 0;
        gap: 35px;
        background-color: transparent;
        width: 100%;
        border-radius: 0;
        list-style: none;
        margin: 0;
    }

    .main-nav li {
        position: relative;
        width: 80%;
        max-width: 360px;
        text-align: center;
        border-bottom: none;
    }

    .main-nav li:not(:last-child)::after {
        content: '';
        position: absolute;
        bottom: -17px;
        left: 50%;
        transform: translateX(-50%);
        width: 100%;
        height: 1px;
        background-color: rgba(254, 253, 255, 0.18);
    }

    .main-nav a {
        font-family: 'Apfel Grotezk Fett', sans-serif;
        font-size: 1.15rem;
        line-height: 1.15;
        display: block;
        padding: 0;
        text-align: center;
        border-bottom: none;
        color: var(--col-offwhite);
        opacity: 0;
        transform: translateY(12px);
        transition: opacity 0.45s ease, transform 0.45s ease;
    }

    .main-nav.open a {
        opacity: 1;
        transform: none;
    }

    /* Staggered Reveal — jedes Element kommt 60 ms nach dem vorigen */
    .main-nav.open li:nth-child(1) a { transition-delay: 0.10s; }
    .main-nav.open li:nth-child(2) a { transition-delay: 0.16s; }
    .main-nav.open li:nth-child(3) a { transition-delay: 0.22s; }
    .main-nav.open li:nth-child(4) a { transition-delay: 0.28s; }
    .main-nav.open li:nth-child(5) a { transition-delay: 0.34s; }
    .main-nav.open li:nth-child(6) a { transition-delay: 0.40s; }
    .main-nav.open li:nth-child(7) a { transition-delay: 0.46s; }

    .main-nav a.active::after { display: none; }
    .main-nav a.nav-highlight { color: var(--col-secondary); }

    /* FAB-Buttons auf Mobile komplett ausblenden — Funktion wandert ins Menü. */
    #lang-toggle,
    #anim-toggle {
        display: none !important;
    }

    /* Preference-Row sichtbar als zwei runde FAB-Buttons nebeneinander, zentriert.
       Visuell identisch mit den Desktop-FABs (44×44, lila bg, weiße Schrift/Icon,
       Shadow), damit das Visual-Vocabulary konsistent bleibt. */
    .nav-pref-row {
        display: flex !important;
        justify-content: center;
        align-items: center;
        gap: 20px;
        list-style: none;
        /* Etwas mehr Abstand zum letzten Content-Link (Downloads & Kontakt),
           damit die Hierarchie "Navigation vs. Settings" lesbar bleibt. */
        margin-top: 10px !important;
        /* Eigener Divider weg, sonst Strich zwischen zwei runden Buttons */
    }
    /* Divider-Linien rund um die nav-pref-row unterdrücken:
       — Strich NACH "Downloads & Kontakt" raus (sonst optisch eine harte
         Trennung zur Settings-Row, der mt: 10px-Abstand reicht als Pause)
       — Strich INNERHALB der Row entfällt sowieso (nur ein li) */
    .main-nav li.nav-pref-row::after,
    .main-nav li:has(+ .nav-pref-row)::after {
        display: none !important;
    }

    .nav-fab {
        /* Glas-Effekt wie der Hamburger-Close-X im offenen Menü:
           12 % Offwhite-Overlay auf dem Lila-Menü-Background → gleicher
           visueller Token wie der ".hamburger.open"-State. */
        background-color: rgba(254, 253, 255, 0.12);
        color: var(--col-offwhite);
        border: none;
        border-radius: 50%;
        width: 44px;
        height: 44px;
        padding: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        opacity: 0;
        transform: translateY(12px);
        transition: opacity 0.45s ease, transform 0.45s ease,
                    background-color 0.18s ease-out;
        -webkit-tap-highlight-color: transparent;
        font-family: 'acumin-variable', 'acumin-fb', sans-serif;
        font-size: 0.85rem;
        font-weight: 600;
        letter-spacing: 0.5px;
    }
    .main-nav.open .nav-fab {
        opacity: 1;
        transform: none;
    }
    /* Anim-State: keine Background-Farb-Änderung mehr — Slash-Overlay reicht
       als Indikator, weil die Glas-Tönung konsistent bleibt. */
    .nav-fab--anim svg { display: block; pointer-events: none; }
    .nav-fab--anim svg .slash {
        opacity: 0;
        transition: opacity 0.18s ease-out;
    }
    html.anim-off .nav-fab--anim svg .slash { opacity: 1; }

    @media (hover: hover) {
        .nav-fab:hover {
            background-color: rgba(254, 253, 255, 0.2);
        }
    }
    .nav-fab:focus-visible {
        outline: 2px solid var(--col-offwhite);
        outline-offset: 3px;
    }
    /* Staggered Reveal: Settings-Row kommt nach den 7 Content-Links (Item 8). */
    .main-nav.open li:nth-child(8) .nav-fab { transition-delay: 0.52s; }
    .main-nav.open li:nth-child(8) .nav-fab + .nav-fab { transition-delay: 0.58s; }
    .main-nav.open li:nth-child(8) .nav-fab + .nav-fab + .nav-fab { transition-delay: 0.64s; }

    #members .section-title,
    #members h3 {
        padding-left: 0;
    }

    .footer-text-area,
    .section-title,
    .section-wrapper-offwhite h2,
    .section-wrapper-offwhite h3,
    .footer-layout {
        padding-left: 0 !important;
        margin-left: 0 !important;
        margin-right: 0 !important;
        text-align: left !important;
        align-items: flex-start !important;
    }

    #members .bento-grid .card,
    #event-branding .bento-grid .card,
    #social-media .bento-grid .card,
    #logo-design .bento-grid .card { max-width: 100% !important; }

    #members .cd-logo-cards,
    #members .cd-color-cards { max-width: 100% !important; }

    #members .cd-logo-cards .card,
    #members .cd-color-cards .card { max-width: 100% !important; }

    #members .bento-grid .card img,
    #social-media .bento-grid .card img {
        height: auto !important;
        object-fit: contain !important;
    }

    /* Bilder füllen die Card komplett. Wegen display:flex auf .card greift
       height:100% am img sonst nicht (picture als Flex-Child würde nur
       Content-Höhe nehmen → bei aspect-ratio 1/1 + 1.687/1-Bild blieb unten
       transparenter Leerraum, der wie eine Lücke aussah). */
    #event-branding .merch-images .card > picture,
    #event-branding .merch-images .card > img:first-child {
        width: 100% !important;
        height: 100% !important;
        display: block !important;
        flex: 1 1 auto !important;
        min-height: 0 !important;
    }
    #event-branding .merch-images .card > picture > img {
        width: 100% !important;
        height: 100% !important;
        object-fit: cover !important;
        display: block !important;
    }

    #members .cd-text,
    #event-branding .cd-text,
    #social-media .cd-text,
    #logo-design .cd-text { max-width: 100% !important; }

    #lebenslauf,
    #members,
    #event-branding,
    #social-media,
    #logo-design {
        padding-top: 40px !important;
        padding-bottom: 40px !important;
        margin-bottom: 0 !important;
    }

    .downloads-wrapper {
        padding-top: 40px !important;
        padding-bottom: 40px !important;
    }

    #members h3,
    #event-branding h3,
    #social-media h3,
    #logo-design h3 {
        margin-top: 0 !important;
        margin-bottom: 0 !important;
    }

    /* Mobile-Boost: Apfel Grotezk Mittel statt synthetisches Browser-Bold.
       Hält die Desktop-Wahl (Mittel) auch auf Mobile konsistent. */
    h3 {
        font-family: 'Apfel Grotezk Mittel', sans-serif !important;
        font-weight: 400 !important;
    }

    /* Visueller Abstand cd-text → folgender h3 soll dem h2 → h3 (20px) entsprechen. */
    #members > .bento-grid,
    #event-branding > .bento-grid { gap: 20px !important; }


    /* Case C: h3 als direktes Section-Kind (nicht in Bento-Item).
       Hier braucht's eine explizite margin-bottom, weil kein Flex-Gap greift. */
    #social-media > h3,
    #logo-design > h3 {
        margin-bottom: 20px !important;
    }

    #members .bento-grid > div:last-child { margin-top: 0 !important; }

    .typo-header-left h3,
    .typo-header-right h3 { margin-bottom: 0 !important; }

    /* Footer Mobile Override */
    footer#footer-kontakt {
        padding: 70px 0 70px 0 !important;
    }

    footer#footer-kontakt .footer-layout {
        display: flex !important;
        flex-direction: row !important;
        flex-wrap: nowrap !important;
        align-items: flex-end !important;
        justify-content: space-between !important;
        text-align: left !important;
        gap: 15px !important;
    }

    footer#footer-kontakt .footer-text-area {
        display: block !important;
        flex: 1 !important;
        min-width: 0 !important;
    }

    footer#footer-kontakt .footer-text-area h1 {
        font-size: 2rem !important;
        margin-bottom: 8px !important;
    }

    footer#footer-kontakt .footer-columns {
        display: flex !important;
        flex-direction: row !important;
        gap: 15px !important;
        width: 100% !important;
    }

    footer#footer-kontakt .footer-col-left,
    footer#footer-kontakt .footer-col-right {
        display: flex !important;
        flex-direction: column !important;
        flex: 1 !important;
        order: unset !important;
        align-items: flex-start !important;
        gap: 15px !important;
    }

    footer#footer-kontakt .footer-col-left p,
    footer#footer-kontakt .footer-col-right p {
        margin: 0 !important;
        padding: 0 !important;
        order: unset !important;
        font-size: 0.85rem !important;
        width: auto !important;
        line-height: 1.5 !important;
    }

    footer#footer-kontakt .footer-legal-links {
        display: flex !important;
        flex-direction: column !important;
        gap: 10px !important;
        margin-top: auto !important;
    }

    footer#footer-kontakt .footer-legal-links a { font-size: 0.85rem !important; }

    footer#footer-kontakt .scroll-top-btn {
        width: 40px !important;
        flex-shrink: 0 !important;
        margin-left: 0 !important;
        margin-top: 0 !important;
        align-self: flex-end !important;
    }

    footer#footer-kontakt .footer-contact-list {
        display: flex !important;
        flex-direction: column !important;
    }

    footer#footer-kontakt .footer-contact-item {
        margin: 0 !important;
        padding: 0 !important;
        font-size: 0.85rem !important;
        line-height: 1.5 !important;
        gap: 8px !important;
        align-items: center !important;
    }

    footer#footer-kontakt .footer-icon,
    footer#footer-kontakt .footer-icon-wrap {
        width: 18px !important;
        height: 18px !important;
        flex-shrink: 0 !important;
    }

    footer#footer-kontakt .footer-contact-list {
        gap: 0 !important;
    }

    /* Login Overlay Mobile */
    #login-overlay { height: 100dvh !important; }
    .login-box { padding: 30px 20px !important; width: 92% !important; }
    .login-box h2 { font-size: 2rem !important; white-space: normal !important; }
    .login-box input { font-size: 1rem !important; }

    /* =====================================================================
       Mobile Scroll-FX:
         • Hero-Parallax aus Variant „Cinematic" (Faktor 0.4, JS-driven)
       Progress-Bar wurde entfernt — Hero-Parallax bleibt als einziger
       Scroll-Effekt aktiv via body.fx-on.
       ===================================================================== */

    /* ----- Hero-Parallax: Cinematic-Faktor 0.4 (JS setzt translate3d) ----- */
    body.fx-on #start picture img {
        will-change: transform;
    }

    /* Reduced-Motion: User-Setting hat Vorrang */
    @media (prefers-reduced-motion: reduce) {
        body.fx-on #start picture img {
            transform: none !important;
        }
    }
}



/* =========================================================================
   Small-Desktop Tweaks (992 – 1199 px)
   ----
   In diesem Bereich ist das Desktop-Bento-Grid aktiv, aber der Container
   ist viel schmaler als die designte Soll-Breite (1440 px). Mit 88 px
   Side-Padding bleibt zu wenig Inhalt übrig — Spalten schrumpfen auf
   58–75 px (statt 95 px), Color-Palette und Bento-Grids wirken gequetscht.
   Fix: Padding auf 40 px reduzieren → +96 px Inhalt-Breite.
   Hero-Overlay & Scroll-Arrow ziehen mit, damit ihre Y-Achse weiter mit
   dem Section-Text fluchtet (sonst würden sie 88 px vom Rand stehen,
   während die Sections 40 px haben).
   ========================================================================= */
@media (min-width: 992px) and (max-width: 1199px) {
    /* Eine Zeile statt 3 separater Overrides: --container-pad wird zentral
       gesteuert, .container, .hero-overlay, Sections etc. lesen daraus
       automatisch — Konsistenz garantiert. */
    :root {
        --container-pad: 40px;
    }
}


/* =========================================================================
   Tablet-Range Footer Restore (600 – 991 px)
   ----
   Im Mobile-Block (max-width: 991px) sind die Footer-Werte für Phones
   getuned (h1 = 2rem, Text 0.85rem, Scroll-Btn 40 px, Gaps 15 px). Das
   wirkt auf Tablets zu eng. Hier ziehen wir die Footer-Maße zurück auf
   Desktop-ähnliche Werte, damit Headline und Spalten "an den üblichen
   Positionen" sitzen — das Layout (flex-row) bleibt identisch.
   ========================================================================= */
@media (min-width: 600px) and (max-width: 991px) {
    footer#footer-kontakt .footer-layout {
        gap: 40px !important;
    }

    footer#footer-kontakt .footer-text-area h1 {
        font-size: 2.5rem !important;
        margin-bottom: 10px !important;
    }

    footer#footer-kontakt .footer-columns {
        gap: 40px !important;
    }

    footer#footer-kontakt .footer-col-left,
    footer#footer-kontakt .footer-col-right {
        gap: 30px !important;
    }

    footer#footer-kontakt .footer-col-left p,
    footer#footer-kontakt .footer-col-right p,
    footer#footer-kontakt .footer-contact-item,
    footer#footer-kontakt .footer-legal-links a {
        font-size: 1rem !important;
        line-height: 1.6 !important;
    }

    footer#footer-kontakt .footer-contact-list {
        gap: 14px !important;
    }

    footer#footer-kontakt .footer-icon,
    footer#footer-kontakt .footer-icon-wrap {
        width: 22px !important;
        height: 22px !important;
    }

    footer#footer-kontakt .scroll-top-btn {
        width: 60px !important;
    }

    footer#footer-kontakt .scroll-top-btn img {
        width: 40px !important;
    }
}
/* =========================================================================
   Einrasten der Inhalts-Sections (nur Desktop, html.snap-on per script.js)
   ---------------------------------------------------------------------------
   Aufbau: .snap-track > .snap-stage > section + .snap-runway, danach im Track
   eine zweite .snap-runway. Die Runways liefern die zusaetzliche Scroll-
   Strecke, waehrend der die Section per position: sticky stehen bleibt und
   ihr Text eingefaerbt wird. Kein Abfangen von Rad/Trackpad — der Browser
   scrollt ganz normal, deshalb bleibt es auch mit Schwung fluessig.
   Zwei verschachtelte sticky-Ebenen erlauben zwei Halte-Punkte (Corporate
   Design: erst Wort-Bild-Marke + Farbwelt, dann Typografie + Plakat):
   - Section:  top = --snap-t1          → Halt 1 (Strecke = Runway 1)
   - Stage:    top = --snap-t2 − Runway 1 → Halt 2 (Strecke = Runway 2)
   Sections mit nur einem Halt haben Runway 2 = 0.
   Runways als eigene Elemente statt padding: sticky bewegt sich nur im
   Inhaltsbereich des Eltern-Elements, nicht in dessen padding.
   ========================================================================= */
html.snap-on .snap-stage {
    position: sticky;
    top: calc(var(--snap-t2, 0px) - var(--snap-r1, 0px));
}
html.snap-on .snap-stage > section {
    position: sticky;
    top: var(--snap-t1, 0px);
    /* Niedrige Bildschirme: proportional verkleinern (script.js, MIN_ZOOM).
       Feste Layoutbreite, damit das Raster nicht in die frei werdende Breite
       waechst; margin auto zentriert die verkleinerte Section. */
    zoom: var(--snap-zoom, 1);
    width: var(--snap-width, auto);
    margin-inline: auto;
}
.snap-runway {
    height: 0;
}
html.snap-on .snap-stage > .snap-runway {
    height: var(--snap-r1, 0px);
}
html.snap-on .snap-track > .snap-runway {
    height: var(--snap-r2, 0px);
}

/* Stehender Titel (Section mit zwei Halten, .snap-title-sticky per script.js):
   H1 + H2 bleiben ab Halt 1 stehen, der erste Teil scrollt darunter weg, der
   zweite rastet unter dem Titel ein. Losgelassen wird der Titel, wenn Halt 2
   endet: seine margin-bottom waechst um --snap-title-hold, damit er genau dann
   ans Inhaltsende der Section stoesst (sticky bleibt im Eltern-Element). Die
   Folge-Reihe gleicht das mit negativem margin-top aus — beide Margins
   kollabieren, das Layout bleibt unveraendert. */
html.snap-on .snap-title-sticky .snap-stage > section > .section-title {
    position: sticky;
    top: var(--snap-title-top, 0px);
    z-index: 3;
    margin-bottom: calc(var(--snap-title-gap, 10px) + var(--snap-title-hold, 0px)) !important;
}
html.snap-on .snap-title-sticky .snap-stage > section > .section-title + * {
    margin-top: calc(var(--snap-title-hold, 0px) * -1) !important;
}
/* Deckende Flaeche vom Viewport-Rand bis zur Titel-Unterkante, volle Breite —
   der wegscrollende erste Teil verschwindet dahinter statt durch die Schrift
   zu laufen. */
html.snap-on .snap-title-sticky .snap-stage > section > .section-title::before,
html.snap-on .snap-title-sticky .snap-stage > section > .section-title::after {
    content: '';
    position: absolute;
    z-index: -1;
    /* volle Viewport-Breite, in Zoom-Pixeln der Section (script.js) */
    left: calc(var(--snap-bleed, 0px) * -1);
    right: calc(var(--snap-bleed, 0px) * -1);
    pointer-events: none;
}
html.snap-on .snap-title-sticky .snap-stage > section > .section-title::before {
    top: calc(var(--snap-title-top, 0px) * -1);
    bottom: 0;
    background: var(--col-offwhite);
}
/* Progressive-Blur-Zone unter dem Titel (Technik wie .edge-blur). Nur sichtbar,
   waehrend der erste Teil darunter wegscrollt (.snap-title-moving per
   script.js) — in den Halten laege sie sonst ueber den Zwischenueberschriften,
   die nur 10px unter dem Titel stehen. Hoehe = TITLE_BLUR in script.js. */
html.snap-on .snap-title-sticky .snap-stage > section > .section-title::after {
    top: 100%;
    height: 48px;
    background: linear-gradient(to bottom, var(--col-offwhite), rgba(254, 253, 255, 0));
    -webkit-mask-image: linear-gradient(to bottom, #000 50%, transparent);
    mask-image: linear-gradient(to bottom, #000 50%, transparent);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    opacity: 0;
    transition: opacity 0.25s ease;
}
html.snap-on .snap-title-sticky.snap-title-moving .snap-stage > section > .section-title::after {
    opacity: 1;
}
html.fx-lite.snap-on .snap-title-sticky .snap-stage > section > .section-title::after {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

/* =========================================================================
   Rand-Unschaerfe oben (Desktop)
   ---------------------------------------------------------------------------
   Technik nachgebaut nach Skiper UI "Progressive Blur" (skiper41): feste
   Leiste mit backdrop-filter (Inhalt darunter wird weich), Verlauf in die
   Seitenfarbe und eine Maske, die den Effekt zur Bildmitte hin ausblendet.
   Nur noch oben (die Leiste unten ist entfernt). Sichtbarkeit steuert
   script.js (edgeBlur) ueber html.edge-blur-top.
   Blur 4px: laut Vorlage gut hardware-beschleunigt. fx-lite schaltet nur
   den Weichzeichner ab, der Farbverlauf bleibt.
   z-index 999: ueber dem Inhalt, unter Header (1000), FABs und Lightbox.
   ========================================================================= */
.edge-blur {
    display: none;
}
@media (min-width: 992px) and (hover: hover) and (pointer: fine) {
    .edge-blur {
        display: block;
        position: fixed;
        left: 0;
        right: 0;
        height: 140px;
        z-index: 999;
        pointer-events: none;
        user-select: none;
        -webkit-backdrop-filter: blur(4px);
        backdrop-filter: blur(4px);
        opacity: 0;
        transition: opacity 0.3s ease;
    }
    .edge-blur--top {
        top: 0;
        background: linear-gradient(to bottom, var(--col-offwhite), rgba(254, 253, 255, 0));
        -webkit-mask-image: linear-gradient(to bottom, #000 50%, transparent);
        mask-image: linear-gradient(to bottom, #000 50%, transparent);
    }
    html.edge-blur-top .edge-blur--top {
        opacity: 1;
    }
    html.fx-lite .edge-blur {
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

/* Ziel des Hero-Pfeils (Skip-Link) bekommt per script.js tabindex="-1" und den
   Fokus — ohne sichtbaren Rahmen um die ganze Section. */
section[tabindex="-1"]:focus {
    outline: none;
}

/* Nav-Pille, Hero-Titel und Hero-Pfeil auf dieselben 12 Spalten wie die
   Sections legen. Auf niedrigen Bildschirmen sind die Sections verkleinert
   (sectionSnap, CSS zoom) — --snap-content-width/-left halten Navbar und Hero
   buendig dazu. Ohne Skalierung entsprechen die Werte dem Container. */
/* Header liegt im Fluss und zieht sich per negativem margin-bottom ueber das
   Hero: Hoehe (= Pille, 90px) + margin = -30px, passend zu Hero-Hoehe
   100svh + 30px. Skaliert die Pille mit (--snap-zoom-all), wird der Header
   niedriger — der margin muss mitgehen, sonst rutscht das Hero hoch und
   unten blitzt die naechste Section durch. */
html.snap-on header {
    margin-bottom: calc(-30px - 90px * var(--snap-zoom-all, 1));
}
html.snap-on .nav-pill {
    /* Gleicher Zoom wie die Sections, damit die Nav-Schrift mitschrumpft und
       die Pille nicht ueberlaeuft. Breite in Zoom-Pixeln = Layoutbreite der
       Sections → sichtbar exakt so breit wie sie. */
    zoom: var(--snap-zoom-all, 1);
    width: var(--snap-layout-width, 100%);
    margin-inline: auto;
}
html.snap-on .hero-overlay,
html.snap-on .hero-scroll-arrow--desktop {
    left: var(--snap-content-left, calc(max((100vw - var(--container-width)) / 2, 0px) + var(--container-pad)));
}

/* =========================================================================
   Schriftgroessen-Variante (html.type-large, Umschalter #type-toggle)
   ---------------------------------------------------------------------------
   Variante A (Standard): Sections werden so weit verkleinert, wie fuers
   Einrasten noetig, aber nur bis Fliesstext 13px.
   Variante B (type-large): Verkleinerung nur so weit, dass der Fliesstext
   sichtbar 14px behaelt. Passt ein Halt dann nicht ins Bild, bleibt der Titel
   oben stehen und der Inhalt reicht unten darueber hinaus.
   ========================================================================= */
/* Variante B aendert die Schriftgroesse NICHT: Die Umbrueche im Fliesstext
   sind fest gesetzt (<br>) und Teil des Layouts — eine groessere Schrift bei
   gleicher Spaltenbreite wuerde zusaetzlich umbrechen. Stattdessen wird die
   Section weniger stark verkleinert (minZoom in script.js), das Layout bleibt
   identisch und nur groesser. */
#type-toggle {
    position: fixed;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 240px);
    right: 16px;
    z-index: 9500;
    background-color: var(--col-offblack);
    color: var(--col-offwhite);
    border: none;
    border-radius: 50%;
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
    transition: transform 0.18s ease-out, box-shadow 0.18s ease-out, opacity 0.2s ease;
    -webkit-tap-highlight-color: transparent;
    font-family: 'acumin-variable', 'acumin-fb', sans-serif;
    font-size: 0.82rem;
    font-weight: 700;
    opacity: 0.55;
}
html.type-large #type-toggle {
    background-color: var(--col-primary);
    opacity: 1;
}
@media (hover: hover) {
    #type-toggle:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25); }
}
#type-toggle:focus-visible { outline: 2px solid var(--col-primary); outline-offset: 3px; }
@media (max-width: 991px) {
    #type-toggle { display: none; }
}

/* Farbfelder in Corporate Design quadratisch halten, ohne aspect-ratio.
   Safari rechnet aspect-ratio innerhalb von CSS zoom nicht mit — die Felder
   blieben dort gross, waehrend alles andere schrumpfte. Stattdessen erzwingt
   ein ::after mit padding-top: 100% die Hoehe: Prozent-Padding bezieht sich
   auf die BREITE des Eltern-Elements und verhaelt sich in jedem Browser
   gleich. Die Werte liegen darueber absolut am unteren Rand.
   Nur im skalierten Desktop-Layout; Mobile behaelt die bestehende Regel. */
@media (min-width: 992px) {
    html.snap-on .cd-color-cards .color-card {
        aspect-ratio: auto;
        display: block;
        position: relative;
        padding: 20px;
    }
    /* ::after statt ::before: ::before war frueher fuer den Hover-Lichtrand
       (Bento-Glow) belegt; ::after bleibt frei von Kollisionen. */
    html.snap-on .cd-color-cards .color-card::after {
        content: '';
        display: block;
        padding-top: 100%;
    }
    html.snap-on .cd-color-cards .color-card > .color-vals {
        position: absolute;
        left: 20px;
        right: 20px;
        bottom: 20px;
    }
}

/* Lebenslauf verdichten (sectionSnap, --cv-t am Track): Auf niedrigen
   Bildschirmen passt er nicht bei demselben Faktor wie die Projekt-Sections.
   Statt alle Sections staerker zu verkleinern, ruecken seine Eintraege
   zusammen: --cv-t = 1 normale Abstaende, 0 = engste Stufe (Abstaende 35 %,
   Zeilenabstand 1.3). Die Schriftgroesse bleibt unveraendert. */
html.snap-on #lebenslauf .cv-entry {
    padding-top: calc(18px * (0.35 + 0.65 * var(--cv-t, 1)));
    padding-bottom: calc(18px * (0.35 + 0.65 * var(--cv-t, 1)));
}
html.snap-on #lebenslauf .cv-block:not(:last-child) {
    margin-bottom: calc(50px * (0.35 + 0.65 * var(--cv-t, 1)));
}
html.snap-on #lebenslauf .cv-details p {
    line-height: calc(1.3 + 0.2 * var(--cv-t, 1));
}

/* Grenzfall niedrige Bildschirme (sectionSnap, --snap-media am Track):
   Passt eine Section bei Fliesstext-Untergrenze noch nicht ins Bild,
   schrumpfen nur ihre Bild-Gruppen ([data-snap-media]: Device, Plakate,
   Logo-, Farb-, Typo-Karten …) weiter. zoom wirkt aufs Layout; script.js
   friert dafuer die natuerliche Breite der Gruppe ein (inline width).
   Die Abstaende auf der X-Achse bleiben gleich:
   - innerhalb einer Gruppe: gap wird um 1/--snap-media vergroessert, der
     zoom macht daraus wieder genau --grid-gap,
   - daneben: [data-snap-follow] rueckt um den gesparten Platz nach links
     (--snap-shift, per translate — aendert weder Breite noch Umbrueche). */
html.snap-on .snap-track [data-snap-media] {
    zoom: var(--snap-media, 1);
}
html.snap-on .snap-track [data-snap-media],
html.snap-on .snap-track [data-snap-media] > div:not(.card) {
    gap: calc(var(--grid-gap) / var(--snap-media, 1)) !important;
}
html.snap-on .snap-track [data-snap-follow] {
    translate: calc(var(--snap-shift, 0px) * -1) 0;
}

/* Downloads und Kontakt (Footer) auf dieselbe Breite und denselben Faktor wie
   die uebrigen Sections: Inhalt mit gemeinsamem Zoom (--snap-zoom-all) und
   Layoutbreite der Sections, zentriert — damit fluchten die Kanten mit
   Navbar und Sections, und die Schrift ist ueberall gleich gross. Die
   Hintergrundflaechen (Footer-Lila) bleiben vollflaechig. */
html.snap-on .downloads-wrapper > *,
html.snap-on #footer-kontakt .footer-content > .footer-layout {
    zoom: var(--snap-zoom-all, 1);
    width: var(--snap-layout-width, auto);
    margin-inline: auto;
}
