﻿/* Landingpage-spezifisches CSS (Grundgeruest: Sidebar/Rail, Header, Hero).
   Referenzquelle: Konzept/vylife-landingpage.html. Bewusst EIGENE CSS-Variablen
   (--landing-*) statt der App-Fluent-Design-Tokens: die Landingpage ist ein
   eigenstaendiger, anonymer Marketing-Auftritt und soll unabhaengig vom
   Dark/Light-Theme-Zustand der eingeloggten App funktionieren (im Konzept
   ebenfalls ein eigenes :root mit fixen Farben statt Fluent-Tokens). */

:root {
    --landing-accent: #0067c0;
    --landing-accent-dark: #005ba1;
    --landing-accent-soft: #e7f1fc;
    /* Sekundaerfarbe: entspricht dem Lila-Ton am Ende des Farbverlaufs von
       "gebaut mit Claude." (siehe .landing-grad). Eigene Variable, damit die
       Farbe zentral gepflegt wird und bei einem spaeteren Design-/Theme-
       Wechsel konsistent wiederverwendet werden kann statt hartcodiert an
       mehreren Stellen zu stehen. */
    --landing-secondary: #573ca9;
    --landing-secondary-dark: #452f87;
    --landing-secondary-soft: #ede8f7;
    --landing-bg: #f3f3f3;
    --landing-panel: #ffffff;
    --landing-panel-alt: #f7f7f7;
    --landing-border: #e2e2e2;
    --landing-text: #1a1a1a;
    --landing-text-muted: #4a4a4a;
    --landing-text-faint: #7a7a7a;
    --landing-radius: 12px;
    --landing-radius-sm: 6px;
    --landing-radius-pill: 20px;
    /* Zentrale Obergrenze fuer die Content-Breite aller Sections (Hero,
       Feature-Grid, Hub, Technik-Karten usw.). Ohne diese Grenze wuerden
       Wrapper, die nur ueber padding-inline begrenzt sind (kein eigenes
       max-width), auf sehr breiten/hochaufloesenden Bildschirmen (z.B.
       echte 2560px+ CSS-Pixel-Breite bei 100% Skalierung) beliebig weit
       auseinandergezogen. 1180px ist bewusst der bereits an mehreren
       Stellen etablierte Wert (.landing-mockup-wrap, .landing-tech-inner,
       .landing-tech-smoke) und wird hier zentralisiert, damit neue/weitere
       Wrapper (.landing-grid-4, .landing-hub) denselben Wert referenzieren
       statt ihn erneut hart zu codieren. */
    --landing-content-max: 1300px;
}

.landing-body {
    margin: 0;
    padding: 0;
    font-family: 'Segoe UI Variable', 'Segoe UI', system-ui, -apple-system, sans-serif;
    background: var(--landing-bg);
    color: var(--landing-text);
    -webkit-font-smoothing: antialiased;
    /* Landingpage ist bewusst themeunabhaengig (siehe Kommentar oben). Ohne
       eigenes FluentDesignTheme auf diesem Layout bleiben aber global von
       Login/MainLayout gesetzte Fluent-Design-Tokens (z.B. Dark-Mode-Akzent-
       /Vordergrundfarben) nach einer Zwischennavigation ueber /impressum
       bestehen, da FluentDesignTheme diese Tokens nicht scoped, sondern
       global setzt. Dadurch faerbten sich VylifeLogo-Icon UND -Schriftzug
       (nutzen var(--accent-fill-rest)/var(--neutral-foreground-*)) faelschlich
       in der fremden Theme-Farbe. Fix: hier lokal auf feste Landing-Werte
       zurueckgesetzt, unabhaengig vom App-Theme-Zustand. */
    --accent-fill-rest: var(--landing-accent);
    --neutral-foreground-rest: var(--landing-text);
    --neutral-foreground-hint: var(--landing-text-faint);
}

.landing-body a {
    color: var(--landing-accent);
    text-decoration: none;
}

.landing-body button {
    font-family: inherit;
}

.landing-layout {
    display: flex;
    height: 100vh;
    overflow: hidden;
}

/* ===== Sidebar / Rail ===== */
.landing-sidebar {
    width: 272px;
    flex: none;
    display: flex;
    flex-direction: column;
    background: var(--landing-bg);
    padding: 18px 16px;
    /* Optische Feinjustierung: Logo/Nav-Inhalt soll etwas hoeher sitzen, damit
       das Logo mit dem Hamburger-Menue im Header auf gleicher Hoehe ausgerichtet
       ist - daher zusaetzliches padding-top ueber das Basis-Padding hinaus. */
    padding-top: 10px;
    /* Der Footer (Impressum/Datenschutz) sitzt ueber margin-top:auto ganz unten
       im Flex-Container - dieses Basis-padding-bottom bestimmt daher direkt den
       Abstand vom Footer-Text zum unteren Fensterrand. Bewusst deutlich kleiner
       als das Standard-Padding, damit dieser Abstand gleich gross ist wie der
       Abstand zwischen der Trennlinie und dem Text darueber (siehe
       .landing-sidebar-footer-divider margin-bottom). */
    padding-bottom: 0.4rem;
    /* Kontrast-Override fuer den nativen FluentDivider im Footer: der globale
       Fluent-Divider-Token ist auf --landing-bg zu schwach (analog
       --neutral-stroke-divider-rest-Override in app-shell.css). */
    --neutral-stroke-divider-rest: color-mix(in srgb, var(--landing-text) 18%, transparent);
    /* Breite animiert NUR beim Zuklappen (Voll->Rail); die Transition steht
       daher in der .rail-Regel (analog .app-sidebar in app-shell.css). Beim
       Aufklappen (Rail->Voll) gilt diese Basis-Regel ohne Transition -> die
       Sidebar erscheint sofort in voller Breite, Inhalte wandern nicht mit. */
    transition: none;
    overflow: hidden;
}

/* Auf Desktop-Breite existiert kein aufklappbares Off-Canvas-Menue -> kein
   Overlay (analog .app-sidebar-overlay in app-shell.css). */
.landing-sidebar-overlay {
    display: none;
}

/* Rail-Modus (Desktop): schmale, reine Icon-Spalte - analog .app-sidebar.rail
   in app-shell.css. Texte faden aus statt die Sidebar komplett zu verstecken. */
.landing-sidebar.rail {
    width: 60px;
    /* Etwas grosszuegigeres Rail-Padding als die reine Icon-Breite erfordern
       wuerde, damit die Buttons im eingeklappten Zustand nicht direkt am
       Browserfenster-Rand kleben, sondern einen sichtbaren Aussenabstand
       behalten (analog .app-sidebar.rail in app-shell.css, dort 6px auf
       einer insgesamt breiteren Sidebar - hier etwas mehr, da die Landing-
       Sidebar im Vollmodus schmaler ist und der Randabstand sonst zu knapp wirkt). */
    padding-left: 10px;
    padding-right: 10px;
    transition: width 0.2s ease-in-out;
}

/* Unterdrueckt kurzzeitig ALLE Transitions beim Ueberschreiten des Mobile-
   Breakpoints (per JS, siehe suppressSidebarAnimBriefly in app-shell.js) -
   verhindert ein sichtbares kurzes "Aufblitzen" der vollen/offenen Sidebar,
   wenn zwischen Rail/Voll-Regelsatz (Desktop) und Off-Canvas-Regelsatz
   (Mobile) umgeschaltet wird. Analog .app-sidebar.no-anim in app-shell.css. */
.landing-sidebar.no-anim,
.landing-sidebar.no-anim * {
    transition: none !important;
}

.landing-sidebar.rail .vylife-logo-title,
.landing-sidebar.rail .landing-sidebar-footer-text,
.landing-sidebar.rail .landing-sidebar-footer-legal {
    opacity: 0;
    max-width: 0;
    transform: translateX(-6px);
    overflow: hidden;
    white-space: nowrap;
    pointer-events: none;
    transition:
        opacity 0.14s ease-in-out,
        max-width 0.2s ease-in-out,
        transform 0.14s ease-in-out;
}

/* Logo im Rail zentrieren und ohne eigenes Seiten-Padding, damit das
   Icon exakt auf derselben horizontalen Position sitzt wie die zentrierten
   Nav-Icons darunter (analog .app-sidebar.rail .app-sidebar-brand in
   app-shell.css). */
.landing-sidebar.rail .landing-brand {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
}

/* WICHTIG: .vylife-logo setzt intern einen festen gap (siehe
   VylifeLogo.razor.css) zwischen Icon und Titel-Block. Auch wenn der
   Titel-Block im Rail via opacity/max-width ausgeblendet wird, bleibt
   dieser gap als tatsaechlicher Flex-Abstand bestehen - dadurch wird nicht
   das Icon selbst zentriert, sondern "Icon + Gap + Null-Breite-Titel"
   zusammen, was das Icon sichtbar nach links verschiebt. Im Rail-Modus
   daher den gap auf 0 setzen, damit wirklich nur das Icon zentriert wird. */
.landing-sidebar.rail .landing-brand .vylife-logo {
    gap: 0;
}

.landing-sidebar.rail .landing-nav button span {
    opacity: 0;
    max-width: 0;
    transform: translateX(-6px);
    overflow: hidden;
    white-space: nowrap;
    pointer-events: none;
    transition:
        opacity 0.14s ease-in-out,
        max-width 0.2s ease-in-out,
        transform 0.14s ease-in-out;
}

/* Im Rail-Modus wird jeder Nav-Punkt zu einem zentrierten Icon-Button
   (analog .app-sidebar.rail .app-nav .fluent-nav-link in app-shell.css):
   das Icon behaelt exakt seine Groesse (20x20px, siehe .landing-nav button
   svg oben), nur das Padding schrumpft und der Inhalt wird zentriert statt
   linksbuendig, damit das Icon nicht durch das unveraenderte Button-Padding
   zusammengequetscht wirkt. */
.landing-sidebar.rail .landing-nav button {
    justify-content: center;
    padding: 10px 0;
    gap: 0;
}

.landing-sidebar.rail .landing-nav-scrollbar-track {
    right: -10px;
}

.landing-brand {
    display: flex;
    align-items: center;
    /* Kein eigenes linkes Padding mehr: .landing-brand ist wie .landing-nav
       direktes Kind von .landing-sidebar und erbt dessen Seiten-Padding
       (18px 16px). Ein zusaetzliches eigenes padding-left verschob das
       Logo-Icon sichtbar weiter nach rechts als die Nav-Button-Icons, die
       nur das Sidebar-Padding + ihr eigenes Button-padding-left (12px)
       tragen - der Vergleichswert fuer das Logo ist daher exakt 0, nicht
       ein separat berechneter Wert. Rechtes Padding bleibt fuer den
       Abstand zur Sidebar-Kante bestehen. */
    padding: 4px 12px 22px 0;
}

.landing-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.landing-nav::-webkit-scrollbar {
    display: none;
    width: 0 !important;
    height: 0 !important;
}

/* Wrapper fuer den gleitenden Selection-Indicator (analog .app-nav-wrap). */
.landing-nav-wrap {
    position: relative;
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* Gleitender Win11-Selection-Indicator (Positionierung/Animation kommt aus
   app-shell.js, moveToActive - dieselbe Funktion wie in der ERP-Sidebar). */
.landing-nav-indicator {
    position: absolute;
    left: 0;
    width: 3px;
    border-radius: 3px;
    background: var(--landing-accent);
    pointer-events: none;
    z-index: 1;
    visibility: hidden;
}

/* Overlay-Scrollbar der Landing-Navigation (analog .app-nav-scrollbar-track/
   -thumb in app-shell.css, per JS befuellt/positioniert - initNavScrollbar). */
.landing-nav-scrollbar-track {
    position: absolute;
    top: 0;
    right: -16px;
    bottom: 0;
    width: 2px;
    pointer-events: none;
    z-index: 2;
    opacity: 0;
    transition: opacity 0.15s ease;
}
.landing-nav-wrap:hover .landing-nav-scrollbar-track {
    opacity: 1;
}
.landing-nav-scrollbar-thumb {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    border-radius: 2px;
    background-color: color-mix(in srgb, var(--landing-text) 32%, transparent);
}

.landing-nav button {
    all: unset;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 10px 12px;
    border-radius: var(--landing-radius-sm);
    color: var(--landing-text);
    font-size: 15px;
    position: relative;
    cursor: pointer;
    width: 100%;
}

/* Icon darf im Flex-Layout nicht schrumpfen (Basis: analog .app-nav .fluent-nav-link
   svg in app-shell.css, dort mit fester Groesse 22x22px). Ohne flex-shrink:0 UND
   eine feste Groesse quetscht der Flex-Container das Icon im Rail-Modus (schmale
   60px-Spalte, button-Padding bleibt gleich) sichtbar kleiner zusammen, statt es
   in gleicher Groesse zu behalten wie im Vollmodus. */
.landing-nav button svg {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
}

.landing-nav button:hover {
    background: #e7e7e7;
}

.landing-nav button.active {
    background: #e4e4e4;
    font-weight: 600;
}

.landing-sidebar-footer {
    margin-top: auto;
    padding: 0.5rem 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.landing-sidebar-footer-divider {
    margin: 0;
}

.landing-sidebar-footer-brand {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.landing-sidebar-footer-text {
    display: inline-flex;
    align-items: baseline;
    gap: 0.2rem;
    font-size: 11px;
    color: var(--landing-text);
}

.landing-sidebar-footer-legal {
    font-size: 11px;
    color: var(--landing-text-faint);
    align-self: flex-end;
    margin-top: 2px;
}

/* ===== Main / Header ===== */
.landing-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    position: relative;
}

.landing-header {
    flex: none;
    min-height: 64px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
    padding: 12px 32px;
    background: transparent;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 10;
    transition: background-color .25s ease, backdrop-filter .25s ease, box-shadow .25s ease;
}

.landing-header.scrolled {
    background: rgba(243, 243, 243, .8);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
}

/* IconActionButton uebernimmt Ruheflaeche/Hover selbst (analog .app-fluent-header
   in der ERP-Shell) - hier nur der Akzentfarben-Override fuer das Icon, da die
   Landingpage eigene --landing-*-Tokens statt --accent-fill-rest direkt nutzt. */
.landing-menu-btn {
    --accent-fill-rest: var(--landing-accent);
}

/* Sprechblasenform (kein Fenster-Header, keine Kopfzeile) - angelehnt an
   .landing-ticket-bubble weiter unten: abgerundetes Rechteck mit einer
   spitzen Ecke oben links (border-top-left-radius: 2px) und Bot-Avatar
   links. Farben bleiben der bisherige Blau-Lila-Verlauf. Kein Dauerschatten
   (wirkte im Header zu schwer) und keine dauerhaft laufende Bounce-
   Animation mehr. Die Sprechblase selbst bleibt IMMER sichtbar (kein
   Aus-/Einblenden beim Statuswechsel mehr) - nur der Text wird getippt/
   rueckwaerts geloescht. Der Bot-Avatar blendet dagegen mit aus, sobald
   der Text rueckwaerts geloescht wird (.is-hidden auf dem Avatar), und
   ploppt beim naechsten Textstart mit einem kurzen Grow/Shrink-Puls
   wieder auf (.is-popping auf der Blase). Insgesamt etwas kompakter
   (weniger Padding) als die vorherige Variante. */
.landing-status-bubble {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    width: fit-content;
    max-width: 100%;
    height: 32px;
    background: linear-gradient(135deg, var(--landing-accent), var(--landing-secondary));
    border-radius: var(--landing-radius-sm);
    border-top-left-radius: 2px;
    padding: 0 12px 0 6px;
    position: relative;
}

.landing-status-bubble-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 19px;
    height: 19px;
    border-radius: 50%;
    background: rgba(255, 255, 255, .18);
    flex: none;
    opacity: 1;
    transform: scale(1);
    transition: opacity .25s ease, transform .25s ease;
}

.landing-status-bubble-avatar.is-hidden {
    opacity: 0;
    transform: scale(.4);
}

.landing-status-bubble.is-popping .landing-status-bubble-avatar {
    animation: landing-status-badge-pop .35s ease;
}

@keyframes landing-status-badge-pop {
    0% { transform: scale(1); }
    40% { transform: scale(1.35); }
    70% { transform: scale(.9); }
    100% { transform: scale(1); }
}

.landing-status-bubble-text {
    font-size: 12.5px;
    font-weight: 600;
    color: #ffffff;
    white-space: nowrap;
    overflow: hidden;
    position: relative;
}

.landing-status-bubble-text::after {
    content: "";
    display: inline-block;
    width: 1px;
    height: 13px;
    margin-left: 2px;
    background: currentColor;
    vertical-align: -2px;
    animation: landing-status-badge-caret 1s step-end infinite;
}

@keyframes landing-status-badge-caret {
    0%, 100% { opacity: 1; }
    50% { opacity: 0; }
}

.landing-header-spacer {
    flex: 1;
}

.landing-lang-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid #d0d0d0;
    background: #fbfbfb;
    color: var(--landing-text);
    line-height: 1;
    border-radius: var(--landing-radius-sm);
    height: 32px;
    width: 32px;
    padding: 0;
    cursor: pointer;
}

.landing-lang-toggle svg {
    border-radius: 2px;
    display: block;
}

.landing-lang-toggle:hover {
    background: #f1f1f1;
}

/* Natives <a>-Tag statt FluentButton (analog .landing-btn-primary): FluentButton
   rendert seine sichtbare Flaeche/Textfarbe ueber Fluent-Design-Tokens
   (--accent-fill-rest, --neutral-foreground-on-accent-*), die von der global
   aktiven FluentDesignTheme-Instanz (Dark/Light) berechnet werden. Da
   LandingLayout bewusst KEIN eigenes FluentDesignTheme hat (Landingpage soll
   themeunabhaengig funktionieren), blieb nach einer Zwischennavigation ueber
   /impressum (LoginLayout setzt FluentDesignTheme global) die Textfarbe des
   zuletzt aktiven App-Themes (z.B. Dark) haengen -> Button-Text erschien in
   falscher Farbe. Ein natives Element mit fest eingetragenen Farben umgeht
   das komplett, unabhaengig vom App-Theme-Zustand (analog .landing-btn-primary/
   .landing-menu-btn). Groesse 1:1 aus der vorherigen FluentButton-Optik
   uebernommen (32px Hoehe, wie .landing-lang-toggle daneben). Kuenftiger
   Landing-Dark-Modus soll ueber eigene --landing-*-Tokens erfolgen, nicht ueber
   die App-Fluent-Tokens.
   WICHTIG (Textfarbe): `.landing-body a` (weiter oben) setzt `color` ueber
   einen Element+Klasse-Selektor - das ist SPEZIFISCHER als die reine Klasse
   `.landing-demo-btn` und ueberschreibt die weisse Schrift mit der blauen
   Linkfarbe (identischer, bereits an .landing-btn-primary dokumentierter
   Konflikt). Farbe daher zusaetzlich ueber den staerkeren Selektor
   `a.landing-demo-btn` gesetzt. */
a.landing-demo-btn,
a.landing-demo-btn:hover {
    color: #ffffff;
}

.landing-demo-btn {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    height: 32px;
    padding: 0 14px 0 10px;
    border-radius: var(--landing-radius-sm);
    background: var(--landing-accent);
    border: 1px solid var(--landing-accent);
    color: #ffffff;
    font-size: 13px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 0, 0, .03), 0 1px 2px rgba(0, 0, 0, .02);
    transition: background-color .15s ease, border-color .15s ease, transform .2s ease, box-shadow .2s ease;
}

.landing-demo-btn:hover {
    background: var(--landing-accent-dark);
    border-color: var(--landing-accent-dark);
}

.landing-demo-btn:active {
    background: var(--landing-accent-dark);
    border-color: var(--landing-accent-dark);
}

.landing-scroll-area {
    flex: 1;
    min-height: 0;
    overflow: auto;
    height: 100%;
    /* Native Scrollbar ausblenden: der Header liegt "position: absolute" ueber
       der vollen Breite von .landing-main (ohne eigene Scrollbar, siehe oben),
       waehrend der Content hier innerhalb eines overflow:auto-Containers
       liegt. Mit sichtbarer nativer Scrollbar ist dieser Container effektiv
       um die Scrollbar-Breite schmaler als der Header - dadurch sass ein
       rechtsbuendiges Element im Header (z.B. Sprachumschalter) trotz
       identischem padding-right (32px) sichtbar weiter rechts als der
       Content darunter. Ohne sichtbare native Scrollbar faellt dieser
       Breitenunterschied komplett weg (Navigation erfolgt ohnehin primaer
       ueber die Hauptnavigation/Klicks, nicht ueber Scrollbar-Dragging). */
    scrollbar-width: none;
}

.landing-scroll-area::-webkit-scrollbar {
    display: none;
}

/* Jede Section bekommt IDENTISCH exakt die volle Viewport-Hoehe (100dvh)
   und zentriert ihren Inhalt darin vertikal - kurzer Inhalt (z.B. Section 2)
   steht dadurch mittig im Viewport, waehrend eine Section mit deutlich
   laengerem Inhalt (z.B. Section 3) diese Mindesthoehe einfach ueberschreitet
   und dann normal von oben beginnend gerendert wird. KEIN scroll-margin-top
   mehr: da jede Section exakt 100dvh hoch ist, wuerde ein zusaetzlicher
   Versatz dazu fuehren, dass die Section-Oberkante beim Sprung 84px UNTER
   die Viewport-Oberkante rutscht, obwohl die Section bereits 1:1 genauso
   hoch wie der Viewport ist - dadurch ragt sie unten 84px ueber den
   sichtbaren Bereich hinaus und der Trigger-/Snap-Punkt wirkt verschoben.
   Der Header darf den Content trotzdem ueberlappen, da der Inhalt zentriert
   ist und nicht mehr oben an der Section-Kante klebt.

   OBERGRENZE per clamp(): bei sehr hohen Viewports (z.B. echte 1080px+
   CSS-Pixel-Hoehe bei 100% Skalierung, waehrend der eigentliche Content
   unveraendert gleich hoch bleibt) wuerde 100dvh sonst einen unverhaeltnis-
   maessig grossen Leerraum ueber/unter dem zentrierten Content erzeugen.
   clamp(560px, 100dvh, 900px) veraendert dabei NICHTS am Verhalten bei
   normalen/kleineren Viewports (100dvh liegt dort ohnehin unterhalb der
   900px-Obergrenze und wird 1:1 durchgereicht) - erst wenn 100dvh die 900px
   uebersteigt, deckelt clamp() die Section-Hoehe, waehrend der Content ueber
   justify-content:center weiterhin exakt zentriert bleibt. */
.landing-scroll-area > section {
    box-sizing: border-box;
    min-height: clamp(560px, 100dvh, 900px);
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* Symmetrisches vertikales Padding (oben = unten) statt 0. Bei kurzem
       Inhalt aendert sich optisch nichts (bleibt weiterhin exakt mittig,
       nur mit etwas Luft oben/unten statt direkt an den Raendern). Der
       eigentliche Zweck: sobald der Inhalt einer Section (z.B. auf
       kleinen/mobilen Bildschirmen) hoeher als der Viewport wird und daher
       nicht mehr zentriert werden kann, sorgt padding-top garantiert fuer
       einen Mindestabstand zur Section-Oberkante, damit die Ueberschrift
       nicht vom absolut positionierten, transparenten Header (siehe
       .landing-header) verdeckt wird - unabhaengig von der konkreten
       Bildschirmgroesse/-orientierung, da es sich automatisch aus der
       Content-Hoehe ergibt statt an einem festen Breakpoint zu haengen. */
    padding-block: 96px;
}


.landing-hero {
    /* War frueher ein Sonderfall wegen des transparenten, absolut
       positionierten Headers ueber dem Content - seit die Hero-Section
       nur noch Logo/Ueberschrift/CTAs enthaelt (Mockup ist eine eigene
       Section, siehe .landing-mockup-section) sorgt die normale vertikale
       Zentrierung (.landing-scroll-area > section) bereits fuer genug
       Abstand nach oben, kein zusaetzliches padding-top mehr noetig.
       NUR padding-inline setzen (nicht das padding-Shorthand), damit das
       vertikale padding-block der Basisregel (.landing-scroll-area >
       section) erhalten bleibt. */
    padding-inline: 32px;
    text-align: center;
    position: relative;
    overflow: hidden;
}

/* Mockup-Seitenverhaeltnis (frueher hier per Media-Query je Slide gesteuert)
   wird jetzt zentral ueber .landing-mockup-wrap aspect-ratio/max-height
   bestimmt, siehe dort - kein separater Desktop-Override mehr noetig. */

.landing-hero-glow {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate3d(-50%, 0, 0);
    width: 800px;
    height: 420px;
    background: rgba(96, 165, 250, .18);
    border-radius: 50%;
    filter: blur(90px);
    z-index: 0;
    pointer-events: none;
    /* Blur-Filter sind fuer den Browser teuer neu zu berechnen. Ohne
       will-change/eigene Compositing-Ebene fuehrte das dazu, dass der ganze
       (jetzt deutlich groessere, min-height:100vh) Hero-Bereich beim Scrollen
       spuerbar traege/verzoegert reagierte, weil der Blur bei jedem Frame neu
       gezeichnet wurde. will-change zwingt den Browser, das Element auf einer
       eigenen GPU-Ebene zu rendern statt es staendig neu zu rasterisieren. */
    will-change: transform;
}

.landing-hero-inner {
    max-width: 760px;
    margin: 0 auto;
    position: relative;
    z-index: 1;
}

/* ===== Slider-Section (#slider) =====
   Eigenstaendiges Layout, KEIN Nachbau von .landing-stand-grid/.landing-stand-row:
   die Modul-Section hat zwei nebeneinanderliegende, vertikal gestapelte LISTEN
   (Text sitzt als Padding einer einzelnen Listenzeile), waehrend der Slider
   hier EIN Eintrag ist, der horizontal in Text (links) / Bild (rechts)
   aufgeteilt wird - beide Konzepte sind trotz gleicher grid-template-columns
   nicht direkt vergleichbar, ein Uebernehmen der Zeilen-Innenabstaende ergibt
   daher keinen sinnvollen Breitenabgleich. Einzige geteilte Konvention mit
   den anderen Content-Sections ist die AEUSSERE Container-Breite
   (--landing-content-max), damit der Slider nicht breiter/schmaler als der
   Rest der Seite wirkt. Gap/Innenabstand des Text/Bild-Verhaeltnisses sind
   frei und eigenstaendig gewaehlt. */
.landing-slider-grid {
    /* Direkt an --landing-content-max gekoppelt (keine zusaetzliche
       1100px-Deckelung mehr): der Slider soll bei hohen Aufloesungen
       genauso mitwachsen wie alle anderen Content-Sections. */
    max-width: var(--landing-content-max);
    width: 100%;
    margin-inline: auto;
}

/* Bei mittleren Viewport-Breiten (z.B. ~1272px effektive Breite) wirkt das
   quadratische Slider-Bild bei voller 1100px-Breite zu gross/zu hoch fuer
   den sichtbaren Viewport - das Bild ist dann nicht mehr schoen zentriert
   im Contentbereich. Ab dieser Breite abwaerts wird der Slider daher auf
   eine kleinere Maximalbreite begrenzt; oberhalb bleibt die volle 1100px-
   Breite (siehe .landing-slider-grid oben) unveraendert bestehen. */
@media (max-width: 1360px) {
    .landing-slider-grid {
        max-width: 900px;
    }
}

/* Variante 2 (landing-slider-item-wide, Grid-Modifier .landing-slider-grid-wide)
   bekommt UNTER 1360px bewusst volle Breite (100%) statt der 900px-Grenze
   von Variante 1 - ab 1360px aufwaerts bleibt sie aber bei der normalen,
   geteilten --landing-content-max-Breite (siehe .landing-slider-grid oben),
   damit sie sich dort weiterhin konsistent in die Seitenbegrenzung einfuegt. */
@media (max-width: 1360px) {
    .landing-slider-grid.landing-slider-grid-wide {
        max-width: 100%;
    }
}

/* Variante 2 (landing-slider-item-wide) verwendet oberhalb 1360px bewusst
   wieder dieselbe --landing-content-max-Begrenzung wie alle anderen
   Content-Sections (siehe .landing-slider-grid oben) statt einer eigenen
   groesseren Breite - die Seitenbegrenzung soll dort konsistent bleiben,
   auch fuer den Slider. */

.landing-slider-item {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 48px;
    align-items: center;
}

/* Variante 2 (siehe Landingpage.razor, "Slider-Variante 2"): Text nimmt nur
   noch 1/3 der Breite ein, das Bild/Media 2/3 (Verhaeltnis 1fr/2fr statt
   1fr/1fr). Die Section-Hoehe selbst bleibt unveraendert (siehe weiterhin
   #slider.landing-section-panel min-height weiter unten) - nur das
   Breitenverhaeltnis UND das Seitenverhaeltnis des Bildes aendern sich
   (kein Quadrat mehr, sondern ein breiteres Rechteck), damit das Bild bei
   deutlich mehr Breite nicht unnoetig hoch/aufgeblasen wirkt. */
.landing-slider-item.landing-slider-item-wide {
    grid-template-columns: 1fr 2fr;
}

.landing-slider-item.landing-slider-item-wide .landing-slider-media {
    aspect-ratio: 16 / 10;
}

/* Screenshots in Variante 2 haben ein anderes Seitenverhaeltnis als der
   16:10-Rahmen und wuerden mit object-fit:cover (siehe .landing-slider-media
   img weiter unten) rechts abgeschnitten. Hier daher bewusst object-fit:
   contain statt cover: das komplette Bild bleibt sichtbar, der Rahmen selbst
   (Groesse/Seitenverhaeltnis der Box) bleibt unveraendert - es entsteht ggf.
   Leerraum oben/unten bzw. seitlich statt eines Zuschnitts. Die Platzhalter-
   farbe fuer diesen Leerraum kommt vom .landing-slider-media-Container
   selbst (siehe unten), nicht mehr vom img direkt. */
.landing-slider-item.landing-slider-item-wide .landing-slider-media img {
    object-fit: contain;
    object-position: center;
    position: absolute;
    top: 34px;
    left: 0;
    width: 100%;
    height: calc(100% - 34px);
}

.landing-slider-text h3 {
    margin: 0 0 12px;
    font-size: clamp(22px, 2.4vw, 26px);
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.35;
    background: linear-gradient(90deg, var(--landing-accent), var(--landing-secondary));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

.landing-slider-text p {
    margin: 0;
    font-size: 15.5px;
    line-height: 1.6;
    color: var(--landing-text-muted);
}

.landing-slider-media {
    width: 100%;
    aspect-ratio: 1 / 1;
    overflow: hidden;
    border-radius: var(--landing-radius);
    box-shadow: 0 1px 2px rgba(0, 0, 0, .09), 0 8px 20px rgba(0, 0, 0, .08);
    position: relative;
    /* Platzhalterfarbe fuer eventuellen Leerraum bei object-fit:contain
       (siehe .landing-slider-item-wide .landing-slider-media img oben) -
       lila Akzentton (--landing-secondary) statt neutralem Grau, damit der
       Leerraum zur Marke passt statt als "Fehlstelle" zu wirken. Gilt fuer
       beide Slider-Varianten (nur bei cover/Variante 1 unsichtbar, da dort
       kein Leerraum entsteht). */
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--landing-secondary) 22%, transparent),
        color-mix(in srgb, var(--landing-accent) 18%, transparent));
}

/* "Fenstersteuerelemente"-Leiste (nur Variante 2, siehe Markup in
   Landingpage.razor): drei Punkte oben links wie bei einem Browser-/App-
   Fensterrahmen, damit der Screenshot wie in einem Fenster wirkt statt
   freischwebend im Bildfeld zu stehen. Bewusst absolut positioniert statt
   den Bild-Container per flex umzustrukturieren, damit Variante 1 (ohne
   Titelleiste im Markup) unveraendert bleibt. */
.landing-slider-media-titlebar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 34px;
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 0 14px;
    background: color-mix(in srgb, var(--landing-secondary) 55%, #1a1330 45%);
    z-index: 1;
}

.landing-slider-media-dot {
    width: 10px;
    height: 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .55);
}

.landing-slider-media img {
    display: block;
    width: 100%;
    height: 100%;
    /* Screenshots haben unterschiedliche Seitenverhaeltnisse (siehe
       Vylife-ERP.Shared/wwwroot/images/landing/slider-*.png) und werden
       daher passgenau ab der oberen linken Ecke in das quadratische
       Slider-Feld eingepasst statt zentriert zugeschnitten. */
    object-fit: cover;
    object-position: top left;
}

/* 3-Dots-Steuerung sitzt bewusst IN der Text-Spalte (nicht unter dem Bild),
   damit sie mit demselben "reveal"/Blop-Timing wie der Text einblendet. */
.landing-slider-dots {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 28px;
}

.landing-slider-dot {
    width: 10px;
    height: 10px;
    padding: 0;
    border: none;
    border-radius: 999px;
    background: color-mix(in srgb, var(--landing-secondary) 30%, transparent);
    cursor: pointer;
    transition: background .2s ease, transform .2s ease;
}

.landing-slider-dot:hover {
    background: color-mix(in srgb, var(--landing-secondary) 55%, transparent);
}

.landing-slider-dot.active {
    background: var(--landing-secondary);
    transform: scale(1.35);
}

/* "Blop"-Einblendeffekt: leichtes Ueberschwingen (scale > 1 -> 1) statt
   reinem Fade, per @key in Landingpage.razor erzeugt Blazor bei jedem
   Slide-Wechsel ein frisches DOM-Element - die Animation spielt dadurch
   garantiert von vorne. Das Bild bekommt eine kleine animation-delay, damit
   es sichtbar NACH dem Text einblendet (zeitversetzt). */
@keyframes landing-slider-pop {
    0% {
        opacity: 0;
        transform: scale(.92);
    }

    60% {
        opacity: 1;
        transform: scale(1.03);
    }

    100% {
        opacity: 1;
        transform: scale(1);
    }
}

.landing-slider-pop {
    animation: landing-slider-pop .5s cubic-bezier(.34, 1.56, .64, 1) both;
}

.landing-slider-media.landing-slider-pop {
    animation-delay: .12s;
}

/* #slider ist inhaltlich deutlich kompakter (Text + ein quadratisches Bild)
   als die uebrigen "ein Bildschirm pro Section"-Bereiche. Nur die UNTERE
   Mindesthoehe ist daher niedriger als bei den anderen Sections (reduziert
   Leerraum auf kleinen/normalen Viewports). Die OBERE Grenze (900px) und die
   dvh-Basis (100dvh) sind bewusst IDENTISCH zu ".landing-scroll-area > section"
   uebernommen: mit einem niedrigeren Deckel (vorher 70dvh/700px) wurde die
   Section bei sehr hohen effektiven Aufloesungen (z.B. 4K bei 225% Skalierung)
   kuerzer als der sichtbare Viewport - beim Scrollen blieb sie dadurch oben
   ausgerichtet statt wie alle anderen Sections den kompletten Viewport zu
   fuellen und ihren Inhalt darin zu zentrieren. */
#slider.landing-section-panel {
    min-height: clamp(420px, 100dvh, 900px);
}

@media (max-width: 820px) {
    .landing-slider-item {
        grid-template-columns: 1fr;
    }

    .landing-slider-media {
        /* Bewusst ueber width statt max-height begrenzen: width:100% +
           aspect-ratio:1/1 wuerden bei einem max-height-Deckel sonst auch
           in der Breite zusammengezwungen (die Hoehenbegrenzung wirkt via
           aspect-ratio automatisch auf die Breite zurueck), wodurch das
           Bild schmaler als der verfuegbare Platz und optisch nicht
           zentriert wirkt. margin-inline:auto zentriert das quadratische
           Bild innerhalb der vollen Spaltenbreite. */
        width: min(100%, min(70vh, 480px));
        max-width: 100%;
        margin-inline: auto;
    }

    /* Variante 2 (landing-slider-item-wide) hat eine hoehere CSS-
       Spezifitaet als die generische .landing-slider-item-Regel oben und
       wuerde daher trotz Media Query weiterhin die 1fr-2fr-Spalten behalten
       - hier deshalb explizit auf eine Spalte umbrechen (wie Variante 1).
       Das Breiten-/Hoehenverhaeltnis des Bildes selbst bleibt dabei
       unangetastet (aspect-ratio:16/10 aus der Basisregel oben bleibt
       aktiv), nur die generische quadratische 70vh/480px-Breitenbegrenzung
       passt nicht zum breiteren 16:10-Format und wird daher fuer diese
       Variante auf die volle Spaltenbreite zurueckgesetzt. */
    .landing-slider-item.landing-slider-item-wide {
        grid-template-columns: 1fr;
    }

    .landing-slider-item.landing-slider-item-wide .landing-slider-media {
        width: 100%;
        max-width: 100%;
    }
}

.landing-hero-logo {
    display: flex;
    justify-content: center;
    margin-bottom: 52px;
}

/* Logo skaliert im selben Verhaeltnis wie .landing-hero-title (44px -> 32px
   am Breakpoint 820px, siehe @media max-width:820px weiter unten): 32/44 =
   0.727, also derselbe Faktor wie fuer die Icon-Groesse (80px -> ~58px).
   Dadurch bleibt das Verhaeltnis Logo/Ueberschrift konstant, statt dass sich
   nur die Ueberschrift verkleinert und das Logo stehen bleibt. !important
   ist noetig, da die Komponente die Groesse per Inline-Style (IconSize-
   Parameter) setzt, was sonst gegenueber jeder externen Stylesheet-Regel
   ohne !important gewinnt. */
.landing-hero-logo .vylife-logo {
    --vylife-logo-size: 80px !important;
}

.landing-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: #fbfbfb;
    border: 1px solid #d9d9d9;
    border-radius: var(--landing-radius-pill);
    padding: 6px 14px;
    font-size: 13px;
    font-weight: 600;
    color: var(--landing-text-muted);
    margin-bottom: 22px;
}

.landing-pill-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--landing-accent);
    display: inline-block;
    position: relative;
}

.landing-pill-dot::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: var(--landing-accent);
    opacity: .6;
    animation: landing-pill-ping 1.8s cubic-bezier(0, 0, .2, 1) infinite;
}

@keyframes landing-pill-ping {
    0% { transform: scale(1); opacity: .6; }
    100% { transform: scale(2.4); opacity: 0; }
}

.landing-hero-title {
    font-size: 44px;
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.15;
    margin: 0 0 20px;
}

.landing-grad {
    background: linear-gradient(90deg, var(--landing-accent), var(--landing-secondary));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

.landing-hero-lead {
    font-size: 17px;
    color: var(--landing-text-muted);
    line-height: 1.6;
    margin: 0 0 32px;
}

.landing-hero-ctas {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    flex-wrap: wrap;
}

.landing-btn-primary,
.landing-btn-secondary {
    font-size: 15px;
    font-weight: 600;
}

/* Beide Hero-CTAs sind jetzt native Elemente (<a>/<button>) statt FluentButton:
   FluentButton rendert seine sichtbare Flaeche als ::part(control) im
   Shadow-DOM, was zusaetzlich zur Host-Box einen sichtbaren "Abkantungs"-
   Effekt (doppelte Kante/Rand) erzeugte. Native Elemente geben hier volle,
   einfache CSS-Kontrolle uber Flaeche/Rahmen/Hover ohne Shadow-DOM-Umweg.
   WICHTIG (Textfarbe): `.landing-body a` (weiter oben) setzt `color` ueber
   einen Element+Klasse-Selektor - das ist SPEZIFISCHER als die reine Klasse
   `.landing-btn-primary` und ueberschrieb die weisse Schrift wieder mit der
   blauen Linkfarbe (analog zum bereits dokumentierten Konflikt bei
   .landing-demo-btn). Farbe/Border-Farbe daher hier zusaetzlich ueber den
   staerkeren Selektor `a.landing-btn-primary` gesetzt. */
a.landing-btn-primary,
a.landing-btn-secondary {
    color: #ffffff;
}

/* Uebergreifender Verlauf: jeder Button bekommt selbst einen Gradient von
   seiner "eigenen" Farbe zu einer Mischfarbe Richtung des jeweils anderen
   Buttons - dadurch wirkt der Verlauf ueber beide Buttons hinweg optisch
   fortlaufend, auch mit sichtbarem Abstand (gap) dazwischen. Auf Desktop
   (nebeneinander) horizontal (90deg), in der mobilen gestapelten Ansicht
   (siehe Media-Query weiter unten) vertikal (180deg). */
.landing-btn-primary {
    box-sizing: border-box;
    height: 48px;
    /* Symmetrisches Icon-Padding wie bei den App-internen Buttons:
       Abstand linke Kante -> Icon ist genauso gross wie der Abstand
       Icon -> Text (12px), der Text bekommt rechts mehr Raum (22px). */
    padding: 0 22px 0 12px;
    display: inline-flex;
    align-items: center;
    gap: 12px;
    border-radius: var(--landing-radius-sm);
    cursor: pointer;
    background: linear-gradient(90deg, var(--landing-accent), color-mix(in srgb, var(--landing-accent) 55%, var(--landing-secondary)));
    border: none;
    color: #ffffff;
    /* Hover-Effekt (Anheben + Schatten): identisch zu .landing-feature-card:hover
       (gleiche Transition-Dauer/Easing und gleicher neutraler Schatten statt
       eines farbigen Glows), damit ALLE interaktiven Elemente der Landingpage
       (ausser Hauptnavigation) konsistent reagieren. */
    box-shadow: 0 1px 2px rgba(0, 0, 0, .09), 0 8px 20px rgba(0, 0, 0, .08);
    transition:
        background-color 0.15s ease-in-out,
        transform .2s ease,
        box-shadow .2s ease;
}

.landing-btn-primary:hover {
    background: linear-gradient(90deg, var(--landing-accent-dark), color-mix(in srgb, var(--landing-accent-dark) 55%, var(--landing-secondary-dark)));
    transform: translateY(-2px);
    box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 14px 32px rgba(0, 0, 0, .14);
}

.landing-btn-primary:active {
    transform: translateY(0);
    box-shadow: 0 4px 10px -4px color-mix(in srgb, var(--landing-accent) 55%, transparent);
}

.landing-btn-secondary {
    box-sizing: border-box;
    height: 48px;
    padding: 0 22px 0 12px;
    display: inline-flex;
    align-items: center;
    gap: 12px;
    border-radius: var(--landing-radius-sm);
    cursor: pointer;
    background: linear-gradient(90deg, color-mix(in srgb, var(--landing-secondary) 55%, var(--landing-accent)), var(--landing-secondary));
    border: none;
    color: #ffffff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .09), 0 8px 20px rgba(0, 0, 0, .08);
    transition:
        background-color 0.15s ease-in-out,
        transform .2s ease,
        box-shadow .2s ease;
}

.landing-btn-secondary:hover {
    background: linear-gradient(90deg, color-mix(in srgb, var(--landing-secondary-dark) 55%, var(--landing-accent-dark)), var(--landing-secondary-dark));
    transform: translateY(-2px);
    box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 14px 32px rgba(0, 0, 0, .14);
}

.landing-btn-secondary:active {
    transform: translateY(0);
    box-shadow: 0 4px 10px -4px color-mix(in srgb, var(--landing-secondary) 55%, transparent);
}

/* ===== Content-Sections mit Feature-Grid (Konzept: #entstehung u.a.) =====
   Gleicher Hintergrund wie der Hero/Body (--landing-bg), damit beim
   Scrollen kein sichtbarer Farbbruch zwischen den Sections entsteht.
   Horizontales Padding analog zu .landing-hero (32px), damit Intro-Text und
   Feature-Grid nicht bis an den Bildschirmrand gestreckt werden. Kein
   vertikales Padding - die Section ist ohnehin genauso hoch wie der
   Viewport (min-height:100dvh) und zentriert ihren Inhalt darin (siehe
   Kommentar bei .landing-scroll-area > section). */
.landing-section-panel {
    background: var(--landing-bg);
    padding-inline: 32px;
}

.landing-section-intro {
    max-width: 640px;
    margin: 0 auto 40px;
    text-align: center;
}

.landing-section-intro h2 {
    margin: 0 0 12px;
    font-size: clamp(26px, 3vw, 32px);
    font-weight: 700;
    letter-spacing: -0.01em;
    /* background-clip:text malt den Gradient nur innerhalb der Line-Box
       (bestimmt durch line-height). Ober-/Unterlaengen der Schrift (z.B. "G",
       "y"), die bei diesem font-weight/font-size ueber eine zu knappe Line-Box
       hinausragen, bekommen dann keinen Gradient mehr und wirken abgeschnitten
       - anders als bei normalem color:, das Glyphen unabhaengig von der
       Line-Box vollstaendig zeichnet. Ausreichend grosszuegiges line-height
       schafft genug Box-Hoehe, damit der Gradient die vollen Glyphen deckt. */
    line-height: 1.45;
    background: linear-gradient(90deg, var(--landing-accent), var(--landing-secondary));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

.landing-section-sub {
    margin: 0;
    font-size: 16.5px;
    color: var(--landing-text-muted);
    line-height: 1.5;
}

.landing-grid-4 {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 20px;
    max-width: var(--landing-content-max);
    margin-inline: auto;
}

@media (max-width: 980px) {
    .landing-grid-4 { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
    .landing-grid-4 { grid-template-columns: 1fr; }
}

.landing-feature-card {
    background: var(--landing-panel);
    border: 1px solid rgba(0, 0, 0, .05);
    border-radius: 12px;
    /* Deutlichere, schaerfer abgesetzte Schattenkante als vorher (vorher fast
       unsichtbar bei nur .03/.02 Deckkraft): staerkerer, engerer Schlagschatten
       direkt an der Kante (2px Blur) plus weicherer, groesserer Schatten
       darunter fuer Tiefe. */
    box-shadow: 0 1px 2px rgba(0, 0, 0, .09), 0 8px 20px rgba(0, 0, 0, .08);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transition: transform .2s ease, box-shadow .2s ease;
}

.landing-feature-card:hover {
    /* !important noetig: .reveal.visible (siehe weiter unten, Abschnitt
       "Scroll-Reveal") setzt "transform: none" mit derselben Spezifitaet
       (2 Klassen) und steht in der Datei SPAETER als diese Regel - bei
       gleicher Spezifitaet gewinnt sonst die spaeter definierte Regel,
       wodurch der Hover-Lift-Effekt fuer bereits eingeblendete Karten
       (die zusaetzlich zu .landing-feature-card auch .reveal.visible tragen)
       komplett wirkungslos blieb, obwohl im Konzept (vylife-landingpage.html)
       derselbe Hover-Effekt sichtbar funktioniert. */
    transform: translateY(-2px) !important;
    box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 14px 32px rgba(0, 0, 0, .14) !important;
}

/* Kopfbereich: eigenstaendiges, farbiges Band (analog .landing-ticket-top)
   statt Icon/Titel direkt im Karten-Padding - Icon und Titel erscheinen
   dadurch in Weiss auf dem Farbverlauf. */
.landing-feature-card-header {
    display: flex;
    align-items: center;
    gap: 12px;
    /* Seitliches Padding an .landing-ticket-top (Chat-/Ticket-Box oben in
       #ki-funktionen) angeglichen (14px statt vorher 24px) - oben/unten
       bleibt unveraendert bei 14px. */
    padding: 14px 14px;
    background: linear-gradient(90deg, var(--landing-accent), var(--landing-secondary));
}

/* FluentIcon rendert direkt als <svg>, das per default inline/vertical-align:
   baseline gesetzt ist - dadurch wirkt es gegenueber dem Titeltext leicht
   vertikal versetzt, obwohl beide Flex-Items ueber align-items:center
   eigentlich mittig ausgerichtet werden sollen. display:block entfernt den
   Inline-Baseline-Bezug; width/height explizit gleich gesetzt (das Icon
   bringt inline nur "width" mit, "height" bleibt sonst dem Default-SVG-
   Verhalten ueberlassen), damit die Flex-Zentrierung das Icon exakt auf
   Titelhoehe mittig ausrichtet statt es leicht zu versetzen. */
.landing-feature-card-header svg {
    display: block;
    width: 24px;
    height: 24px;
    flex-shrink: 0;
}

.landing-feature-card-header h3 {
    /* margin:0 wichtig: die generische .landing-feature-card h3-Regel weiter
       unten hatte frueher noch eine eigene margin-bottom (Rest aus dem alten
       Kartenmuster ohne Kopfbereich) und dieselbe Selektor-Spezifitaet (1
       Klasse + Element) - je nach Regelreihenfolge konnte das die hier
       gewuenschte margin:0 wieder ueberschreiben. Die alte, jetzt ungenutzte
       .landing-feature-card h3-Regel wurde deshalb komplett entfernt. */
    margin: 0;
    /* Kleinerer Schriftgrad, damit alle Kopfzeilen-Ueberschriften einzeilig
       bleiben statt umzubrechen. */
    font-size: 15px;
    font-weight: 600;
    line-height: 1.3;
    color: #fff;
}

.landing-feature-card-body {
    /* Seitliches Padding ebenfalls an .landing-ticket-top/.landing-ticket-body
       angeglichen (14px statt vorher 24px), oben/unten bleibt bei 24px. */
    padding: 24px 14px;
    flex: 1;
    display: flex;
}

.landing-feature-card p {
    margin: 0;
    font-size: 14px;
    color: var(--landing-text-muted);
    line-height: 1.55;
    flex: 1;
}

/* ===== "Geplante Module" (#stand): zwei nebeneinander liegende row-lists
   im Windows-11-Zeilen-Stil der App (siehe Win11Row/Win11BarList), mit
   echter GRID-LUECKE zwischen den beiden Spalten (keine gemeinsame Box).
   Icon bleibt ein reines, farbiges Icon (keine Sticker-/Badge-Flaeche) -
   Groesse/Zeilenhoehe an Win11Row.razor.css angelehnt (Icon 24px, Zeile
   padding 12px 16px). Stagger-Animation: jede Zeile ist ein eigenes
   .reveal-Element mit aufsteigendem transition-delay (siehe Markup in
   Landingpage.razor), analog zum Konzept-Prototyp (.row-item mit
   transition-delay je Eintrag). */
.landing-stand-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: var(--landing-content-max);
    margin-inline: auto;
}

/* #stand ist bewusst OHNE eigenes overflow:hidden/position mehr - der neue
   Rauch-Cluster (.landing-tech-smoke, siehe weiter unten bei #technik) liegt
   als eigenstaendiges Element NACH #stand im DOM und ragt per negativem
   top-Wert optisch nach oben in diese Section hinein (1:1 wie im Konzept-
   Prototyp: section#stand hat dort ebenfalls keine eigene Overflow-Regel). */

.landing-stand-col {
    background: rgba(255, 255, 255, .5);
    border: 1px solid rgba(255, 255, 255, .4);
    border-radius: var(--landing-radius);
    box-shadow: 0 4px 12px rgba(0, 0, 0, .03), 0 1px 2px rgba(0, 0, 0, .02);
    overflow: hidden;
    backdrop-filter: blur(20px) saturate(160%);
    -webkit-backdrop-filter: blur(20px) saturate(160%);
}

.landing-stand-row {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 16px;
    min-height: 20px;
    border-bottom: 1px solid rgba(0, 0, 0, .06);
    transition: background .15s ease;
}

.landing-stand-col .landing-stand-row:last-child {
    border-bottom: none;
}

.landing-stand-row:hover {
    background: rgba(255, 255, 255, .5);
}

.landing-stand-row svg {
    display: block;
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    color: var(--landing-accent);
}

.landing-stand-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.landing-stand-text h3 {
    margin: 0;
    font-size: 14px;
    line-height: 20px;
    font-weight: 700;
    color: var(--landing-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.landing-stand-text p {
    margin: 0;
    font-size: 13px;
    line-height: 20px;
    font-weight: 400;
    color: var(--landing-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

@media (max-width: 640px) {
    .landing-stand-grid { grid-template-columns: 1fr; }
}@media (max-width: 640px) {
    .landing-stand-grid { grid-template-columns: 1fr; }
    .landing-stand-row:nth-child(even) { border-left: none; }
}

/* ===== Technischer Aufbau (#technik): full-bleed Akzent-Band, 1:1 aus
   Konzept/vylife-landingpage-neu.html uebernommen (.tech-wrap/.tech-smoke/
   .tech-band/.tech-fill). #technik (.landing-tech-wrap) ist wie jede andere
   Section ein direktes Kind von .landing-scroll-area (siehe
   ".landing-scroll-area > section" weiter oben) und bekommt dadurch
   automatisch dieselbe volle Viewport-Hoehe (100dvh) + vertikale
   Zentrierung wie #stand/#entstehung/etc. Innerhalb der Section ist
   .landing-tech-smoke (Rauch-Cluster) ein GESCHWISTER-Element VOR
   .landing-tech-band (dem eigentlichen Glas-Panel) - nicht dessen Kind.
   Das ist entscheidend: backdrop-filter verwischt nur das, was HINTER dem
   eigenen Element im Malvorgang liegt (vorherige Geschwister), nie die
   eigenen Kinder. Nur als vorangestelltes Geschwister scheint der Rauch
   durch das halbtransparente weisse Acryl-Glas von .landing-tech-band
   hindurch und wirkt an der oberen Bandkante sichtbar verschwommen - exakt
   der Effekt aus dem Original. Farben ueber die bestehenden
   Landingpage-Tokens (--landing-accent/-secondary) statt fixer Hex-Werte
   wie im Original. */
section.landing-tech-wrap {
    position: relative;
    isolation: isolate;
    /* Die generische Basisregel ".landing-scroll-area > section" setzt
       padding-block:96px auf JEDE Section - bei allen anderen Sections ist
       das ok, weil dort kein flaechendeckender Hintergrund existiert. Hier
       wuerde es aber oben/unten eine Luecke OHNE jeden Acryl-Hintergrund
       erzeugen, bevor .landing-tech-band ueberhaupt beginnt. Der noetige
       Innenabstand steckt stattdessen bereits in .landing-tech-band selbst
       (padding: 64px 40px), daher hier bewusst auf 0 zurueckgesetzt, damit
       das Acryl-Panel wirklich die komplette Section lueckenlos ausfuellt.
       WICHTIG: der Selektor braucht den vorangestellten Element-Teil
       "section", da ".landing-scroll-area > section" sonst durch den
       zusaetzlichen Element-Selektor eine HOEHERE CSS-Spezifitaet (0,1,1)
       als ein reiner Klassenselektor ".landing-tech-wrap" (0,1,0) haette und
       padding-block:0 dadurch nie greifen wuerde - das war die Ursache des
       sichtbaren weissen Rands am unteren (und oberen) Section-Ende. */
    padding-block: 0;
}

.landing-tech-band {
    /* Im Original war .tech-band ein kompaktes, nur content-hohes Banner
       (keine eigene 100dvh-Section). Bei uns ist .landing-tech-wrap aber
       eine ganz normale volle Section (".landing-scroll-area > section"
       macht sie zu einer 100dvh-Flex-Column mit justify-content:center).
       Ohne flex:1 waere .landing-tech-band nur so hoch wie sein Inhalt und
       oben/unten bliebe innerhalb der Section eine Luecke OHNE Acryl-
       Hintergrund, in der die normale Seitenflaeche durchscheint - flex:1
       streckt das Glas-Panel auf die komplette verfuegbare Hoehe unserer
       Section, damit die Acrylflaeche die Section wirklich lueckenlos
       fuellt (der Inhalt bleibt ueber .landing-tech-inner weiterhin
       vertikal zentriert). */
    flex: 1 1 auto;
    width: 100%;
    display: flex;
    align-items: center;
    position: relative;
    clip-path: inset(-2000px 0 0 0);
    -webkit-clip-path: inset(-2000px 0 0 0);
    /* TEST: statt des reinen weissen Acryl-Panes (Original-Prototyp) bekommt
       die Flaeche hier zusaetzlich einen eigenen Blau/Lila-Basisverlauf, damit
       bei grossen Aufloesungen (viel Flaeche zwischen den fill-spot-Blobs)
       kein neutraler Weissraum mehr durchscheint. Die Blobs (.landing-tech-fill)
       und der Rauch (.landing-tech-smoke) bleiben unveraendert obenauf. */
    background:
        linear-gradient(160deg,
            color-mix(in srgb, var(--landing-accent) 55%, transparent) 0%,
            color-mix(in srgb, var(--landing-secondary) 55%, transparent) 55%,
            color-mix(in srgb, var(--landing-accent) 45%, transparent) 100%),
        rgba(255, 255, 255, .14);
    -webkit-backdrop-filter: blur(28px) saturate(220%);
    backdrop-filter: blur(28px) saturate(220%);
    padding: 64px 40px;
    box-sizing: border-box;
}


.landing-tech-inner {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: var(--landing-content-max);
    margin: 0 auto;
    text-align: center;
    color: #fff;
}

.landing-tech-band .landing-section-intro h2 {
    background: none;
    -webkit-background-clip: unset;
    background-clip: unset;
    -webkit-text-fill-color: unset;
    color: #fff;
    /* Analog zum Windows-11-Sperrbildschirm: ein weicher, dunkler
       Schlagschatten hinter weisser Schrift sorgt fuer Kontrast, egal wie
       hell/dunkel gerade der driftende Fill-Blob darunter liegt (ein
       backdrop-filter auf den Text selbst wuerde hier NICHT helfen, da er
       nur den Hintergrund unscharf macht, nicht die Textfarbe/den
       Kontrast veraendert). */
    text-shadow: 0 1px 4px rgba(0, 0, 0, .35), 0 2px 16px rgba(0, 0, 0, .2);
}

.landing-tech-band .landing-section-sub {
    color: #fff;
    max-width: 620px;
    margin: 0 auto;
    /* Staerkerer Schatten als bei der Ueberschrift fuer zuverlaessige
       Lesbarkeit gegenueber den hellen Fill-Blobs darunter. */
    text-shadow: 0 1px 3px rgba(0, 0, 0, .55), 0 2px 10px rgba(0, 0, 0, .4);
}

/* Flaechenfuellender Wolkeneffekt INNERHALB der Box: groessere, langsamere
   Versionen desselben Blau/Lila-Effekts, ueber die ganze Box verteilt. */
.landing-tech-fill {
    position: absolute;
    inset: 0;
    z-index: 0;
    overflow: visible;
}

.landing-tech-fill-rotator {
    position: absolute;
    inset: -15%;
    animation: landingFillSway 60s ease-in-out infinite alternate;
}

@keyframes landingFillSway {
    0% { transform: rotate(-4deg) scale(1.05); }
    100% { transform: rotate(4deg) scale(1.12); }
}

.landing-tech-spot {
    position: absolute;
    border-radius: 50%;
    filter: blur(50px);
    animation-name: var(--drift), var(--hue);
    animation-duration: var(--dur), var(--huedur);
    animation-timing-function: ease-in-out, ease-in-out;
    animation-iteration-count: infinite, infinite;
    animation-direction: alternate, alternate;
}

.landing-tech-spot.fs1 { width: 580px; height: 580px; top: -14%; left: -10%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 68%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 68%, transparent) 55%, transparent 80%); --drift: landingFillDrift1; --dur: 26s; --hue: landingHueShift; --huedur: 19s; animation-delay: 0s, -4s; }
.landing-tech-spot.fs2 { width: 500px; height: 500px; top: 26%; left: 16%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 62%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 62%, transparent) 55%, transparent 80%); --drift: landingFillDrift2; --dur: 31s; --hue: landingHueShiftRev; --huedur: 23s; animation-delay: -12s, -8s; }
.landing-tech-spot.fs3 { width: 660px; height: 660px; top: -4%; left: 40%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 62%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 62%, transparent) 55%, transparent 80%); --drift: landingFillDrift3; --dur: 29s; --hue: landingHueShift; --huedur: 17s; animation-delay: -20s, -2s; }
.landing-tech-spot.fs4 { width: 470px; height: 470px; top: 42%; left: 64%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 60%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 60%, transparent) 55%, transparent 80%); --drift: landingFillDrift1; --dur: 24s; --hue: landingHueShiftRev; --huedur: 21s; animation-delay: -6s, -11s; }
.landing-tech-spot.fs5 { width: 420px; height: 420px; top: -20%; left: 80%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 58%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 58%, transparent) 55%, transparent 80%); --drift: landingFillDrift2; --dur: 33s; --hue: landingHueShift; --huedur: 25s; animation-delay: -28s, -15s; }
.landing-tech-spot.fs6 { width: 360px; height: 360px; top: 10%; left: -8%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 56%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 56%, transparent) 55%, transparent 80%); --drift: landingFillDrift3; --dur: 22s; --hue: landingHueShiftRev; --huedur: 16s; animation-delay: -9s, -3s; }
.landing-tech-spot.fs7 { width: 430px; height: 430px; top: 54%; left: 30%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 60%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 60%, transparent) 55%, transparent 80%); --drift: landingFillDrift1; --dur: 27s; --hue: landingHueShift; --huedur: 20s; animation-delay: -16s, -6s; }
.landing-tech-spot.fs8 { width: 390px; height: 390px; top: 2%; left: 58%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 56%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 56%, transparent) 55%, transparent 80%); --drift: landingFillDrift2; --dur: 30s; --hue: landingHueShiftRev; --huedur: 18s; animation-delay: -23s, -10s; }
/* fs9-fs11: zusaetzliche Blobs fuer den unteren Bereich - unsere Section ist
   (anders als das kompakte Banner im Original-Prototyp) eine volle 100dvh-
   Section, daher blieb der untere Drittel-Bereich (top > 60%) vorher spuerbar
   duenner mit Farbe gefuellt als der obere Bereich. */
.landing-tech-spot.fs9 { width: 480px; height: 480px; top: 70%; left: 6%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 58%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 58%, transparent) 55%, transparent 80%); --drift: landingFillDrift3; --dur: 28s; --hue: landingHueShift; --huedur: 22s; animation-delay: -14s, -7s; }
.landing-tech-spot.fs10 { width: 560px; height: 560px; top: 66%; left: 42%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 60%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 60%, transparent) 55%, transparent 80%); --drift: landingFillDrift1; --dur: 32s; --hue: landingHueShiftRev; --huedur: 24s; animation-delay: -19s, -12s; }
.landing-tech-spot.fs11 { width: 420px; height: 420px; top: 78%; left: 72%; background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 56%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 56%, transparent) 55%, transparent 80%); --drift: landingFillDrift2; --dur: 25s; --hue: landingHueShift; --huedur: 17s; animation-delay: -8s, -18s; }

@keyframes landingFillDrift1 {
    0% { transform: translate(-90px, -40px) scale(.95); }
    35% { transform: translate(120px, 50px) scale(1.15); }
    70% { transform: translate(-60px, 70px) scale(.9); }
    100% { transform: translate(150px, -60px) scale(1.1); }
}

@keyframes landingFillDrift2 {
    0% { transform: translate(100px, 60px) scale(1.1); }
    35% { transform: translate(-130px, -30px) scale(.92); }
    70% { transform: translate(70px, -80px) scale(1.14); }
    100% { transform: translate(-100px, 40px) scale(.96); }
}

@keyframes landingFillDrift3 {
    0% { transform: translate(-60px, 80px) scale(1.05); }
    35% { transform: translate(90px, -50px) scale(.9); }
    70% { transform: translate(-120px, -20px) scale(1.16); }
    100% { transform: translate(80px, 60px) scale(1); }
}

@keyframes landingHueShift {
    0% { filter: blur(50px) hue-rotate(0deg); }
    100% { filter: blur(58px) hue-rotate(45deg); }
}

@keyframes landingHueShiftRev {
    0% { filter: blur(50px) hue-rotate(0deg); }
    100% { filter: blur(58px) hue-rotate(-45deg); }
}

/* Rauch-/Wolkeneffekt: steigt vom blauen Bereich in die Section darueber
   (#stand) - liegt ausserhalb von .landing-tech-band, direkt davor im
   .landing-tech-wrap, und ragt per negativem top ueber die Bandgrenze
   hinaus nach oben. */
.landing-tech-smoke {
    position: absolute;
    top: -820px;
    left: 0;
    right: 0;
    height: 1000px;
    pointer-events: none;
    overflow: visible;
    z-index: 0;
    max-width: 1300px;
    margin: 0 auto;
}

.landing-smoke-group {
    position: absolute;
    left: 38%;
    bottom: -90px;
    width: 270px;
    height: 270px;
    animation: landingDriftSlowA 24s ease-in-out infinite alternate;
    animation-delay: -3s;
}

/* Pausiert die gesamte Rauch-/Wolken-Animationskette (Sway/Breathe/Drift/
   Rotate/HueShift auf allen verschachtelten Kind-Elementen), sobald
   .landing-tech-smoke per IntersectionObserver (siehe landing.js) als nicht
   sichtbar erkannt wird. Vorher lief die Animation dauerhaft weiter, auch
   wenn #technik laengst nicht mehr im Viewport war - unnoetige Dauerlast im
   Compositor-Thread ohne sichtbaren Nutzen. */
.landing-tech-smoke.animations-paused,
.landing-tech-smoke.animations-paused * {
    animation-play-state: paused !important;
}

.landing-smoke-cluster {
    position: absolute;
    inset: 0;
    transform-origin: center bottom;
    animation: landingClusterBreathe 16s ease-in-out infinite;
}

.landing-cluster-rotator {
    position: absolute;
    inset: 0;
    transform-origin: center center;
    animation: landingClusterSway 48s ease-in-out infinite alternate;
}

@keyframes landingClusterSway {
    0% { transform: rotate(-5deg); }
    100% { transform: rotate(5deg); }
}

@keyframes landingClusterBreathe {
    0% { transform: scaleX(0.88); }
    50% { transform: scaleX(1.18); }
    100% { transform: scaleX(0.88); }
}

.landing-group-rotator {
    position: absolute;
    inset: 0;
    animation: landingRotateCW 32s linear infinite;
}

.landing-smoke-group.group2 .landing-group-rotator {
    animation: landingRotateCCW 20s linear infinite;
}

@keyframes landingRotateCW { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes landingRotateCCW { from { transform: rotate(0deg); } to { transform: rotate(-360deg); } }

.landing-group-spot {
    position: absolute;
    display: block;
    border-radius: 50%;
}

.landing-group-spot .inner {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 50%;
}

.landing-group-spot.g1a { width: 225px; height: 225px; top: 30px; left: 0px; }
.landing-group-spot.g1a .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 90%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 90%, transparent) 55%, transparent 78%); filter: blur(34px); animation: landingPulseA 7s ease-in-out infinite alternate; }

.landing-group-spot.g1b { width: 178px; height: 178px; top: -50px; left: 120px; }
.landing-group-spot.g1b .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 86%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 86%, transparent) 55%, transparent 78%); filter: blur(37px); animation: landingPulseB 9s ease-in-out infinite alternate; animation-delay: -3s; }

.landing-group-spot.g1c { width: 142px; height: 142px; top: 70px; left: 170px; }
.landing-group-spot.g1c .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 75%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 75%, transparent) 55%, transparent 78%); filter: blur(38px); animation: landingPulseC 6.5s ease-in-out infinite alternate; animation-delay: -5s; }

.landing-smoke-group.group2 { left: 52%; bottom: -90px; width: 280px; height: 280px; animation: landingDriftFastA 12s ease-in-out infinite alternate; animation-delay: -4s; }

.landing-group-spot.g2a { width: 272px; height: 272px; top: 20px; left: 0px; }
.landing-group-spot.g2a .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 82%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 82%, transparent) 55%, transparent 78%); filter: blur(36px); animation: landingPulseB 8s ease-in-out infinite alternate; animation-delay: -2s; }

.landing-group-spot.g2b { width: 112px; height: 112px; top: -35px; left: 190px; }
.landing-group-spot.g2b .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 88%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 88%, transparent) 55%, transparent 78%); filter: blur(34px); animation: landingPulseA 5.5s ease-in-out infinite alternate; animation-delay: -4s; }

.landing-group-spot.g2c { width: 89px; height: 89px; top: 90px; left: 210px; }
.landing-group-spot.g2c .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 70%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 70%, transparent) 55%, transparent 78%); filter: blur(35px); animation: landingPulseC 7s ease-in-out infinite alternate; animation-delay: -1.5s; }

.landing-smoke-group.group3 { left: 63%; bottom: -90px; width: 260px; height: 260px; animation: landingDriftSlowB 22s ease-in-out infinite alternate; animation-delay: -7s; }
.landing-smoke-group.group3 .landing-group-rotator { animation: landingRotateCW 24s linear infinite; }

.landing-group-spot.g3a { width: 195px; height: 195px; top: 15px; left: 0px; }
.landing-group-spot.g3a .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 82%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 82%, transparent) 55%, transparent 78%); filter: blur(37px); animation: landingPulseA 8s ease-in-out infinite alternate; animation-delay: -3.5s; }

.landing-group-spot.g3b { width: 183px; height: 183px; top: -45px; left: 130px; }
.landing-group-spot.g3b .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 78%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 78%, transparent) 55%, transparent 78%); filter: blur(39px); animation: landingPulseB 6.5s ease-in-out infinite alternate; animation-delay: -2s; }

.landing-group-spot.g3c { width: 95px; height: 95px; top: 100px; left: 150px; }
.landing-group-spot.g3c .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 65%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 65%, transparent) 55%, transparent 78%); filter: blur(36px); animation: landingPulseC 9s ease-in-out infinite alternate; animation-delay: -6s; }

.landing-smoke-group.group4 { left: 14%; bottom: -90px; width: 250px; height: 250px; animation: landingDriftFastB 15s ease-in-out infinite alternate; animation-delay: -6s; }
.landing-smoke-group.group4 .landing-group-rotator { animation: landingRotateCCW 22s linear infinite; }

.landing-group-spot.g4a { width: 165px; height: 165px; top: 20px; left: 0px; }
.landing-group-spot.g4a .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 85%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 85%, transparent) 55%, transparent 78%); filter: blur(33px); animation: landingPulseC 7.5s ease-in-out infinite alternate; animation-delay: -4s; }

.landing-group-spot.g4b { width: 150px; height: 150px; top: -40px; left: 140px; }
.landing-group-spot.g4b .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-accent) 80%, transparent) 0%, color-mix(in srgb, var(--landing-accent) 80%, transparent) 55%, transparent 78%); filter: blur(35px); animation: landingPulseA 9.5s ease-in-out infinite alternate; animation-delay: -2.5s; }

.landing-group-spot.g4c { width: 115px; height: 115px; top: 90px; left: 160px; }
.landing-group-spot.g4c .inner { background: radial-gradient(circle, color-mix(in srgb, var(--landing-secondary) 68%, transparent) 0%, color-mix(in srgb, var(--landing-secondary) 68%, transparent) 55%, transparent 78%); filter: blur(34px); animation: landingPulseB 6s ease-in-out infinite alternate; animation-delay: -7s; }

@keyframes landingDriftSlowA {
    0% { transform: translate(0, 40px); opacity: .2; filter: blur(0px); }
    20% { transform: translate(70px, -90px); opacity: .55; filter: blur(9px); }
    45% { transform: translate(-95px, -250px); opacity: .48; filter: blur(17px); }
    70% { transform: translate(75px, -430px); opacity: .3; filter: blur(26px); }
    88% { transform: translate(-60px, -560px); opacity: .14; filter: blur(33px); }
    100% { transform: translate(0, -680px); opacity: .05; filter: blur(38px); }
}

@keyframes landingDriftSlowB {
    0% { transform: translate(0, 30px); opacity: .2; filter: blur(0px); }
    25% { transform: translate(-90px, -100px); opacity: .5; filter: blur(9px); }
    50% { transform: translate(80px, -280px); opacity: .42; filter: blur(18px); }
    75% { transform: translate(-85px, -450px); opacity: .26; filter: blur(27px); }
    90% { transform: translate(-30px, -580px); opacity: .13; filter: blur(34px); }
    100% { transform: translate(0, -660px); opacity: .05; filter: blur(38px); }
}

@keyframes landingDriftFastA {
    0% { transform: translate(0, 25px); opacity: .2; filter: blur(0px); }
    15% { transform: translate(45px, -40px); opacity: .6; filter: blur(7px); }
    35% { transform: translate(-55px, -140px); opacity: .52; filter: blur(15px); }
    55% { transform: translate(50px, -260px); opacity: .38; filter: blur(22px); }
    78% { transform: translate(-42px, -420px); opacity: .2; filter: blur(29px); }
    100% { transform: translate(0, -560px); opacity: .06; filter: blur(35px); }
}

@keyframes landingDriftFastB {
    0% { transform: translate(0, 20px); opacity: .18; filter: blur(0px); }
    18% { transform: translate(-50px, -45px); opacity: .55; filter: blur(7px); }
    40% { transform: translate(45px, -150px); opacity: .46; filter: blur(15px); }
    60% { transform: translate(-48px, -270px); opacity: .32; filter: blur(22px); }
    82% { transform: translate(38px, -420px); opacity: .17; filter: blur(29px); }
    100% { transform: translate(0, -540px); opacity: .05; filter: blur(34px); }
}

@keyframes landingPulseA {
    0% { transform: scale(.7); }
    50% { transform: scale(1.3); }
    100% { transform: scale(.9); }
}

@keyframes landingPulseB {
    0% { transform: scale(1.15); }
    50% { transform: scale(.75); }
    100% { transform: scale(1.25); }
}

@keyframes landingPulseC {
    0% { transform: scale(.85); }
    50% { transform: scale(1.4); }
    100% { transform: scale(1); }
}

.landing-tech-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: 18px;
    margin-top: 36px;
    position: relative;
    z-index: 1;
}

.landing-tech-card {
    background: rgba(255, 255, 255, .14);
    -webkit-backdrop-filter: blur(10px) saturate(140%);
    backdrop-filter: blur(10px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, .22);
    border-radius: 12px;
    padding: 22px 20px;
    text-align: left;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
}

.landing-tech-card svg {
    display: block;
    width: 26px;
    height: 26px;
    margin-bottom: 16px;
    /* SVG-Pendant zu text-shadow (text-shadow greift bei SVG-Icons nicht):
       sorgt fuer denselben Kontrast-Puffer wie bei Titel/Absatz darunter. */
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, .3));
}

.landing-tech-card .t {
    font-size: 15.5px;
    font-weight: 700;
    margin-bottom: 8px;
    line-height: 1.35;
    color: #fff;
    text-shadow: 0 1px 3px rgba(0, 0, 0, .3);
}

.landing-tech-card p {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.6;
    color: rgba(255, 255, 255, .86);
}

@media (prefers-reduced-motion: reduce) {
    .landing-tech-fill-rotator { animation: none; }
    .landing-tech-spot { animation: none; }
    .landing-smoke-group,
    .landing-smoke-cluster,
    .landing-cluster-rotator,
    .landing-group-rotator,
    .landing-group-spot .inner {
        animation: none;
        opacity: .5;
    }
}


/* ===== "Geplante KI-Funktionen" (Konzept: #ki-funktionen, Hub-Layout) =====
   Zwei Spalten (Text+Liste / Ticket-Mockup), die bei schmalerer Breite
   untereinander umbrechen - analog .hub-section aus der Konzeptvorlage. */
.landing-hub {
    display: flex;
    gap: 56px;
    align-items: center;
    flex-wrap: wrap;
    /* Gleiche Obergrenze wie .landing-grid-4, damit beide Sections auf
       sehr breiten Bildschirmen (z.B. echte 1920px+ CSS-Pixel-Breite bei
       100% Skalierung) konsistent an derselben Kante enden statt einer der
       beiden Bloecke bis zum Section-Rand zu ziehen. */
    max-width: var(--landing-content-max);
    margin-inline: auto;
    width: 100%;
}

.landing-hub-text {
    flex: 1 1 480px;
    min-width: 300px;
}

.landing-hub-text h2 {
    margin: 0 0 12px;
    font-size: clamp(24px, 2.6vw, 28px);
    font-weight: 700;
    letter-spacing: -0.01em;
    /* Gleicher Gradient-Treatment wie .landing-section-intro h2 (siehe dortiger
       Kommentar zu background-clip:text/line-height): grosszuegiges
       line-height noetig, damit Ober-/Unterlaengen nicht abgeschnitten wirken. */
    line-height: 1.4;
    background: linear-gradient(90deg, var(--landing-accent), var(--landing-secondary));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

.landing-hub-text .landing-section-sub {
    text-align: left;
}

.landing-kicker {
    font-size: 12.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--landing-secondary);
    margin-bottom: 14px;
}

.landing-hub-list {
    margin-top: 18px;
}

/* Etwas kompakter als im Konzept (20px 4px): die Karte ist ohnehin schon
   die volle Sektionshoehe des Hero-Grids, mit drei Zeilen wirkte die
   Roadmap-Section dadurch spuerbar hoeher als die uebrigen Sections -
   engeres Padding/Gap haelt die drei Zeilen kompakter. */
.landing-hub-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 10px;
    border-top: 1px solid var(--landing-border);
    transition: background .15s ease;
    position: relative;
    cursor: pointer;
    overflow: hidden;
}

/* Story-artiger Fortschrittsbalken: schmaler Strich am unteren Rand der
   aktiven Zeile, der ueber die Zyklusdauer (siehe HubCycleMs im @code-Block)
   von 0% auf 100% Breite waechst - visuelles Feedback, dass dieser Punkt
   gerade aktiv ist und wie lange bis zum naechsten automatischen Wechsel. */
.landing-hub-row-progress {
    position: absolute;
    left: 0;
    bottom: 0;
    height: 2px;
    background: linear-gradient(90deg, var(--landing-accent), var(--landing-secondary));
    transition: width .1s linear;
}

.landing-hub-row:first-child {
    border-top: none;
}

.landing-hub-row-text {
    flex: 1;
    min-width: 0;
    transition: transform .2s ease;
}

.landing-hub-row-text h4 {
    margin: 0 0 4px;
    font-size: 15.5px;
    font-weight: 600;
    color: var(--landing-text);
}

.landing-hub-row-text p {
    margin: 0;
    font-size: 14px;
    color: var(--landing-text-muted);
    line-height: 1.5;
}

.landing-hub-row-chevron {
    color: var(--landing-text-faint);
    flex: none;
    transition: transform .2s ease, color .2s ease;
}

/* Fuehrendes Icon (links, z.B. Chat/Database/Person) bewegte sich bisher
   NICHT mit, obwohl Text (.landing-hub-row-text) und Chevron rechts beim
   Hover nach rechts wandern - dadurch wirkte die Zeile inkonsistent
   animiert. Gleiche Transform/Transition wie beim Chevron, damit alle drei
   Elemente einer Zeile (Icon, Text, Chevron) gemeinsam nach rechts gleiten.
   Selektor bewusst NICHT mehr ":first-child" (seit der Progress-Bar ist
   .landing-hub-row-progress das tatsaechliche erste Kind der Zeile, das
   fuehrende svg ist das zweite Kind - ":first-child" griff dadurch nie mehr)
   sondern ueber ":not()" alle SVG-Kinder ausser dem Chevron selbst. */
.landing-hub-row > svg:not(.landing-hub-row-chevron) {
    transition: transform .2s ease;
}

.landing-hub-row:hover > svg:not(.landing-hub-row-chevron) {
    transform: translateX(4px);
}

.landing-hub-row:hover {
    background: var(--landing-panel-alt);
}

.landing-hub-row.active {
    background: color-mix(in srgb, var(--landing-secondary) 5%, transparent);
}

.landing-hub-row.active .landing-hub-row-text h4 {
    color: var(--landing-secondary);
}

.landing-hub-row:hover .landing-hub-row-text {
    transform: translateX(4px);
}

.landing-hub-row:hover .landing-hub-row-chevron {
    transform: translateX(4px);
    color: var(--landing-accent);
}

/* flex-grow bewusst 0 statt 1 (anders als .landing-hub-text): die Ticket-
   Karte braucht deutlich weniger Breite als der Text-/Listenbereich, damit
   soll sie nicht gleichberechtigt mitwachsen, sondern der Textbereich bekommt
   den zusaetzlichen Platz - reduziert Zeilenumbrueche links und damit die
   Gesamthoehe der Section. */
.landing-hub-visual {
    flex: 0 1 340px;
    min-width: 280px;
    display: flex;
    justify-content: center;
    /* Sobald .landing-hub-text (flex:1 1 480px) bei mittlerer Breite in eine
       eigene Zeile umbricht, steht .landing-hub-visual als einziges Element
       in seiner Flex-Zeile - da es selbst nicht waechst (flex-grow:0), wuerde
       es sonst gemaess dem Standard-justify-content des Flex-Containers
       (.landing-hub) links ausgerichtet bleiben, obwohl in der Zeile Platz
       ist. margin-inline:auto zentriert es in diesem Fall automatisch
       (Flexbox-Auto-Margins wirken pro umgebrochener Zeile), unabhaengig
       vom konkreten Breakpoint/Geraet - ohne diesen Fix stand die Chatbox
       erst ab dem naechsten (mobilen Navigations-)Breakpoint zentriert. */
    margin-inline: auto;
}

/* Ticket-Mockup: Karte mit denselben Schatten-/Radius-Werten wie
   .landing-feature-card, damit sie sich optisch in dasselbe Kartensystem
   einfuegt. */
.landing-ticket-mock {
    width: 100%;
    max-width: 340px;
    background: var(--landing-panel);
    border: 1px solid rgba(0, 0, 0, .05);
    border-radius: var(--landing-radius);
    box-shadow: 0 1px 2px rgba(0, 0, 0, .09), 0 8px 20px rgba(0, 0, 0, .08);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    /* Feste Mindesthoehe noetig: die drei rotierenden Hub-Items haben
       unterschiedlich lange Nachrichten-/Antworttexte. Ohne min-height
       wuerde die Kartenhoehe bei jedem automatischen Wechsel springen und
       dadurch (wegen .landing-hub { align-items:center }) die gesamte
       Section samt Ueberschrift/Menuepunkten links auf/ab bewegen. Der Wert
       ist auf den laengsten der drei Hub-Items abgestimmt. Leicht erhoeht
       (400px -> 420px), da Kopf-/Body-Padding etwas grosszuegiger wurden -
       bewusst weiterhin kleiner als die 4 Feature-Cards darueber. */
    min-height: 420px;
}

/* Card-Innenabstaende/Schriftgroessen insgesamt gegenueber dem Konzept
   (400px-Karte) leicht verkleinert: die schmalere 340px-Karte (siehe
   .landing-ticket-mock) wuerde sonst durch den unveraenderten Content in
   der Hoehe staerker wachsen als die drei Roadmap-Zeilen links daneben -
   proportional kompaktere Werte halten beide Spalten etwa gleich hoch. */
.landing-ticket-top {
    display: flex;
    align-items: center;
    gap: 8px;
    /* Oben/unten etwas grosszuegiger als vorher (11px -> 14px), seitlich
       unveraendert bei 14px (an .landing-feature-card-header angeglichen) -
       bewusst weiterhin kompakter als die Feature-Card-Header. */
    padding: 14px 14px;
    background: linear-gradient(90deg, var(--landing-accent), var(--landing-secondary));
    overflow: hidden;
}

/* Kopfbereich (Icon+Titel) laeuft beim Wechsel sichtbar aus dem Header raus
   und (nach Pause, siehe .is-switching-Verzoegerung unten) von rechts wieder
   rein - synchron zur Box darunter, damit der Wechsel oben genauso klar
   wahrnehmbar ist wie der Content-Wechsel selbst, nicht nur ein kaum
   sichtbares Detail. */
.landing-ticket-top-inner {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    transform: translateX(0);
    opacity: 1;
    transition: opacity .18s ease, transform .18s ease;
}

.landing-ticket-top-inner.is-switching {
    opacity: 0;
    transform: translateX(-24px);
    transition: opacity .16s ease, transform .16s ease;
}

/* Direkt nach dem Content-Tausch startet der Titel rechts ausserhalb und
   ohne Transition (siehe .is-entering), damit der naechste Frame ihn per
   Transition sichtbar von rechts einfahren laesst - kein Zurueckfahren auf
   demselben Weg wie beim Ausblenden nach links. */
.landing-ticket-top-inner.is-entering {
    opacity: 0;
    transform: translateX(24px);
    transition: none;
}

.landing-ticket-title {
    font-size: 14.5px;
    font-weight: 600;
    color: #fff;
}

.landing-ticket-body {
    flex: 1 1 auto;
    /* Oben/unten etwas grosszuegiger als vorher (14px -> 18px), seitlich
       unveraendert bei 14px. */
    padding: 18px 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    opacity: 1;
    transition: opacity .4s ease;
}

/* Waehrend der Wechsel-Sequenz (siehe _hubSwitching/HubFadeOutMs im
   @code-Block) blendet die GESAMTE Box aus. Der Inhalt wird von C# erst
   getauscht, sobald sie unsichtbar ist - danach faellt is-switching wieder
   weg und die Box blendet ein, wobei die einzelnen Bloecke unten gestaffelt
   nacheinander erscheinen (reines CSS, kein manuelles Timer-Stepping mehr). */
.landing-ticket-body.is-switching {
    opacity: 0;
}

/* Gestaffeltes Einblenden der Ticket-Bloecke (Kundennachricht -> "automatisch
   erkannt"-Status -> Claude-Antwort -> Button) nach einem Wechsel, analog zur
   .ticket-step-Animation aus dem Konzept-Mockup (Konzept/vylife-landingpage.html).
   Bewusst GROSSZUEGIGE Verzoegerungen: soll wie ein echter, nach und nach
   eintrudelnder Chatverlauf wirken (erst poppt die Kundennachricht auf, dann
   nach spuerbarer Pause der Status, dann noch spaeter die Antwort, zuletzt
   der Button) statt fast gleichzeitig durchzulaufen. Rein CSS-getrieben ueber
   transition-delay pro Block: solange die Elternbox (.landing-ticket-body)
   is-switching traegt, sind alle Bloecke unsichtbar OHNE Verzoegerung
   (transition-delay:0s beim Ausblenden); erst beim Wiedereinblenden greifen
   die gestaffelten delays. */
.landing-ticket-step {
    opacity: 0;
    transform: translateY(14px) scale(.97);
    transition: opacity .5s ease, transform .5s ease;
}

.landing-ticket-body:not(.is-switching) .landing-ticket-step {
    opacity: 1;
    transform: none;
}

.landing-ticket-body:not(.is-switching) .landing-ticket-msg:not(.landing-ticket-msg-reply).landing-ticket-step {
    transition-delay: 1s;
}

.landing-ticket-body:not(.is-switching) .landing-ticket-tags.landing-ticket-step {
    transition-delay: 1.6s;
}

/* Nachdem die "Automatisch erkannt"-Zeile selbst eingeblendet ist (Delay
   1.6s), poppen die beiden Tags NICHT gleichzeitig mit ihr, sondern separat
   nacheinander (eigene .landing-ticket-tag-Animation weiter unten) - dafuer
   ruecken Antwort und Button entsprechend spaeter. */
.landing-ticket-body:not(.is-switching) .landing-ticket-msg-reply.landing-ticket-step {
    transition-delay: 3.2s;
}

.landing-ticket-body:not(.is-switching) .landing-ticket-use-btn.landing-ticket-step {
    transition-delay: 4s;
}

.landing-ticket-body.is-switching .landing-ticket-step {
    transition-delay: 0s;
}

/* Tippeffekt der Claude-Antwort: sobald die Sprechblase (Delay 3.2s + .5s
   Reveal-Dauer, siehe ReplyTypeStartMs im @code-Block) fertig eingeblendet
   ist, wird der Text zeichenweise ueber _hubContentElapsedMs/TypedReplyText
   aufgebaut. Waehrend des Tippens zeigt ein blinkender Cursor am Textende
   an, dass "getippt" wird; ist der Text fertig, verschwindet der Cursor. */
.landing-ticket-typing {
    display: inline;
}

.landing-ticket-typing.is-typing::after {
    content: "";
    display: inline-block;
    width: 2px;
    height: 12px;
    margin-left: 2px;
    background: var(--landing-secondary);
    vertical-align: -1px;
    animation: landing-typing-cursor .8s step-end infinite;
}

@keyframes landing-typing-cursor {
    0%, 49% { opacity: 1; }
    50%, 100% { opacity: 0; }
}

/* Die beiden erkannten Tags poppen einzeln nacheinander auf (Scale-Bounce
   statt seitlichem Einblenden wie die uebrigen Bloecke), NACHDEM die
   Tagline-Zeile selbst (siehe .landing-ticket-tags-Delay 1.6s oben) sichtbar
   ist - Delays hier sind daher jeweils 1.6s + eigener Versatz. */
.landing-ticket-tag {
    display: inline-flex;
    opacity: 0;
    transform: scale(.4);
    transition: opacity .25s ease, transform .35s cubic-bezier(.34, 1.56, .64, 1);
}

.landing-ticket-body:not(.is-switching) .landing-ticket-tags.landing-ticket-step .landing-ticket-tag {
    opacity: 1;
    transform: none;
}

.landing-ticket-body:not(.is-switching) .landing-ticket-tags.landing-ticket-step .landing-ticket-tag-1 {
    transition-delay: 2.1s;
}

.landing-ticket-body:not(.is-switching) .landing-ticket-tags.landing-ticket-step .landing-ticket-tag-2 {
    transition-delay: 2.5s;
}

.landing-ticket-body.is-switching .landing-ticket-tag {
    transition-delay: 0s;
    opacity: 0;
    transform: scale(.4);
}

.landing-ticket-msg {
    display: flex;
}

.landing-ticket-author {
    font-size: 12px;
    font-weight: 600;
    color: var(--landing-text-muted);
}

.landing-ticket-bubble-content {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

/* Der Avatar-Platzhalter sitzt jetzt oben in der Sprechblase statt
   daneben - dadurch entfaellt die Nebeneinander-Anordnung und die Karte
   wird insgesamt kompakter. Blau eingefaerbt, damit Kundennachricht (blau)
   und KI-Antwort (lila, siehe .landing-ticket-bubble-avatar-bot) farblich
   klar unterscheidbar sind. */
.landing-ticket-bubble-avatar {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--landing-accent);
    color: #fff;
    font-size: 13px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
}

.landing-ticket-bubble {
    background: color-mix(in srgb, var(--landing-accent) 6%, var(--landing-panel));
    border: 1px solid color-mix(in srgb, var(--landing-accent) 35%, transparent);
    border-radius: 10px;
    border-top-left-radius: 2px;
    padding: 9px 12px;
    color: var(--landing-text);
    max-width: 100%;
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
}

.landing-ticket-bubble p {
    margin: 0;
    font-size: 13px;
    line-height: 1.5;
}

.landing-ticket-tags {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.landing-ticket-tagline {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--landing-secondary);
    margin-right: 2px;
}

/* Pop-in-Animation (opacity/transform/transition) fuer .landing-ticket-tag
   ist weiter oben bei .landing-ticket-step definiert, hier nur die
   optischen Basis-Styles (Farbe/Radius/Abstand). */
.landing-ticket-tag {
    font-size: 11.5px;
    font-weight: 600;
    padding: 3px 9px;
    border-radius: var(--landing-radius-pill);
    background: var(--landing-secondary-soft);
    color: var(--landing-secondary);
}

/* Antwort-Sprechblase im selben Grundmuster wie die Kundennachricht oben
   (.landing-ticket-bubble), nur mit Bot-Avatar statt Initialen-Kuerzel und
   lila statt blauer Einfaerbung, damit Kunden- (blau) und KI-Nachricht (lila)
   optisch klar unterscheidbar bleiben. */
.landing-ticket-bubble-reply {
    background: color-mix(in srgb, var(--landing-secondary) 6%, var(--landing-panel));
    border: 1px solid color-mix(in srgb, var(--landing-secondary) 35%, transparent);
    border-top-left-radius: 2px;
}

.landing-ticket-bubble-avatar-bot {
    background: var(--landing-secondary);
}

.landing-ticket-bubble-avatar-bot svg {
    display: block;
}

.landing-ticket-use-btn {
    font-size: 12px;
    font-weight: 600;
    color: #fff;
    background: var(--landing-secondary);
    border: none;
    border-radius: 6px;
    padding: 7px 12px;
    cursor: default;
    align-self: flex-start;
    /* .landing-ticket-body ist ein Flex-Container mit fester min-height
       (siehe .landing-ticket-mock) - je nach Item bleibt darunter Freiraum,
       da es keinen eigenen Fussbereich gibt. margin-top:auto zieht den
       Button (als letztes Kind) in die Mitte dieses Restraums statt ihn
       oben an den letzten Chat-Block kleben zu lassen. */
    margin-top: auto;
    margin-bottom: auto;
}

@media (max-width: 900px) {
    .landing-hub {
        gap: 36px;
    }
}

/* ===== Scroll-Reveal =====
   ACHTUNG (Fallback, bewusst NICHT geloescht): Der folgende Block ist die
   URSPRUENGLICHE, transition-basierte Variante des Reveal-Effekts. Sie
   funktioniert zuverlaessig fuer den EINMALIGEN Reveal beim ersten Scrollen/
   Betreten einer Section, aber NICHT zuverlaessig fuer das erneute Abspielen
   per Klassenwechsel (Menue-Navigation, mehrfacher Durchlauf) - CSS-
   Transitions garantieren nicht, dass der Browser zwischen Entfernen und
   Wiederhinzufuegen einer Klasse tatsaechlich einen Frame rendert, selbst mit
   erzwungenem Reflow (el.offsetHeight)/doppeltem requestAnimationFrame. Bei
   Bedarf kann dieser Block wieder aktiviert werden (auskommentieren rueckgaengig
   machen) UND gleichzeitig der neue @keyframes-Block weiter unten deaktiviert
   werden - beide Varianten sollen nicht gleichzeitig aktiv sein, da sie
   dieselben Klassennamen (.reveal, .reveal.visible usw.) verwenden.

.reveal, .reveal-left, .reveal-right, .reveal-scale {
    opacity: 0;
    transition: opacity .7s cubic-bezier(.16, 1, .3, 1), transform .7s cubic-bezier(.16, 1, .3, 1);
}

.reveal { transform: translateY(28px); }
.reveal-left { transform: translateX(-32px); }
.reveal-right { transform: translateX(32px); }
.reveal-scale { transform: scale(.92); }

.reveal.visible, .reveal-left.visible, .reveal-right.visible, .reveal-scale.visible {
    opacity: 1;
    transform: none;
}

.reveal-instant {
    transition: none !important;
}
*/

/* ===== Scroll-Reveal (AKTIV): Keyframe-Animation statt Transition =====
   Grund fuer den Wechsel: eine CSS-Animation (@keyframes), die per Klasse
   (.reveal-play) gestartet wird, beginnt beim erneuten Hinzufuegen dieser
   Klasse GARANTIERT wieder bei 0% - dafuer reicht ein einzelner erzwungener
   Reflow (el.offsetHeight) zwischen Entfernen und Wiederhinzufuegen der
   Klasse. Transitions haben dieses Garantieverhalten nicht (siehe Kommentar
   oben) - das war die Ursache dafuer, dass der Stagger-Effekt bei
   Menue-Navigation ab dem zweiten Durchlauf nicht mehr sichtbar ablief,
   obwohl die JS-Logs (siehe landing.js, [reveal-debug]) einen korrekten
   Ablauf zeigten.

   Basis-Zustand (.reveal/.reveal-left/.reveal-right/.reveal-scale ohne
   .reveal-play) bleibt unsichtbar/verschoben - identisch zum bisherigen
   Basiszustand, damit vor dem ersten Aufdecken nichts kurz aufblitzt. */
.reveal, .reveal-left, .reveal-right, .reveal-scale {
    opacity: 0;
}

.reveal { transform: translateY(28px); }
.reveal-left { transform: translateX(-32px); }
.reveal-right { transform: translateX(32px); }
.reveal-scale { transform: scale(.92); }

@keyframes reveal-play-up {
    from { opacity: 0; transform: translateY(28px); }
    to { opacity: 1; transform: none; }
}
@keyframes reveal-play-left {
    from { opacity: 0; transform: translateX(-32px); }
    to { opacity: 1; transform: none; }
}
@keyframes reveal-play-right {
    from { opacity: 0; transform: translateX(32px); }
    to { opacity: 1; transform: none; }
}
@keyframes reveal-play-scale {
    from { opacity: 0; transform: scale(.92); }
    to { opacity: 1; transform: none; }
}

/* .visible bleibt (fuer bestehende JS-Kompatibilitaet/andere Selektoren wie
   .landing-feature-card:hover, die .reveal.visible referenzieren) weiterhin
   der Endzustand - wird von landing.js nach Animationsende zusaetzlich
   gesetzt. .reveal-play ist die Klasse, die die eigentliche Animation
   ANSTOESST; ihr transition-delay (inline im Markup gesetzt, siehe
   Landingpage.razor) wird 1:1 als animation-delay wiederverwendet. */
.reveal.reveal-play, .reveal-left.reveal-play, .reveal-right.reveal-play, .reveal-scale.reveal-play,
.reveal.visible, .reveal-left.visible, .reveal-right.visible, .reveal-scale.visible {
    opacity: 1;
    transform: none;
}

.reveal.reveal-play { animation: reveal-play-up .7s cubic-bezier(.16, 1, .3, 1) both; animation-delay: var(--reveal-delay, 0ms); }
.reveal-left.reveal-play { animation: reveal-play-left .7s cubic-bezier(.16, 1, .3, 1) both; animation-delay: var(--reveal-delay, 0ms); }
.reveal-right.reveal-play { animation: reveal-play-right .7s cubic-bezier(.16, 1, .3, 1) both; animation-delay: var(--reveal-delay, 0ms); }
.reveal-scale.reveal-play { animation: reveal-play-scale .7s cubic-bezier(.16, 1, .3, 1) both; animation-delay: var(--reveal-delay, 0ms); }


/* ===== Responsive ===== */
@media (max-width: 820px) {
    /* Auf schmalen Screens schaltet der Toggle-Button (isMobileWidth() in
       app-shell.js) statt Rail ein Drawer um - dieselbe .rail-Klasse wird
       hier daher als "ausgeblendet" statt "schmal" interpretiert (analog
       .app-sidebar off-canvas-Verhalten in app-shell.css). */
    .landing-sidebar {
        position: fixed;
        z-index: 20;
        height: 100vh;
        width: 272px;
        transform: translateX(0);
        /* Gleiche Transition-Dauer/Kurve wie das mobile Drawer der ERP-Shell
           (siehe .app-sidebar in app-shell.css, @media max-width: 767px),
           damit Oeffnen/Schliessen auf Landingpage und im App-Bereich exakt
           gleich wirken. */
        transition: transform 0.3s ease-in-out;
        box-shadow: 0 0 0 2000px rgba(0, 0, 0, .25);
    }

    .landing-sidebar.rail {
        width: 272px;
        padding: 18px 16px;
        transform: translateX(-100%);
        box-shadow: none;
        /* WICHTIG: die Desktop-Regel .landing-sidebar.rail (oben, ausserhalb
           dieser Media-Query) setzt "transition: width 0.2s ease-in-out" -
           gleiche Selektor-Spezifitaet (zwei Klassen), daher wuerde ohne
           diesen Override die width-Transition weiterhin gelten und
           "transform" (das eigentlich animierte Property beim Schliessen)
           OHNE Animation springen. Deshalb hier explizit transform als
           transitioniertes Property angeben, analog zur Basis-Regel oben. */
        transition: transform 0.3s ease-in-out;
    }

    .landing-sidebar.rail .vylife-logo-title,
    .landing-sidebar.rail .landing-sidebar-footer-text,
    .landing-sidebar.rail .landing-sidebar-footer-legal,
    .landing-sidebar.rail .landing-nav button span {
        opacity: 1;
        max-width: none;
        pointer-events: auto;
    }

    /* Overlay hinter der aufgeklappten Sidebar: schliesst sie beim Klick in
       den Content. Nur in der mobilen Ansicht sichtbar (analog
       .app-sidebar-overlay in app-shell.css). */
    .landing-sidebar-overlay {
        position: fixed;
        inset: 0;
        z-index: 15;
        background: rgba(0, 0, 0, .25);
        display: block;
    }

    .landing-hero {
        padding-inline: 20px;
    }

    .landing-mockup-section {
        padding-inline: 20px;
    }

    .landing-section-panel {
        padding-inline: 20px;
    }

    /* Section-Ueberschriften/-Untertexte (Konzept: entstehung/stand/technik/
       demo teilen sich alle .landing-section-intro h2/.landing-section-sub)
       bekommen auf Mobile feste, kleinere Werte statt des Desktop-clamp()
       bzw. der 16.5px-Basisgroesse - analog zum bereits bestehenden festen
       Verkleinerungsfaktor von Logo/Hero-Titel/Buttons weiter unten. Da
       beide Klassen zentral von allen Content-Sections wiederverwendet
       werden, wirkt diese eine Regel automatisch ueberall gleich. */
    .landing-section-intro h2 {
        font-size: 24px;
    }

    .landing-section-sub {
        font-size: 15px;
    }

    .landing-hero-logo {
        margin-bottom: 32px;
    }

    .landing-hero-logo .vylife-logo {
        /* Gleicher Verkleinerungsfaktor wie .landing-hero-title (44px -> 32px,
           Faktor 0.727), damit Logo/Ueberschrift-Verhaeltnis erhalten bleibt. */
        --vylife-logo-size: 58px !important;
    }

    .landing-header {
        padding: 12px 18px;
        gap: 8px;
    }

    /* Demo-Button im Header: auf Mobile nur noch das Plus-Icon anzeigen (kein
       Text/Label), damit der Button im schmalen Header nicht zu breit wird -
       analog zu anderen reinen Icon-Buttons im Header (z.B. .landing-menu-btn).
       Padding wird dafuer auf ein gleichmaessiges, quadratisch wirkendes Mass
       reduziert statt des asymmetrischen Text+Icon-Paddings. */
    .landing-demo-btn span {
        display: none;
    }

    .landing-demo-btn {
        gap: 0;
        width: 32px;
        padding: 0;
        justify-content: center;
    }

    .landing-hero-title {
        font-size: 32px;
    }

    /* Leicht verkleinert (17px -\u003E 15px), konsistent mit der Verkleinerung
       von Logo/Titel/Buttons im selben Breakpoint - bleibt aber bewusst
       deutlich groesser/lesbarer als die generischen Section-Untertexte
       (siehe .landing-section-sub oben), da der Hero-Lead die zentrale
       Einstiegsaussage der Seite ist. */
    .landing-hero-lead {
        font-size: 15px;
    }

    /* Etwas groesserer Faktor als das reine Logo/Ueberschrift-Verhaeltnis
       (0.727), da die Buttons bei diesem Faktor zu klein/schwer lesbar
       wirkten: Hoehe 48px -> 40px, horizontales Padding 22px -> 18px,
       Schrift 15px -> 13px. */
    .landing-btn-primary,
    .landing-btn-secondary {
        height: 40px;
        padding: 0 18px;
        font-size: 13px;
        gap: 7px;
    }

    /* Hero-CTAs gestapelt statt nebeneinander: Verlauf dreht daher von
       horizontal (90deg, Desktop) auf vertikal (180deg) - bleibt so auch
       gestapelt optisch als ein fortlaufender Verlauf ueber beide Buttons
       hinweg erkennbar (siehe .landing-btn-primary/.landing-btn-secondary). */
    .landing-hero-ctas {
        flex-direction: column;
        align-items: center;
    }

    .landing-btn-primary,
    .landing-btn-secondary {
        justify-content: center;
    }

    .landing-btn-primary,
    .landing-btn-primary:hover {
        background: linear-gradient(180deg, var(--landing-accent), color-mix(in srgb, var(--landing-accent) 55%, var(--landing-secondary)));
    }

    .landing-btn-primary:hover {
        background: linear-gradient(180deg, var(--landing-accent-dark), color-mix(in srgb, var(--landing-accent-dark) 55%, var(--landing-secondary-dark)));
    }

    .landing-btn-secondary,
    .landing-btn-secondary:hover {
        background: linear-gradient(180deg, color-mix(in srgb, var(--landing-secondary) 55%, var(--landing-accent)), var(--landing-secondary));
    }

    .landing-btn-secondary:hover {
        background: linear-gradient(180deg, color-mix(in srgb, var(--landing-secondary-dark) 55%, var(--landing-accent-dark)), var(--landing-secondary-dark));
    }

    /* Mockup-Slider auf Mobile: die Slide wird IMMER als eine Spalte
       gestapelt (Bild oben, "col" = Text + Dots darunter), unabhaengig
       davon, ob eine Slide auf Desktop "links"/"rechts"/"center" layoutet
       ist. Der Rahmen bekommt eine flachere, an der Viewport-Hoehe
       orientierte Groesse statt der festen 420px-Desktop-Hoehe. */
    .landing-media-slider-row {
        gap: 8px;
    }

    .landing-media-slide[data-layout] {
        grid-template-columns: 1fr;
        grid-template-rows: auto auto;
        grid-template-areas:
            "media"
            "col";
        gap: 16px;
    }

    .landing-media-slide[data-layout] .landing-media-slide-media {
        height: clamp(200px, 34vh, 300px);
        width: 100%;
    }

    .landing-media-slide-textcol {
        max-width: 100%;
        align-items: center;
    }

    .landing-media-slide-text {
        text-align: center;
    }

    .landing-media-slide-text h3 {
        font-size: 21px;
    }


    /* ===== "Geplante KI-Funktionen" (#ki-funktionen) auf Mobile =====
       Ueberschrift/Untertext dieser Section liegen NICHT in
       .landing-section-intro (das generische Muster gilt nur fuer die
       zentrierten Ein-Spalten-Sections), sondern in .landing-hub-text -
       daher eigener, etwas kleinerer Override statt der generischen
       .landing-section-intro h2/.landing-section-sub-Werte von oben. */
    .landing-hub-text h2 {
        font-size: 22px;
    }

    .landing-hub-text .landing-section-sub {
        font-size: 14.5px;
    }

    /* Hub-Zeilen (anklickbare Roadmap-Liste links) kompakter: kleineres
       Icon, engeres Padding/Gap sowie kleinere Titel-/Beschreibungsschrift,
       damit die drei Zeilen auf schmalen Screens nicht zu viel Hoehe
       beanspruchen, bevor das Ticket-Mockup darunter folgt. */
    .landing-hub-row {
        gap: 10px;
        padding: 11px 2px;
    }

    .landing-hub-row > svg:not(.landing-hub-row-chevron) {
        width: 20px;
        height: 20px;
        flex-shrink: 0;
    }

    .landing-hub-row-text h4 {
        font-size: 14px;
    }

    .landing-hub-row-text p {
        font-size: 12.5px;
    }

    .landing-hub-row-chevron {
        width: 16px;
        height: 16px;
    }

    /* Ticket-Mockup: auf Mobile volle verfuegbare Breite statt der festen
       340px-Desktop-Breite, damit es nicht schmaler wirkt als die Hub-Liste
       darueber, bleibt aber weiterhin zentriert (siehe .landing-hub-visual
       justify-content:center). */
    .landing-hub-visual {
        flex-basis: 100%;
        min-width: 0;
    }

    .landing-ticket-mock {
        max-width: 420px;
    }
}

/* ===== Abschluss-CTA #demo (Konzept: .final-cta/.final-cta-grid/.final-cta-col
   aus Konzept/vylife-landingpage-neu.html, 1:1 uebernommen) =====
   Wie alle anderen Sections ein direktes Kind von .landing-scroll-area mit
   min-height:100dvh (siehe ".landing-scroll-area > section"), daher hier
   bewusst KEIN eigenes background/border-top/border-bottom mehr wie im
   Prototyp (der dort mit fluessiger Seitenhoehe statt fixer Sections
   arbeitet) - der einheitliche --landing-bg-Hintergrund kommt weiterhin von
   .landing-scroll-area, damit kein Farbbruch zu den Nachbar-Sections
   entsteht. */
.landing-final-cta {
    display: flex;
    align-items: center;
    justify-content: center;
    padding-inline: 32px;
}

.landing-final-cta-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 48px;
    max-width: 900px;
    width: 100%;
    margin: 0 auto;
    text-align: left;
}

.landing-final-cta-col {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}

.landing-final-cta-col h2 {
    margin: 0 0 14px;
    font-size: 24px;
    font-weight: 700;
    color: var(--landing-text);
}

.landing-final-cta-col p {
    margin: 0 0 24px;
    font-size: 15.5px;
    line-height: 1.6;
    color: var(--landing-text-muted);
}

.landing-final-cta-col .landing-btn-primary,
.landing-final-cta-col .landing-btn-secondary {
    margin-top: auto;
    text-decoration: none;
}

@media (max-width: 700px) {
    .landing-final-cta-grid {
        grid-template-columns: 1fr;
        gap: 40px;
    }
}

/* ===== Kontakt-Dialog (LandingContactDialog.razor) =====
   Eigenstaendig statt FormDialog-Wiederverwendung, siehe Kommentar in
   LandingContactDialog.razor: die Landingpage soll spaeter als reine
   HTML/CSS/JS-Kopie exportierbar bleiben. */
.landing-contact-overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: color-mix(in srgb, var(--landing-text) 45%, transparent);
    backdrop-filter: blur(6px);
    animation: landing-contact-overlay-fade .2s ease;
}

.landing-contact-dialog {
    position: relative;
    width: 100%;
    max-width: 440px;
    max-height: calc(100vh - 40px);
    overflow-y: auto;
    background: var(--landing-bg);
    border: 1px solid var(--landing-border);
    border-radius: var(--landing-radius);
    box-shadow: 0 24px 60px rgba(0, 0, 0, .35);
    display: flex;
    flex-direction: column;
    animation: landing-contact-dialog-pop .32s cubic-bezier(.34, 1.56, .64, 1);
    transform-origin: center;
}

@keyframes landing-contact-overlay-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* Ploppeffekt: leichtes Ueberschwingen (Overshoot) statt reinem Scale-In,
   analog zu .landing-status-bubble (landing-status-badge-pop). */
@keyframes landing-contact-dialog-pop {
    0% { transform: scale(.7); opacity: 0; }
    55% { transform: scale(1.04); opacity: 1; }
    80% { transform: scale(.98); }
    100% { transform: scale(1); }
}

/* Gradient-Kopfband analog .landing-feature-card-header/.landing-ticket-top:
   Icon + Titel in Weiss auf dem Accent-Verlauf statt neutralem Kartenkopf. */
.landing-contact-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 18px 52px 18px 22px;
    background: linear-gradient(90deg, var(--landing-accent), var(--landing-secondary));
    border-radius: var(--landing-radius) var(--landing-radius) 0 0;
}

.landing-contact-header svg {
    display: block;
    width: 24px;
    height: 24px;
    flex-shrink: 0;
}

.landing-contact-header h3 {
    margin: 0;
    font-size: 17px;
    font-weight: 700;
    line-height: 1.3;
    color: #fff;
}

.landing-contact-body {
    padding: 20px 22px 22px;
}

.landing-contact-close {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: none;
    border-radius: var(--landing-radius-sm);
    background: transparent;
    cursor: pointer;
    transition: background-color .15s ease-in-out;
}

.landing-contact-close:hover {
    background: color-mix(in srgb, #fff 20%, transparent);
}

.landing-contact-lead {
    margin: 0 0 18px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--landing-text-muted);
}

.landing-contact-field {
    display: flex;
    flex-direction: column;
    gap: 5px;
    margin-bottom: 12px;
}

.landing-contact-field label {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--landing-text-muted);
}

.landing-contact-required {
    color: var(--landing-accent);
}

.landing-contact-field input,
.landing-contact-field textarea {
    box-sizing: border-box;
    width: 100%;
    padding: 9px 11px;
    font-size: 13.5px;
    font-family: inherit;
    color: var(--landing-text);
    background: color-mix(in srgb, var(--landing-text) 4%, var(--landing-bg));
    border: 1px solid var(--landing-border);
    border-radius: var(--landing-radius-sm);
    resize: vertical;
}

.landing-contact-field input:focus,
.landing-contact-field textarea:focus {
    outline: none;
    border-color: var(--landing-accent);
}

.landing-contact-error {
    margin: 0 0 12px;
    font-size: 13px;
    color: #d92d20;
}

.landing-contact-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 6px;
}

.landing-contact-actions .landing-btn-primary,
.landing-contact-actions .landing-btn-secondary {
    height: 38px;
    font-size: 13.5px;
}

.landing-contact-success {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 8px;
    padding: 8px 0 4px;
}

.landing-contact-success h4 {
    margin: 4px 0 0;
    font-size: 17px;
    font-weight: 700;
    color: var(--landing-text);
}

.landing-contact-success p {
    margin: 0 0 14px;
    font-size: 13.5px;
    color: var(--landing-text-muted);
}

@media (max-width: 480px) {
    .landing-contact-header {
        padding: 16px 48px 16px 18px;
    }

    .landing-contact-body {
        padding: 18px 18px 20px;
    }

    .landing-contact-actions {
        flex-direction: column-reverse;
    }

    .landing-contact-actions .landing-btn-primary,
    .landing-contact-actions .landing-btn-secondary {
        width: 100%;
        justify-content: center;
    }
}
