/* moritzsauer.com
   Farben: die Root-Palette von nectex.io (style.css, Palette "native") - Grundtoene je Thema, alles Abgeleitete
   steht genau einmal in :root. Das Thema haengt als data-theme am <html> (Kopf-Script in index.html, style.js).
   Wer einen Ton braucht, gibt ihm eine Rolle in BEIDEN Bloecken - keine Zweitnamen (s. nectex.io/FARBEN.md). */

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

/* ===== Marke und Masse ========================================================================== */
:root {
    --ci-primary:#235ffe;
    --ci-secondary:#6934fd;
    /* 135deg = oben links nach unten rechts, Lila ab 75% - wie nectex. */
    --ci-gradient:linear-gradient(135deg, var(--ci-primary) 0%, var(--ci-secondary) 75%);
    --ci-gradient-hover:linear-gradient(135deg, var(--ci-primary) -25%, var(--ci-secondary) 50%);
    --ci-focus:color-mix(in srgb, var(--ci-primary) 35%, var(--ci-secondary));
    --radius-control:8px;
    --radius-card:18px;
    --header-height:76px;
    --wrap:1120px;
    --gutter:24px
}

/* ===== Grundtoene hell (Standard, gilt schon vor dem ersten Script) ============================= */
:root, [data-theme=light] {
    /* Browser-eigene Elemente (Checkbox, Scrollleiste, Autofill) im passenden Thema. */
    color-scheme:light;
    --bg:#ffffff;
    --bg-surface:#f2f2f2;
    --bg-section:#ebebeb;
    --text-primary:#1e1e1e;
    --text-secondary:#424242;
    --text-tertiary:#696969;
    --text-muted:#818181;
    --border:#e6e6e6;
    --border-strong:#dcdcdc;
    --grid-line:rgba(35,95,254,.10);
    --black-white:#000000;
    --error:#e5484d;
    --btn-hover:color-mix(in srgb, var(--border) 70%, rgb(0 0 0 / 0));
    --btn-shadow:rgba(94, 143, 156, 0.3);
    --shadow-default:0 4px 24px rgba(0, 0, 0, 0.2);
    --shadow-input-focus:0 0 0 4px rgba(97, 142, 208, 0.15);
    /* Milchglas wie nectex: erhobene Flaechen lassen durch und unschaerfen. */
    --surface-glas:color-mix(in srgb, var(--bg-surface) 72%, rgb(0 0 0 / 0));
    --surface-glas-dicht:color-mix(in srgb, var(--bg-surface) 88%, rgb(0 0 0 / 0));
    --surface-blur:saturate(160%) blur(14px);
    /* Akzent als TEXT: auf hellem Grund traegt das CI-Blau selbst (5,3:1 auf Weiss). */
    --accent-text:var(--ci-primary);
    --card-shadow-hover:0 22px 44px -22px rgba(16, 17, 22, .28)
}
[data-theme=dark] {
    /* NUR die Grundtoene - alles Abgeleitete steht in :root und folgt von selbst. */
    color-scheme:dark;
    --bg:#121212;
    --bg-surface:#272727;
    --bg-section:#2f2f2f;
    --text-primary:#ffffff;
    --text-secondary:#e6e6e6;
    --text-tertiary:#a9a9a9;
    --text-muted:#696969;
    --border:#333333;
    --border-strong:#3d3d3d;
    --grid-line:rgba(150,168,255,.16);
    --black-white:#ffffff;
    --shadow-default:0 8px 40px rgba(0, 0, 0, 0.4);
    /* Auf #121212 hat das CI-Blau nur 3,9:1 - aufgehellt liest es sich als Text. */
    --accent-text:color-mix(in srgb, var(--ci-primary) 62%, #ffffff);
    --card-shadow-hover:0 22px 44px -22px rgba(0, 0, 0, .7)
}

/* Beim Umlegen des Schalters springen die Farben ohne Uebergang um (style.js setzt die Klasse fuer einen Frame) -
   sonst liefen Karten, Knoepfe und Felder einzeln und versetzt nach. */
html.theme-switching *,
html.theme-switching *::before,
html.theme-switching *::after {
    transition:none!important
}

/* ===== Grundgeruest ============================================================================= */
html {
    scroll-behavior:smooth;
    scroll-padding-top:calc(var(--header-height) + 12px);
    -webkit-text-size-adjust:100%
}
body {
    /* Google Translate setzt top auf den Rumpf (Platz fuer seine Leiste) - die ist ausgeblendet. */
    top:0!important;
    font-family:Nunito, 'Segoe UI', system-ui, -apple-system, sans-serif;
    font-size:17px;
    line-height:1.6;
    background:var(--bg);
    color:var(--text-primary);
    /* Bezug fuer das leuchtende Raster (.raster-schein), das ueber die ganze Seite reicht. */
    position:relative;
    min-height:100vh;
    min-height:100dvh;
    /* Fusszeile immer unten: der Rumpf ist eine Spalte ueber die volle Hoehe, <main> nimmt den Rest. So klebt der
       Fuss auch bei kurzen Seiten (Visitenkarte, Uebersetzung laedt) am unteren Rand statt mittendrin zu stehen. */
    display:flex;
    flex-direction:column;
    overflow-x:clip;
    -webkit-font-smoothing:antialiased;
    text-rendering:optimizeLegibility
}
main {
    flex:1 0 auto
}
img, svg {
    display:block;
    max-width:100%
}
a {
    color:inherit;
    text-decoration:none
}
b, strong {
    font-weight:700
}
:focus-visible {
    outline:2px solid var(--ci-focus);
    outline-offset:3px;
    border-radius:4px
}
::selection {
    background:color-mix(in srgb, var(--ci-primary) 24%, rgb(0 0 0 / 0))
}
.wrap {
    width:100%;
    max-width:calc(var(--wrap) + 2 * var(--gutter));
    margin:0 auto;
    padding:0 var(--gutter)
}
.visually-hidden {
    position:absolute!important;
    width:1px;
    height:1px;
    overflow:hidden;
    clip:rect(0 0 0 0);
    white-space:nowrap
}

/* Bilder mit Hell-/Dunkel-Fassung: beide im Markup, CSS zeigt die passende - kein Tausch per JS, kein Aufblitzen. */
.only-dark { display:none!important }
[data-theme=dark] .only-dark { display:block!important }
[data-theme=dark] .only-light { display:none!important }

/* ===== Google Translate: Leiste und Hervorhebung weg (wie nectex) ================================ */
.skiptranslate,
#translationContainer {
    display:none
}
.VIpgJd-ZVi9od-aZ2wEe-OiiCO-ti6hGc, .VIpgJd-suEOdc.VIpgJd-yAWNEb-L7lbkb.skiptranslate, .VIpgJd-yAWNEb-L7lbkb.skiptranslate {
    display:none!important
}
.VIpgJd-yAWNEb-VIpgJd-fmcmS-sn54Q {
    background-color:transparent!important;
    box-shadow:none!important
}

/* ===== Kopfleiste =============================================================================== */
#header {
    position:fixed;
    top:0;
    left:0;
    right:0;
    z-index:1000;
    height:var(--header-height);
    padding-top:env(safe-area-inset-top);
    border-bottom:1px solid transparent;
    transition:background-color .3s ease, border-color .3s ease
}
/* Erst beim Scrollen bekommt die Leiste ihre Flaeche - oben liegt sie frei ueber dem Hero. */
#header.scrolled {
    background:color-mix(in srgb, var(--bg) 78%, rgb(0 0 0 / 0));
    backdrop-filter:var(--surface-blur);
    border-bottom-color:var(--border)
}
.header-inner {
    height:100%;
    display:flex;
    align-items:center;
    gap:32px
}
.header-logo {
    flex:0 0 auto;
    display:flex;
    align-items:center
}
.header-logo img {
    width:172px;
    height:auto
}
.header-nav {
    display:flex;
    gap:4px;
    margin-left:auto
}
.header-nav a {
    padding:8px 14px;
    border-radius:var(--radius-control);
    font-size:15px;
    font-weight:600;
    color:var(--text-secondary);
    transition:background-color .2s ease, color .2s ease
}
.header-nav a:hover {
    background:var(--btn-hover);
    color:var(--text-primary)
}
.header-tools {
    display:flex;
    align-items:center;
    gap:12px
}

/* ----- Sprachmenue (Markup und Verhalten wie nectex) ----- */
/* Gleiche Groesse und Zeilenhoehe wie die Menuepunkte daneben - bei 14px sass die Schriftlinie hoeher. */
#languageSelectorContainer {
    position:relative;
    cursor:pointer;
    font-size:15px;
    line-height:24px;
    font-weight:600
}
#languageSelectorToggle {
    display:flex;
    align-items:center;
    min-height:38px;
    padding:8px 10px;
    border-radius:var(--radius-control);
    color:var(--text-secondary);
    transition:background-color .2s ease
}
#languageSelectorToggle:hover {
    background:var(--btn-hover)
}
#languageSelectorContainer.laedt { cursor:progress }
#languageSelectorContainer.laedt #languageSelectorToggle { opacity:.6 }
.languageSelector {
    display:flex;
    align-items:center;
    gap:10px;
    white-space:nowrap
}
.flag-icon {
    width:18px;
    height:auto;
    flex:0 0 auto;
    border-radius:2px
}
#languageSelectorsMenu {
    display:none;
    position:absolute;
    top:calc(100% + 8px);
    right:0;
    flex-direction:column;
    gap:2px;
    min-width:200px;
    max-height:340px;
    padding:6px;
    overflow-y:auto;
    overflow-x:hidden;
    border-radius:12px;
    background:var(--surface-glas-dicht);
    backdrop-filter:var(--surface-blur);
    border:1px solid var(--border);
    box-shadow:0 12px 34px rgba(0,0,0,.16);
    z-index:10
}
#languageSelectorContainer.open #languageSelectorsMenu {
    display:flex
}
#languageSelectorsMenu .languageSelector {
    padding:9px 10px;
    border-radius:8px;
    color:var(--text-primary)
}
#languageSelectorsMenu .languageSelector:hover {
    background:var(--btn-hover)
}

/* ----- Hell/Dunkel-Schalter (aus nectex: Stern wird zur Sonne, Mond als Maske) ----- */
.themeToggle {
    position:relative;
    display:flex
}
/* Visuell versteckt, aber per Tastatur erreichbar - der Fokusring sitzt am Label. */
#colorThemeToggle {
    position:absolute;
    width:1px;
    height:1px;
    opacity:0;
    margin:0;
    pointer-events:none
}
.toggle-switch {
    position:relative;
    display:block;
    width:60px;
    height:30px;
    border-radius:56px;
    cursor:pointer;
    overflow:hidden;
    background-color:var(--ci-primary);
    background-image:var(--ci-gradient)
}
.toggle-switch:hover {
    background-image:var(--ci-gradient-hover)
}
#colorThemeToggle:focus-visible + label {
    outline:2px solid var(--ci-focus);
    outline-offset:3px
}
#star {
    position:absolute;
    top:8px;
    left:10px;
    width:15px;
    height:15px;
    background-color:#fff;
    transform:scale(1);
    border-radius:50%;
    transition:.3s ease top, .3s ease left, .3s ease transform, .3s ease background-color;
    z-index:1
}
.star {
    top:1px;
    left:-3px;
    font-size:20px;
    line-height:14px;
    color:#fff;
    transition:.3s ease color
}
#star-1 { position:relative }
#star-2 {
    position:absolute;
    transform:rotateZ(36deg)
}
#moon {
    position:absolute;
    bottom:-42px;
    right:8px;
    width:20px;
    height:20px;
    background-color:#fff;
    border-radius:50%;
    transition:.3s ease bottom;
    -webkit-mask-image:radial-gradient(circle 10px at 2px 4px, transparent 96%, #000 100%);
    mask-image:radial-gradient(circle 10px at 2px 4px, transparent 96%, #000 100%)
}
/* Stern und Mond folgen auch dem Attribut am <html> - das setzt das Kopf-Script vor dem ersten Bild, den Haken
   erst style.js (sonst schrumpfte der Stern im Dunkelmodus bei jedem Laden sichtbar zur Sonne). */
:is(#colorThemeToggle:checked, :root[data-theme="dark"] #colorThemeToggle) + label #star {
    top:3px;
    left:29px;
    transform:scale(.3);
    background-color:#ff0
}
:is(#colorThemeToggle:checked, :root[data-theme="dark"] #colorThemeToggle) + label .star {
    color:#ff0
}
:is(#colorThemeToggle:checked, :root[data-theme="dark"] #colorThemeToggle) + label #moon {
    bottom:5px
}

/* ===== Bausteine ================================================================================ */
.section {
    position:relative;
    padding:112px 0
}
/* Zwischen Hero und Referenzen etwas weniger Luft (User 15.10.2026); auf schmalen Schirmen s. unten. */
.hero + .section {
    padding-top:80px
}
.section-head {
    max-width:680px;
    margin-bottom:56px
}
/* Ueberschrift links, Knopf rechts auf Hoehe der letzten Zeile - bricht schmal unter die Ueberschrift. */
.section-head-row {
    display:flex;
    flex-wrap:wrap;
    align-items:flex-end;
    justify-content:space-between;
    gap:24px 40px;
    margin-bottom:56px
}
.section-head-row .section-head {
    margin-bottom:0
}
.eyebrow {
    display:inline-flex;
    align-items:center;
    gap:10px;
    margin-bottom:16px;
    font-size:13px;
    font-weight:800;
    letter-spacing:.14em;
    text-transform:uppercase;
    color:var(--accent-text)
}
.eyebrow::before {
    content:'';
    width:22px;
    height:2px;
    border-radius:2px;
    background:var(--ci-gradient)
}
h1, h2, h3 {
    font-weight:800;
    line-height:1.1;
    letter-spacing:-.02em;
    color:var(--text-primary)
}
.section-head h2 {
    font-size:clamp(32px, 4.4vw, 46px)
}
.section-head p {
    margin-top:18px;
    font-size:18px;
    color:var(--text-tertiary)
}
.gradient-text {
    background:var(--ci-gradient);
    -webkit-background-clip:text;
    background-clip:text;
    color:transparent
}
[data-theme=dark] .gradient-text {
    background:linear-gradient(135deg, color-mix(in srgb, var(--ci-primary) 55%, #fff) 0%, color-mix(in srgb, var(--ci-secondary) 55%, #fff) 80%);
    -webkit-background-clip:text;
    background-clip:text
}

.btn {
    display:inline-flex;
    align-items:center;
    justify-content:center;
    gap:10px;
    height:50px;
    padding:0 24px;
    border:1px solid transparent;
    border-radius:var(--radius-control);
    font:inherit;
    font-size:16px;
    font-weight:700;
    white-space:nowrap;
    cursor:pointer;
    transition:transform .2s ease, box-shadow .2s ease, border-color .2s ease, background-color .2s ease
}
.btn svg {
    width:18px;
    height:18px;
    flex:0 0 auto
}
.btn-primary {
    background-color:var(--ci-primary);
    background-image:var(--ci-gradient);
    color:#fff;
    box-shadow:0 10px 26px -10px color-mix(in srgb, var(--ci-primary) 70%, rgb(0 0 0 / 0))
}
.btn-ghost {
    background:var(--surface-glas);
    backdrop-filter:var(--surface-blur);
    border-color:var(--border-strong);
    color:var(--text-primary)
}
@media (hover: hover) {
    .btn-primary:hover {
        background-image:var(--ci-gradient-hover);
        transform:translateY(-2px);
        box-shadow:0 14px 30px -10px color-mix(in srgb, var(--ci-secondary) 70%, rgb(0 0 0 / 0))
    }
    .btn-ghost:hover {
        border-color:var(--ci-primary);
        transform:translateY(-2px)
    }
}
/* Nunito hat ueber den Buchstaben mehr Luft als darunter - rein mittig gesetzt stand die Schrift in Knoepfen und
   Pillen etwas zu hoch. Verschoben wird nur die Schrift, die Icons daneben sitzen schon mittig.
   Knoepfe: 0.5px setzt die Versalmitte genau auf die Kastenmitte (gemessen 15.10.2026; 1.5px war zu tief, 0 zu hoch). */
.btn .label {
    translate:0 .5px
}
.hero-badge span {
    translate:0 1px
}
.btn[disabled] {
    opacity:.7;
    cursor:progress;
    transform:none
}

.chips {
    display:flex;
    flex-wrap:wrap;
    gap:8px;
    list-style:none
}
.chip {
    /* 10px seitlich: so passen n8n, make und Zapier in der KI-Karte noch in eine Zeile. */
    padding:5.5px 10px 4.5px;
    border-radius:999px;
    background:var(--bg-section);
    border:1px solid var(--border);
    font-size:14px;
    font-weight:600;
    line-height:1.5;
    color:var(--text-secondary)
}

/* Chip mit Produktlogo davor (n8n, make, Zapier ...). */
.chip-logo {
    display:inline-flex;
    align-items:center;
    gap:7px
}
.chip-logo img {
    height:15px;
    width:auto
}

.card {
    position:relative;
    padding:28px;
    border-radius:var(--radius-card);
    background:var(--surface-glas);
    backdrop-filter:var(--surface-blur);
    border:1px solid var(--border);
    transition:transform .25s ease, border-color .25s ease, box-shadow .25s ease
}
@media (hover: hover) {
    .card:hover {
        transform:translateY(-3px);
        border-color:color-mix(in srgb, var(--ci-primary) 45%, var(--border));
        box-shadow:var(--card-shadow-hover)
    }
}

/* Einblenden beim Scrollen - nur mit JS (Klasse js am <html>), sonst bliebe ohne Script alles unsichtbar. */
/* ⚠️ Als Keyframe-Animation, nicht als Uebergang: was beim Laden schon im Bild ist, bekam is-visible noch vor dem
   ersten Zeichnen - der Browser uebersprang den Uebergang, und die Karten standen schon, waehrend der Hero noch
   einblendete. Eine Animation laeuft immer. --start (style.js) setzt solche Elemente hinter den Hero.
   ⚠️ Bewegt wird ueber translate, nicht transform: die Animation haelt ihren Endwert (fill both), und ein
   gehaltenes transform:none schluckte das Anheben der Karten beim Ueberfahren. */
.js .reveal {
    opacity:0
}
.js .reveal.is-visible {
    animation:einblenden .8s cubic-bezier(.2, .7, .2, 1) both;
    animation-delay:calc(var(--d, 0) * 80ms + var(--start, 0ms))
}
@keyframes einblenden {
    from { opacity:0; translate:0 18px }
    to { opacity:1; translate:none }
}
/* Der Hero wartet nicht auf den Beobachter: er steht beim ersten Bild im Fenster und blendet per CSS ein. */
.rise {
    animation:rise .8s cubic-bezier(.2, .7, .2, 1) both;
    animation-delay:calc(var(--d, 0) * 90ms)
}
@keyframes rise {
    from { opacity:0; transform:translateY(18px) }
    to { opacity:1; transform:none }
}

/* ===== Hero ===================================================================================== */
.hero {
    position:relative;
    /* Oben Luft zur Kopfleiste, unten wenig - der Abschnitt darunter bringt seinen eigenen Abstand mit. */
    padding:calc(var(--header-height) + 100px) 0 24px;
    isolation:isolate;
    /* Nur seitlich beschneiden (kein Querscrollen durch den Schein hinter dem Bild). Nach unten darf er auslaufen -
       mit overflow:hidden riss die lila Wolke an der Unterkante des Hero sichtbar ab. */
    overflow-x:clip;
    overflow-y:visible
}
/* Rasterlinien im CI-Ton, zur Mitte hin sichtbar - der Gitter-Hauch von nectex, hier als Quadrate. */
.hero::before,
.zeigerschein {
    content:'';
    position:absolute;
    inset:0;
    z-index:-1;
    background-image:
        linear-gradient(var(--raster-linie) 1px, transparent 1px),
        linear-gradient(90deg, var(--raster-linie) 1px, transparent 1px);
    /* ⚠️ Grundraster und Leuchtlagen muessen deckungsgleich liegen - gleiche Zelle, gleicher Ursprung. */
    background-size:56px 56px;
    background-position:center top;
    pointer-events:none
}
.hero::before {
    --raster-linie:var(--grid-line);
    -webkit-mask-image:radial-gradient(ellipse 75% 65% at 65% 40%, #000 20%, transparent 72%);
    mask-image:radial-gradient(ellipse 75% 65% at 65% 40%, #000 20%, transparent 72%)
}
/* Der Zeiger laesst das Raster aufleuchten (wie auf nectex.io): kein Farbfleck auf der Flaeche, sondern eine zweite
   Lage desselben Rasters in kraeftiger Farbe, die eine Maske auf die Umgebung des Zeigers begrenzt - sichtbar werden
   die Linien. Zwei Lagen, blau und lila, mit gegeneinander versetzten Masken ergeben den Farbwechsel im Schein.
   Die Lagen liegen nicht im Hero, sondern ueber die ganze Seite (User 15.10.2026: Raster ueberall, aber nur am Zeiger;
   ohne Maus bleibt es beim Grundraster im Hero). Der Rumpf und der Hero beginnen beide oben links und sind gleich
   breit - so decken sich die Linien mit dem Grundraster.
   ⚠️ z-index:-1 hinter dem Inhalt: Flaechen mit eigenem Grund verdecken den Schein. Die graue Skills-Flaeche malt ihren
   Grund deshalb als ::before noch eine Ebene tiefer (s. .skills). */
.raster-schein {
    position:absolute;
    inset:0;
    z-index:-1;
    pointer-events:none
}
.zeigerschein {
    opacity:0;
    transition:opacity .45s ease
}
/* Bewusst gedaempft: das Raster soll am Zeiger aufscheinen, nicht leuchten. */
.zeigerschein.an { opacity:.6 }
/* Auf hellem Grund treten die Linien staerker hervor - dort reicht weniger. */
[data-theme=light] .zeigerschein.an { opacity:.45 }
.schein-blau {
    --raster-linie:var(--ci-primary);
    -webkit-mask-image:radial-gradient(300px 260px at calc(var(--zeiger-x, 50%) - 42px) calc(var(--zeiger-y, 50%) - 28px),
        #000 0%, rgba(0,0,0,.55) 40%, transparent 76%);
    mask-image:radial-gradient(300px 260px at calc(var(--zeiger-x, 50%) - 42px) calc(var(--zeiger-y, 50%) - 28px),
        #000 0%, rgba(0,0,0,.55) 40%, transparent 76%)
}
.schein-lila {
    --raster-linie:var(--ci-secondary);
    -webkit-mask-image:radial-gradient(280px 240px at calc(var(--zeiger-x, 50%) + 48px) calc(var(--zeiger-y, 50%) + 32px),
        #000 0%, rgba(0,0,0,.55) 40%, transparent 76%);
    mask-image:radial-gradient(280px 240px at calc(var(--zeiger-x, 50%) + 48px) calc(var(--zeiger-y, 50%) + 32px),
        #000 0%, rgba(0,0,0,.55) 40%, transparent 76%)
}
.hero-grid {
    display:grid;
    grid-template-columns:minmax(0, 1.12fr) minmax(0, .88fr);
    align-items:center;
    gap:72px
}
.hero-badge {
    display:inline-flex;
    align-items:center;
    gap:10px;
    margin-bottom:36px;
    padding:7px 14px 7px 10px;
    border-radius:999px;
    background:var(--surface-glas);
    backdrop-filter:var(--surface-blur);
    border:1px solid var(--border);
    font-size:14px;
    font-weight:700;
    color:var(--text-secondary)
}
.hero-badge svg {
    width:16px;
    height:16px;
    color:var(--accent-text)
}
/* Die Unterschrift ist die Ueberschrift: gross gesetzt, links buendig mit dem Text darunter. Das SVG hat links
   und unten kaum Luft - darum ein kleiner Ausgleich, damit der Strich nicht an der Kante klebt. */
/* Links kein Versatz: das S beginnt am Rand der Grafik und steht so buendig mit dem Text darunter (mit -4px ragte
   es ueber die Textkante, User 15.10.2026). */
.hero-signature {
    margin:-4px 0 36px 0;
    line-height:0
}
.hero-signature img {
    width:clamp(170px, 19vw, 250px);
    height:auto
}
/* Startseite: der Ort steht rechts neben der ganzen Unterschrift, mit deutlichem Abstand, unten buendig mit „Sauer“
   (User 15.10.2026 - unter den Bogen geschoben war zu dicht). Auch auf dem Handy in einer Zeile. Den Abstand nach
   unten traegt die Zeile, nicht mehr Unterschrift oder Pille. */
.hero-kopf {
    display:flex;
    flex-wrap:wrap;
    align-items:flex-end;
    gap:12px 28px;
    margin-bottom:36px
}
.hero-kopf .hero-signature {
    margin:-4px 0 0 0
}
.hero-kopf .hero-badge {
    margin-bottom:0
}
.hero-claim {
    margin-top:18px;
    font-size:clamp(22px, 2.5vw, 30px);
    font-weight:800;
    line-height:1.25;
    letter-spacing:-.015em
}
.hero-lead {
    max-width:560px;
    margin-top:22px;
    font-size:18px;
    color:var(--text-tertiary)
}
.hero-cta {
    display:flex;
    flex-wrap:wrap;
    gap:12px;
    margin-top:36px
}

.portrait {
    position:relative;
    justify-self:end;
    width:100%;
    max-width:440px
}
/* Weicher Schein im CI-Verlauf hinter dem Bild. */
.portrait::before {
    content:'';
    position:absolute;
    inset:10% -8% -6% 12%;
    z-index:-1;
    border-radius:48px;
    background:var(--ci-gradient);
    filter:blur(64px);
    opacity:.28
}
.portrait-frame {
    position:relative;
    aspect-ratio:4 / 5;
    border-radius:28px;
    overflow:hidden;
    border:1px solid var(--border);
    background:var(--bg-surface);
    box-shadow:var(--shadow-default)
}
.portrait-frame img {
    width:100%;
    height:100%;
    object-fit:cover;
    object-position:50% 12%
}
/* ⚠️ Safari schneidet Kinder mit transform (die vergroesserten/verschobenen Bilder) nicht an den runden Ecken ab -
   overflow:hidden allein reicht dort nicht, die Ecken waren auf dem iPhone eckig (User 15.10.2026). Abhilfe: eine
   Maske an den inneren Huellen (Foto, Ebenen) - nicht am Rahmen, dort schnitte sie auch dessen Schatten ab. Radius
   = Rahmenradius minus 1px Rand. */
.portrait-frame {
    isolation:isolate
}
.portrait-frame picture,
.portrait-ebenen {
    display:block;
    position:absolute;
    inset:0;
    border-radius:27px;
    overflow:hidden;
    -webkit-mask-image:-webkit-radial-gradient(white, black)
}
/* 3D (User 15.10.2026): das Bild neigt sich plastisch - am Desktop zur Maus (egal wo sie steht), auf dem Handy
   mit der Geraeteneigung. Ein Glanzlicht folgt, der Schatten wird tiefer, und der freigestellte Oberkoerper bewegt
   sich getrennt vom Hintergrund: die Person wandert mit, der Hintergrund weicht aus (statt das Foto zu zoomen).
   style.js (bildKippen) schaltet das ein: .raum, sobald der Effekt laeuft (Desktop mit Maus sofort; iPhone nach dem
   Tipp aufs Portraet und der Erlaubnis; Android mit dem ersten Neigungswert), .kippt, solange bewegt wird. Es setzt
   auch die Werte am .portrait. Die beiden Ebenen (Hintergrund ohne Person, Person freigestellt) laedt es nach und
   blendet sie ueber das Foto, sobald beide da sind - in Ruhe liegen sie deckungsgleich, man sieht keinen Wechsel.
   Ohne .raum (Touch ohne Neigung, „Bewegung reduzieren“) bleibt das Bild ruhig.
   ⚠️ Geneigt wird der Rahmen, nicht .portrait - dessen transform gehoert der Einblend-Animation (.rise). */
/* Naehere Perspektive: derselbe Winkel wirkt raeumlicher (1100px war dem User zu flach) */
.portrait.raum {
    perspective:800px
}
.portrait.raum .portrait-frame {
    transform:rotateX(var(--kipp-x, 0deg)) rotateY(var(--kipp-y, 0deg));
    transition:transform .7s cubic-bezier(.2, .7, .2, 1), box-shadow .7s ease
}
.portrait-ebenen {
    position:absolute;
    inset:0;
    opacity:0;
    pointer-events:none
}
.portrait-ebenen.bereit {
    opacity:1
}
/* Kein Zoom beim Bewegen (User 15.10.2026): Foto und Ebenen sind dauerhaft um 3,5 % vergroessert - so weit, dass der
   Versatz (style.js, mit der Rahmenbreite verkleinert) am Rand bedeckt bleibt. Beim Bewegen aendert sich nur die
   Lage, nie die Groesse. Auch ohne .raum, sonst zoomte das Foto auf dem Handy beim Einschalten einmal sichtbar. */
.portrait-frame img {
    transform:scale(1.035);
    transition:transform .7s cubic-bezier(.2, .7, .2, 1)
}
.portrait-ebenen img {
    position:absolute;
    inset:0
}
.portrait.kippt .ebene-grund {
    transform:translate3d(var(--grund-x, 0), var(--grund-y, 0), 0) scale(1.035);
    transition:transform .15s ease-out
}
.portrait.kippt .ebene-person {
    transform:translate3d(var(--person-x, 0), var(--person-y, 0), 0) scale(1.035);
    transition:transform .15s ease-out
}
.portrait.raum .portrait-frame::after {
    content:'';
    position:absolute;
    inset:0;
    border-radius:inherit;
    background:radial-gradient(circle at var(--glanz-x, 50%) var(--glanz-y, 30%), rgb(255 255 255 / .22), rgb(255 255 255 / 0) 55%);
    mix-blend-mode:soft-light;
    opacity:0;
    transition:opacity .5s ease;
    pointer-events:none
}
.portrait.kippt .portrait-frame {
    transition:transform .15s ease-out, box-shadow .4s ease;
    box-shadow:0 40px 80px -36px rgb(0 0 0 / .55), 0 18px 36px -24px var(--ci-primary)
}
.portrait.kippt .portrait-frame::after {
    opacity:var(--glanz-staerke, 1)
}

/* ===== Referenzen =============================================================================== */
.ref-grid {
    display:grid;
    grid-template-columns:repeat(3, minmax(0, 1fr));
    gap:20px
}
.ref-card {
    display:flex;
    flex-direction:column
}
.ref-meta {
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:8px 12px;
    margin-bottom:18px;
    font-size:13px;
    font-weight:700;
    color:var(--text-muted)
}
.ref-tag {
    padding:4px 10px 2px;
    border-radius:999px;
    background:color-mix(in srgb, var(--ci-primary) 10%, rgb(0 0 0 / 0));
    color:var(--accent-text)
}
.ref-card h3 {
    font-size:24px
}
.ref-role {
    margin-top:6px;
    font-size:15px;
    font-weight:700;
    color:var(--text-secondary)
}
.ref-text {
    margin-top:14px;
    font-size:15.5px;
    color:var(--text-tertiary);
    flex:1
}
.ref-link {
    display:inline-flex;
    align-items:center;
    gap:6px;
    align-self:flex-start;
    margin-top:22px;
    font-size:15px;
    font-weight:700;
    color:var(--accent-text)
}
.ref-link svg {
    width:15px;
    height:15px;
    transition:transform .2s ease
}
.ref-link:hover svg {
    transform:translate(2px, -2px)
}
/* Die ganze Karte ist klickbar, der Link bleibt das eine fokussierbare Element. */
.ref-link::after {
    content:'';
    position:absolute;
    inset:0;
    border-radius:inherit
}

/* nectex vorneweg: zwei Spalten, Rand im CI-Verlauf. */
.ref-card.featured {
    grid-column:span 2;
    padding:36px;
    border:1px solid transparent;
    background:
        linear-gradient(var(--bg-surface), var(--bg-surface)) padding-box,
        var(--ci-gradient) border-box;
    overflow:hidden
}
.ref-card.featured::before {
    content:'';
    position:absolute;
    right:-80px;
    top:-80px;
    width:280px;
    height:280px;
    border-radius:50%;
    background:var(--ci-gradient);
    filter:blur(70px);
    opacity:.18;
    pointer-events:none
}
/* Logo statt Name - wie bei nectex. Jede Marke bekommt ihre optische Hoehe (--h im Markup); was breiter als die
   Karte waere, schrumpft im Rahmen, ohne sich zu verzerren. */
.ref-logo {
    --band:40px;
    height:var(--h, 30px);
    width:auto;
    max-width:100%;
    object-fit:contain;
    object-position:left center;
    /* Mittig in einem festen Band - so stehen Datum und Rolle in jeder Reihe auf einer Linie. */
    margin:calc((var(--band) - var(--h, 30px)) / 2) 0 calc((var(--band) - var(--h, 30px)) / 2 + 22px)
}
/* SRH: Signet plus "University" in der Machart des Originals. ⚠️ Das "ʃ" reicht unter die Grundlinie - die liegt
   im SVG bei 81 % der Hoehe (Fuss des "h"). Darauf steht die Schrift, Versalhoehe rund ein Drittel des "h". */
.srh-lockup {
    display:flex;
    align-items:flex-end;
    gap:calc(var(--h) * .3);
    width:auto
}
.srh-lockup img {
    height:100%;
    width:auto
}
.srh-lockup span {
    margin-bottom:calc(var(--h) * .19);
    font-size:calc(var(--h) * .4);
    font-weight:800;
    line-height:.72;
    letter-spacing:-.005em;
    color:var(--text-secondary);
    white-space:nowrap
}
.ref-card.featured .ref-logo {
    height:auto;
    width:150px;
    margin:0 0 22px
}
.ref-card.featured .ref-text {
    max-width:520px;
    font-size:17px
}

.clients {
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    gap:24px;
    margin-top:56px;
    padding-top:32px;
    border-top:1px solid var(--border)
}
.clients-label {
    font-size:13px;
    font-weight:800;
    letter-spacing:.12em;
    text-transform:uppercase;
    color:var(--text-muted)
}
/* Laufband nach dem Muster der "Gedanken" auf nectex.io: gleiche Reihen nebeneinander, jede wandert um ihre
   eigene Breite PLUS eine Luecke - sonst entstuende beim Sprung zurueck eine Naht. Die Raender laufen ueber eine
   Maske in die Flaeche aus, statt an einer Kante abzubrechen. */
.client-slider {
    --lauf-luecke:64px;
    --lauf-saum:clamp(28px, 8vw, 120px);
    align-self:stretch;
    overflow:hidden;
    padding:6px 0;
    -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 var(--lauf-saum), #000 calc(100% - var(--lauf-saum)), transparent 100%);
    mask-image:linear-gradient(90deg, transparent 0, #000 var(--lauf-saum), #000 calc(100% - var(--lauf-saum)), transparent 100%)
}
.client-track {
    display:flex;
    gap:var(--lauf-luecke);
    width:max-content
}
.client-logos {
    display:flex;
    align-items:center;
    gap:var(--lauf-luecke);
    flex:0 0 auto;
    list-style:none;
    animation:logos-wandern 55s linear infinite
}
/* Beim Ueberfahren laeuft das Band schneller statt anzuhalten, und es laesst sich von Hand verschieben (Ziehen,
   Wischen, seitliches Scrollen) - beides regelt style.js. Senkrechtes Wischen bleibt beim Scrollen der Seite. */
.client-slider {
    cursor:grab;
    touch-action:pan-y;
    -webkit-user-select:none;
    user-select:none
}
.client-slider.zieht {
    cursor:grabbing
}
/* Mit Skript bewegt style.js das Band selbst (transform an den Reihen) - die CSS-Animation ist nur der Rueckfall. */
.client-slider.lauf-js .client-logos {
    animation:none;
    will-change:transform
}
.client-logos img {
    -webkit-user-drag:none
}
@keyframes logos-wandern {
    from { transform:translateX(0) }
    to { transform:translateX(calc(-100% - var(--lauf-luecke))) }
}
.client-logos li {
    display:flex;
    align-items:center;
    flex:0 0 auto
}
/* Jedes Logo verlinkt auf die Marke. Gezogen wird trotzdem am ganzen Band - ein Klick nach dem Ziehen
   wird in style.js verworfen, damit Verschieben nicht versehentlich eine Seite oeffnet. */
.client-logos a {
    display:flex;
    align-items:center;
    gap:10px;
    color:inherit;
    border-radius:6px;
    -webkit-user-drag:none;
    transition:opacity .2s ease
}
@media (hover: hover) {
    .client-slider:hover .client-logos a { opacity:.7 }
    .client-slider:hover .client-logos a:hover { opacity:1 }
}
.client-logos img {
    height:var(--h, 32px);
    width:auto
}
/* Optischer Ausgleich: Schriftzuege mit hoher Oberlaenge (Jacob & Johannsen) wirken sonst zu hoch in der Reihe. */
.logo-tiefer img {
    translate:0 6px
}
/* Marken, von denen es nur das Signet gibt: Signet plus Name, im Gewicht eines Schriftzugs. */
.client-mark {
    font-size:17px;
    font-weight:600;
    letter-spacing:-.01em;
    color:var(--text-primary)
}
.client-mark img {
    height:28px;
    border-radius:6px
}

/* ===== Skills =================================================================================== */
.skills {
    border-top:1px solid var(--border);
    border-bottom:1px solid var(--border)
}
/* Der graue Grund unter dem leuchtenden Raster statt darueber (s. .raster-schein): z-index -2 im Stapel des Rumpfs,
   der Schein liegt bei -1. ⚠️ .skills selbst darf darum keinen eigenen Stapel bilden (kein z-index, isolation,
   transform, opacity-Animation) - sonst landete der Grund wieder ueber dem Schein. */
.skills::before {
    content:'';
    position:absolute;
    inset:0;
    z-index:-2;
    background:var(--bg-surface);
    pointer-events:none
}
/* Auf der grauen Flaeche heben sich die Karten mit dem Grundton ab, nicht mit Glas. */
.skills .card {
    background:var(--bg);
    backdrop-filter:none
}
.skill-grid {
    display:grid;
    grid-template-columns:repeat(2, minmax(0, 1fr));
    gap:20px
}
.skill-top {
    display:flex;
    /* Badge mittig neben dem Symbol, nicht an dessen Oberkante */
    align-items:center;
    justify-content:space-between;
    gap:16px;
    margin-bottom:22px
}
.skill-top .skill-icon {
    margin-bottom:0
}
.ambassador-badge {
    height:44px;
    width:auto
}
.skill-icon {
    display:flex;
    align-items:center;
    justify-content:center;
    width:48px;
    height:48px;
    margin-bottom:22px;
    border-radius:14px;
    background:var(--ci-gradient);
    color:#fff;
    box-shadow:0 10px 24px -12px var(--ci-primary)
}
.skill-icon svg {
    width:24px;
    height:24px
}
.skill-card h3 {
    font-size:22px
}
.skill-card p {
    margin:10px 0 22px;
    font-size:16px;
    color:var(--text-tertiary)
}
.words {
    margin-top:48px;
    text-align:center;
    font-size:15px;
    font-weight:700;
    color:var(--text-muted)
}
/* Werkzeuge als Laufband unter den drei Worten (User 16.10.2026) - gleiche Mechanik wie das Referenzband
   (.client-slider, style.js laufband). Je Werkzeug Icon + Name; die Icons (Simple Icons) sind schwarz und werden im
   Dunkelmodus umgekehrt. */
.werkzeuge {
    margin-top:44px
}
/* Engere Luecke als bei den Referenzen - die Eintraege sind kleiner; Track, Reihen und Keyframes lesen sie alle */
.werkzeuge .client-slider {
    --lauf-luecke:44px
}
.werkzeug {
    display:inline-flex;
    align-items:center;
    gap:10px;
    font-size:16px;
    font-weight:700;
    white-space:nowrap;
    color:var(--text-secondary)
}
.werkzeug img {
    width:22px;
    height:22px;
    opacity:.85
}
[data-theme=dark] .werkzeug img {
    filter:invert(1)
}
.words strong {
    display:block;
    margin-top:6px;
    font-size:clamp(22px, 3vw, 28px);
    font-weight:800;
    letter-spacing:-.01em;
    color:var(--text-primary)
}

/* ===== Kontakt ================================================================================== */
.contact-grid {
    display:grid;
    grid-template-columns:minmax(0, .85fr) minmax(0, 1.15fr);
    gap:64px;
    align-items:start
}
.contact-intro .section-head {
    margin-bottom:32px
}
.channels {
    display:grid;
    gap:10px;
    list-style:none
}
.channel {
    display:flex;
    align-items:center;
    gap:14px;
    padding:12px 14px;
    border-radius:14px;
    border:1px solid var(--border);
    background:var(--surface-glas);
    transition:border-color .2s ease, transform .2s ease
}
@media (hover: hover) {
    .channel:hover {
        border-color:color-mix(in srgb, var(--ci-primary) 45%, var(--border));
        transform:translateX(3px)
    }
}
.channel-icon {
    display:flex;
    align-items:center;
    justify-content:center;
    flex:0 0 auto;
    width:40px;
    height:40px;
    border-radius:10px;
    background:var(--bg-section);
    color:var(--accent-text)
}
.channel-icon svg {
    width:20px;
    height:20px
}
.channel b {
    display:block;
    font-size:15.5px;
    line-height:1.3
}
.channel small {
    display:block;
    font-size:14px;
    color:var(--text-tertiary)
}

.form-card {
    padding:36px
}
.form-card h3 {
    font-size:22px;
    margin-bottom:6px
}
.form-note {
    margin-bottom:26px;
    font-size:15px;
    color:var(--text-tertiary)
}
.form-row {
    display:grid;
    grid-template-columns:repeat(3, minmax(0, 1fr));
    gap:14px
}
.form-row.two { grid-template-columns:minmax(0, 1fr) minmax(0, 2fr) }
.field {
    display:flex;
    flex-direction:column;
    gap:6px;
    margin-bottom:16px
}
.field label {
    font-size:13.5px;
    font-weight:700;
    color:var(--text-secondary)
}
.form-element {
    width:100%;
    height:48px;
    padding:0 14px;
    border:1px solid var(--border-strong);
    border-radius:var(--radius-control);
    background:var(--bg);
    color:var(--text-primary);
    font:inherit;
    font-size:16px;
    transition:border-color .2s ease, box-shadow .2s ease
}
textarea.form-element {
    height:auto;
    min-height:140px;
    padding:12px 14px;
    resize:vertical;
    line-height:1.5
}
.form-element::placeholder {
    color:var(--text-muted)
}
.form-element:focus {
    outline:none;
    border-color:var(--ci-primary);
    box-shadow:var(--shadow-input-focus)
}
.form-element.invalid {
    border-color:var(--error)
}
/* Autofill: Browser faerben Felder, die sie ausfuellen koennen oder ausgefuellt haben, hellblau bzw. gelb, mit
   schwarzer Schrift - auf dem iPhone standen Vorname, Nachname und E-Mail darum hell im dunklen Formular, auch
   nachdem das Formular nach dem Senden geleert war (User 15.10.2026). Die Regeln fuer :-webkit-autofill griffen dort
   nicht: der Browser faerbt beim Ausfuellen an den Pseudoklassen vorbei. Darum gilt die Abdeckung IMMER: ein
   eingesetzter Schatten in Feldfarbe ueber der ganzen Flaeche und eine feste Schriftfarbe (text-fill-color) - beides
   setzen die Browser beim Ausfuellen nicht, also kann es auch nichts ueberschreiben. */
input.form-element,
textarea.form-element {
    -webkit-text-fill-color:var(--text-primary);
    caret-color:var(--text-primary);
    -webkit-box-shadow:0 0 0 1000px var(--bg) inset;
    box-shadow:0 0 0 1000px var(--bg) inset
}
input.form-element:focus,
textarea.form-element:focus {
    -webkit-box-shadow:0 0 0 1000px var(--bg) inset, var(--shadow-input-focus);
    box-shadow:0 0 0 1000px var(--bg) inset, var(--shadow-input-focus)
}
/* text-fill-color erbt der Platzhalter sonst - er bliebe nicht gedaempft */
.form-element::placeholder {
    -webkit-text-fill-color:var(--text-muted)
}
/* Zusaetzlich fuer Browser, die die Pseudoklasse setzen: deren Hintergrundfarbe gar nicht erst einblenden */
.form-element:-webkit-autofill,
.form-element:-webkit-autofill:hover,
.form-element:-webkit-autofill:focus {
    transition:background-color 100000s ease-out 0s, color 100000s ease-out 0s
}

/* Eigene Auswahlliste statt der Browser-Liste (User 15.10.2026), gebaut von contact.js (auswahlBauen). Das echte
   <select> bleibt unsichtbar darunter - es traegt Wert und Pflichtfeld, das Senden liest es wie bisher. Ohne
   Skript bleibt das normale Select mit eigenem Pfeil (s. .select). */
.select.auswahl-an select {
    position:absolute;
    inset:0;
    opacity:0;
    pointer-events:none
}
.auswahl-knopf {
    display:flex;
    align-items:center;
    padding-right:40px;
    text-align:left;
    cursor:pointer;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis
}
.auswahl-text {
    min-width:0;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap
}
.auswahl-knopf.leer {
    color:var(--text-muted)
}
.select.auswahl-an:has(select.invalid) .auswahl-knopf {
    border-color:var(--error)
}
.select.offen .auswahl-knopf {
    border-color:var(--ci-primary);
    box-shadow:var(--shadow-input-focus)
}
.select::after {
    transition:transform .2s ease
}
.select.offen::after {
    transform:rotate(180deg)
}
.auswahl-liste {
    position:absolute;
    top:calc(100% + 6px);
    left:0;
    right:0;
    /* Am Desktop ist das Anrede-Feld schmal (~140 px) - die Liste darf breiter sein, damit die Zeilen nicht brechen */
    min-width:230px;
    z-index:30;
    max-height:300px;
    overflow-y:auto;
    overscroll-behavior:contain;
    margin:0;
    padding:6px;
    list-style:none;
    border:1px solid var(--border-strong);
    border-radius:12px;
    background:var(--bg-surface);
    box-shadow:var(--shadow-default);
    opacity:0;
    visibility:hidden;
    translate:0 -4px;
    transition:opacity .15s ease, translate .15s ease, visibility 0s linear .15s
}
.select.nach-oben .auswahl-liste {
    top:auto;
    bottom:calc(100% + 6px);
    translate:0 4px
}
.select.offen .auswahl-liste {
    opacity:1;
    visibility:visible;
    translate:none;
    transition:opacity .15s ease, translate .15s ease
}
.auswahl-liste li {
    position:relative;
    padding:10px 36px 10px 12px;
    border-radius:8px;
    font-size:15.5px;
    line-height:1.35;
    color:var(--text-secondary);
    cursor:pointer
}
.auswahl-liste li.aktiv {
    background:color-mix(in srgb, var(--ci-primary) 12%, rgb(0 0 0 / 0));
    color:var(--text-primary)
}
.auswahl-liste li[aria-selected="true"] {
    font-weight:700;
    color:var(--text-primary)
}
/* Haekchen an der gewaehlten Zeile, als Maske in CI-Blau */
.auswahl-liste li[aria-selected="true"]::after {
    content:'';
    position:absolute;
    right:12px;
    top:50%;
    width:14px;
    height:14px;
    margin-top:-7px;
    background:var(--ci-primary);
    -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / contain no-repeat;
    mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / contain no-repeat
}
/* Select ohne Browser-Pfeil; der eigene Pfeil ist eine Maske in Textfarbe und folgt damit dem Thema. */
.select {
    position:relative;
    /* Breite kommt vom Formular, nie vom Text: eine lange Wahl (eigener Knopf wie natives Select) drueckte das
       Formular sonst breiter als den Schirm, und das iPhone zoomte heraus (User 15.10.2026). */
    contain:inline-size;
    min-width:0
}
.select select {
    appearance:none;
    -webkit-appearance:none;
    padding-right:40px;
    cursor:pointer
}
.select select:invalid {
    color:var(--text-muted)
}
.select::after {
    content:'';
    position:absolute;
    right:14px;
    top:50%;
    width:14px;
    height:14px;
    margin-top:-7px;
    background:var(--text-tertiary);
    -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") center / contain no-repeat;
    mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") center / contain no-repeat;
    pointer-events:none
}
.consent {
    display:flex;
    align-items:flex-start;
    gap:12px;
    margin:6px 0 24px;
    font-size:14.5px;
    color:var(--text-tertiary);
    cursor:pointer
}
.consent input {
    flex:0 0 auto;
    width:18px;
    height:18px;
    margin-top:3px;
    accent-color:var(--ci-primary);
    cursor:pointer
}
.consent a {
    color:var(--accent-text);
    font-weight:700
}
.form-actions {
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:16px 20px
}
.form-status {
    font-size:15px;
    font-weight:700;
    line-height:1.4
}
.form-status #thanks {
    color:var(--accent-text)
}
.form-status #confirmation {
    color:var(--text-secondary);
    font-weight:600
}
.form-status .alert {
    color:var(--error)!important;
    font-weight:700!important
}
.form-status a {
    text-decoration:underline
}

/* ===== Fusszeile ================================================================================ */
#footer {
    padding:36px 0 calc(36px + env(safe-area-inset-bottom));
    border-top:1px solid var(--border);
    font-size:14px;
    color:var(--text-tertiary)
}
.footer-inner {
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    justify-content:space-between;
    gap:20px 32px
}
.footer-legal {
    display:flex;
    flex-wrap:wrap;
    gap:6px 22px
}
.footer-legal a:hover {
    color:var(--text-primary)
}
/* Social-Profile wie im Fuss von nectex.io: die Zeichen aus files/social/ liegen als Maske ueber dem Link und
   tragen so seine Textfarbe - grau im Ruhezustand, weiss auf dem CI-Verlauf beim Ueberfahren.
   ⚠️ Jedes Netz braucht seine --netz-Zeile: ohne sie waere die Maske ungueltig und es stuende ein volles Quadrat da. */
.footer-social {
    display:flex;
    flex-wrap:wrap;
    gap:8px
}
.netz {
    display:grid;
    place-items:center;
    width:34px;
    height:34px;
    border-radius:10px;
    border:1px solid var(--border);
    color:var(--text-tertiary);
    background:color-mix(in srgb, var(--bg) 60%, rgb(0 0 0 / 0));
    transition:color .2s ease, border-color .2s ease, background .2s ease, transform .2s ease
}
.netz::before,
.netz-icon::before {
    content:'';
    width:17px;
    height:17px;
    background-color:currentColor;
    -webkit-mask:var(--netz) center / contain no-repeat;
    mask:var(--netz) center / contain no-repeat
}
[data-profil="linkedin"]    { --netz:url(files/social/linkedin-outline.svg) }
[data-profil="facebook"]    { --netz:url(files/social/facebook-outline.svg) }
[data-profil="instagram"]   { --netz:url(files/social/instagram-outline.svg) }
[data-profil="whatsapp"]    { --netz:url(files/social/whatsapp-outline.svg) }
[data-profil="producthunt"] { --netz:url(files/social/producthunt-outline.svg) }
.netz:hover {
    color:#fff;
    border-color:transparent;
    background-image:var(--ci-gradient);
    transform:translateY(-2px)
}
/* In der Kontaktliste dieselben Zeichen, im Kasten der anderen Kanaele. */
.netz-icon::before {
    width:20px;
    height:20px
}

/* ===== Umbrueche ================================================================================ */
@media (max-width:1000px) {
    .hero-grid {
        gap:48px
    }
    .ref-grid {
        grid-template-columns:repeat(2, minmax(0, 1fr))
    }
    /* minmax(0, …): ein langer Inhalt (z. B. die gewaehlte Betreff-Zeile) darf die Spalte nicht ueber den Schirm
       druecken - auf dem iPhone zoomte die Seite dann heraus (User 15.10.2026). */
    .contact-grid {
        grid-template-columns:minmax(0, 1fr);
        gap:40px
    }
}
@media (max-width:820px) {
    :root {
        --header-height:68px
    }
    .header-nav {
        display:none
    }
    .header-tools {
        margin-left:auto
    }
    .hero {
        padding:calc(var(--header-height) + 36px) 0 16px
    }
    /* Das Bild steht oben - auf schmalen Geraeten darum VOR dem Text. */
    .hero-grid {
        grid-template-columns:1fr;
        gap:40px
    }
    /* Links buendig mit dem Text darunter, nicht mittig (User 15.10.2026). */
    .portrait {
        order:-1;
        justify-self:start;
        max-width:380px
    }
    .section {
        padding:80px 0
    }
    .hero + .section {
        padding-top:56px
    }
    .section-head,
    .section-head-row {
        margin-bottom:40px
    }
    .skill-grid {
        grid-template-columns:1fr
    }
}
@media (max-width:640px) {
    /* Seitenrand wie auf groesseren Schirmen - mit 16px stand alles zu dicht am Rand (User 15.10.2026). */
    :root {
        --gutter:24px
    }
    body {
        font-size:16px
    }
    /* Mehr Luft unter Unterschrift und Ort - die Zeile klebte auf dem Handy am Claim (User 15.10.2026). */
    .hero-kopf {
        margin-bottom:52px
    }
    .header-inner {
        gap:12px
    }
    .header-logo img {
        width:148px
    }
    /* Im Kopf nur die Flagge - der Name der Sprache steht im Menue. */
    #languageSelectorMenu {
        display:none
    }
    .ref-grid {
        grid-template-columns:1fr
    }
    .ref-card.featured {
        grid-column:auto;
        padding:28px
    }
    .card,
    .form-card {
        padding:24px
    }
    .form-row,
    .form-row.two {
        grid-template-columns:minmax(0, 1fr);
        gap:0
    }
    .hero-cta .btn {
        flex:1 1 auto
    }
    .footer-inner {
        flex-direction:column;
        align-items:flex-start
    }
}
@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior:auto
    }
    .js .reveal {
        opacity:1
    }
    .js .reveal.is-visible {
        animation:none
    }
    .rise {
        animation:none
    }
    /* Ohne Bewegung: eine stehende, umbrechende Reihe statt Laufband. */
    .client-slider {
        -webkit-mask-image:none;
        mask-image:none
    }
    .client-track {
        width:auto
    }
    .client-logos {
        flex-wrap:wrap;
        flex:1 1 auto;
        gap:22px 40px;
        animation:none
    }
    .client-logos[aria-hidden="true"] {
        display:none
    }
    .client-slider {
        cursor:auto;
        touch-action:auto
    }
    .card,
    .btn,
    .channel {
        transition:none
    }
}

/* ===== Visitenkarte (/vcf/) ===================================================================== */
/* Formular unten buendig mit den Kontakt-Kacheln links - oben stand es frei, unten klaffte eine Luecke. */
.vcf-seite .contact-grid {
    align-items:end
}
.vcf-zwischen {
    margin:48px 0 16px;
    font-weight:700;
    color:var(--text-secondary)
}
.form-card .form-titel {
    font-size:22px;
    margin-bottom:6px
}

/* Zeilenumbruch nur auf breiten Schirmen - schmal bricht der Text von selbst um. */
@media (max-width:820px) {
    br.nur-desktop { display:none }
}

/* Begriffe, die nicht am Bindestrich umbrechen sollen (z. B. "Go-to-Market"). */
.nobr {
    white-space:nowrap
}
