Vorschau Hero: Video vollstaendig sichtbar + Endcard mit CTA am Ende

Umgebaut zu Video-getriebenem Slider mit Endcard-Phase:
- Video object-fit: contain (komplett sichtbar, Navy-Letterbox-Raender)
- Waehrend Video-Laufzeit: keine Overlays (Video spricht fuer sich)
- ended-Event triggert .ended/.endcard-Klassen -> 3s Endcard
- Endcard zeigt Titel + Tagline (zentriert) + Beispieltext + CTA
- Slide 2 ohne CTA: Endcard zeigt nur Titel + Tagline
- loop-Attribut aus allen 5 Videos entfernt (sonst feuert ended nicht)
- Festes 15s-Autoplay entfernt; Slide-Wechsel ist video-getrieben
- Fallback-Timer 25s falls ended-Event nicht kommt (Ladefehler etc.)
- Manuelle Navigation (Dots/Pfeile/Swipe) cleant alle Timer sofort
- Tab-Wechsel pausiert/resumt korrekt im jeweiligen Zustand

Rollback-Punkt: c693114
Dieser Commit ist enthalten in:
Claude Code
2026-04-21 01:28:42 +02:00
Ursprung c6931142e7
Commit c85be47307
3 geänderte Dateien mit 104 neuen und 71 gelöschten Zeilen

Datei anzeigen

@@ -60,18 +60,19 @@ a { color:inherit; text-decoration:none; }
.mobile-overlay { position:fixed; inset:0; background:rgba(10,24,50,0.3); z-index:998; opacity:0; pointer-events:none; transition:opacity 0.3s; } .mobile-overlay { position:fixed; inset:0; background:rgba(10,24,50,0.3); z-index:998; opacity:0; pointer-events:none; transition:opacity 0.3s; }
.mobile-overlay.open { opacity:1; pointer-events:all; } .mobile-overlay.open { opacity:1; pointer-events:all; }
/* ==================== HERO (Full-Width Video) ==================== */ /* ==================== HERO (Full-Video mit Endcard) ==================== */
.hero { position:relative; min-height:88vh; overflow:hidden; background:var(--navy); clip-path:polygon(0 0, 100% 0, 100% calc(100% - 60px), 50% 100%, 0 calc(100% - 60px)); margin-bottom:-60px; z-index:1; } .hero { position:relative; min-height:88vh; overflow:hidden; background:var(--navy); clip-path:polygon(0 0, 100% 0, 100% calc(100% - 60px), 50% 100%, 0 calc(100% - 60px)); margin-bottom:-60px; z-index:1; }
.gold { color:var(--gold); font-weight:600; } .gold { color:var(--gold); font-weight:600; }
/* Overlay-Layer für Text + Navigation, über dem Video-Slider */ /* Overlay-Layer für Text + Navigation */
.hero-content { position:absolute; inset:0; z-index:4; color:var(--white); pointer-events:none; } .hero-content { position:absolute; inset:0; z-index:4; color:var(--white); pointer-events:none; }
.hero-content > * { pointer-events:auto; } .hero-content > * { pointer-events:auto; }
/* Brand (Titel + Tagline) als Overlay oben, über dem Top-Gradient */ /* Brand (Titel + Tagline): nur während Endcard sichtbar, in Hero-Mitte */
.hero-brand { position:absolute; top:calc(var(--nav-height) + 40px); left:0; right:0; padding:0 24px; text-align:center; } .hero-brand { position:absolute; top:50%; left:0; right:0; padding:0 24px; text-align:center; transform:translateY(-50%); opacity:0; transition:opacity 0.5s ease; pointer-events:none; }
.hero-title { font-size:3rem; font-weight:700; line-height:1.1; letter-spacing:-0.02em; color:var(--white); margin:0; text-shadow:0 2px 20px rgba(0,0,0,0.55); } .hero.endcard .hero-brand { opacity:1; transition-delay:0.35s; pointer-events:auto; }
.hero-tagline { font-size:1.15rem; font-weight:300; color:rgba(255,255,255,0.95); margin-top:12px; text-shadow:0 1px 16px rgba(0,0,0,0.55); } .hero-title { font-size:3.2rem; font-weight:700; line-height:1.1; letter-spacing:-0.02em; color:var(--white); margin:0; }
.hero-tagline { font-size:1.2rem; font-weight:300; color:rgba(255,255,255,0.9); margin-top:12px; }
/* ==================== HERO SLIDER ==================== */ /* ==================== HERO SLIDER ==================== */
.hero-slider { position:absolute; inset:0; z-index:1; } .hero-slider { position:absolute; inset:0; z-index:1; }
@@ -79,43 +80,32 @@ a { color:inherit; text-decoration:none; }
.hero-slide.active { opacity:1; pointer-events:auto; } .hero-slide.active { opacity:1; pointer-events:auto; }
.hero-slide.exiting { opacity:0; transition:opacity 0.4s ease; } .hero-slide.exiting { opacity:0; transition:opacity 0.4s ease; }
/* Video füllt den gesamten Slide */ /* Video füllt den Slide (contain = komplett sichtbar, Navy-Letterbox) */
.hero-slide-video { position:absolute; inset:0; overflow:hidden; } .hero-slide-video { position:absolute; inset:0; overflow:hidden; transition:opacity 0.4s ease; }
.hero-slide-video video { display:block; width:100%; height:100%; object-fit:cover; } .hero-slide-video video { display:block; width:100%; height:100%; object-fit:contain; background:var(--navy); }
/* Gradient über dem Video: dunkel oben/unten, klar in der Mitte (Safe-Zone) */ /* Beim Endcard-State Video ausfaden */
.hero-slide-video::after { .hero-slide.ended .hero-slide-video { opacity:0; }
content:'';
position:absolute;
inset:0;
pointer-events:none;
background:linear-gradient(to bottom,
rgba(10,24,50,0.72) 0%,
rgba(10,24,50,0.20) 18%,
rgba(10,24,50,0) 42%,
rgba(10,24,50,0) 58%,
rgba(10,24,50,0.55) 82%,
rgba(10,24,50,0.92) 100%);
}
/* Per-Slide-Bottom (Beispieltext + CTA) als Overlay unten, über dem Bottom-Gradient */ /* Per-Slide-Bottom (Beispieltext + CTA): nur während Endcard sichtbar, unter dem Titel */
.hero-slide-bottom { position:absolute; left:0; right:0; bottom:130px; padding:0 32px; text-align:center; } .hero-slide-bottom { position:absolute; left:0; right:0; bottom:140px; padding:0 32px; text-align:center; opacity:0; transition:opacity 0.5s ease; pointer-events:none; }
.hero-slide-example { font-size:1.1rem; font-weight:400; line-height:1.55; color:var(--white); margin:0 auto 22px; max-width:820px; padding:0; border:0; opacity:1; text-shadow:0 1px 14px rgba(0,0,0,0.65); } .hero-slide.ended .hero-slide-bottom { opacity:1; transition-delay:0.5s; pointer-events:auto; }
.hero-slide-example { font-size:1.15rem; font-weight:400; line-height:1.55; color:rgba(255,255,255,0.9); margin:0 auto 24px; max-width:820px; padding:0; border:0; }
.hero-slide-cta { display:flex; gap:16px; flex-wrap:wrap; justify-content:center; } .hero-slide-cta { display:flex; gap:16px; flex-wrap:wrap; justify-content:center; }
.hero-slide-cta .btn-placeholder { opacity:0.5; cursor:default; border-style:dashed; pointer-events:none; } .hero-slide-cta .btn-placeholder { opacity:0.5; cursor:default; border-style:dashed; pointer-events:none; }
/* Slider-Navigation: Dots zentriert unten, Pfeile seitlich auf Hero-Mitte */ /* Slider-Navigation: Dots zentriert unten, Pfeile seitlich auf Hero-Mitte. Immer sichtbar. */
.hero-slider-nav { position:absolute; left:0; right:0; bottom:75px; display:flex; justify-content:center; padding:0 24px; pointer-events:none; } .hero-slider-nav { position:absolute; left:0; right:0; bottom:75px; display:flex; justify-content:center; padding:0 24px; pointer-events:none; z-index:5; }
.hero-slider-dots { display:flex; gap:12px; pointer-events:auto; } .hero-slider-dots { display:flex; gap:12px; pointer-events:auto; }
.hero-dot { width:10px; height:10px; border-radius:50%; border:2px solid var(--gold); background:transparent; cursor:pointer; transition:all 0.3s; padding:0; } .hero-dot { width:10px; height:10px; border-radius:50%; border:2px solid var(--gold); background:transparent; cursor:pointer; transition:all 0.3s; padding:0; }
.hero-dot.active { background:var(--gold); } .hero-dot.active { background:var(--gold); }
.hero-slider-arrows { /* Container - Pfeile sind absolut auf Hero positioniert */ } .hero-slider-arrows { /* Container - Pfeile positionieren sich absolut relativ zu hero-content */ }
.hero-arrow { position:absolute; top:50%; transform:translateY(-50%); width:48px; height:48px; border-radius:50%; border:1px solid rgba(255,255,255,0.4); background:rgba(10,24,50,0.4); color:var(--white); font-size:1.2rem; cursor:pointer; display:flex; align-items:center; justify-content:center; transition:all 0.2s; backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px); } .hero-arrow { position:absolute; top:50%; transform:translateY(-50%); width:48px; height:48px; border-radius:50%; border:1px solid rgba(255,255,255,0.35); background:rgba(10,24,50,0.35); color:var(--white); font-size:1.2rem; cursor:pointer; display:flex; align-items:center; justify-content:center; transition:all 0.2s; backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px); z-index:5; }
.hero-arrow:hover { border-color:var(--gold); color:var(--gold); background:rgba(10,24,50,0.6); } .hero-arrow:hover { border-color:var(--gold); color:var(--gold); background:rgba(10,24,50,0.6); }
.hero-arrow-prev { left:24px; } .hero-arrow-prev { left:24px; }
.hero-arrow-next { right:24px; } .hero-arrow-next { right:24px; }
/* Altes hero-overlay wird nicht mehr gebraucht (Gradient ist jetzt im Video-Layer) */ /* Altes hero-overlay nicht mehr verwendet */
.hero-overlay { display:none; } .hero-overlay { display:none; }
/* ==================== BUTTONS ==================== */ /* ==================== BUTTONS ==================== */
@@ -314,7 +304,7 @@ a { color:inherit; text-decoration:none; }
.mobile-menu-toggle { display:flex; } .mobile-menu-toggle { display:flex; }
.grid-3,.grid-4 { grid-template-columns:1fr; gap:20px; } .grid-3,.grid-4 { grid-template-columns:1fr; gap:20px; }
.hero { min-height:75vh; } .hero { min-height:75vh; }
.hero-brand { top:calc(var(--nav-height) + 24px); padding:0 20px; } .hero-brand { padding:0 20px; }
.hero-title { font-size:1.9rem; } .hero-title { font-size:1.9rem; }
.hero-tagline { font-size:0.95rem; margin-top:8px; } .hero-tagline { font-size:0.95rem; margin-top:8px; }
.hero-slide-bottom { bottom:110px; padding:0 20px; } .hero-slide-bottom { bottom:110px; padding:0 20px; }

Datei anzeigen

@@ -91,7 +91,7 @@
<!-- Slide 1: Echtzeit-Monitoring (Video) --> <!-- Slide 1: Echtzeit-Monitoring (Video) -->
<div class="hero-slide active" data-slide="0"> <div class="hero-slide active" data-slide="0">
<div class="hero-slide-video"> <div class="hero-slide-video">
<video muted loop playsinline preload="auto"> <video muted playsinline preload="auto">
<source src="videos/hero-slide-1-monitoring.mp4" type="video/mp4"> <source src="videos/hero-slide-1-monitoring.mp4" type="video/mp4">
</video> </video>
</div> </div>
@@ -106,7 +106,7 @@
<!-- Slide 2: Automatischer Faktencheck (Video) --> <!-- Slide 2: Automatischer Faktencheck (Video) -->
<div class="hero-slide" data-slide="1"> <div class="hero-slide" data-slide="1">
<div class="hero-slide-video"> <div class="hero-slide-video">
<video muted loop playsinline preload="metadata"> <video muted playsinline preload="metadata">
<source src="videos/hero-slide-2-monitoring.mp4?v=3" type="video/mp4"> <source src="videos/hero-slide-2-monitoring.mp4?v=3" type="video/mp4">
</video> </video>
</div> </div>
@@ -115,7 +115,7 @@
<!-- Slide 3: KI-Recherche (Video) --> <!-- Slide 3: KI-Recherche (Video) -->
<div class="hero-slide" data-slide="2"> <div class="hero-slide" data-slide="2">
<div class="hero-slide-video"> <div class="hero-slide-video">
<video muted loop playsinline preload="metadata"> <video muted playsinline preload="metadata">
<source src="videos/hero-slide-3-monitoring.mp4?v=2" type="video/mp4"> <source src="videos/hero-slide-3-monitoring.mp4?v=2" type="video/mp4">
</video> </video>
</div> </div>
@@ -130,7 +130,7 @@
<!-- Slide 4: Globale Quellenabdeckung (Video) --> <!-- Slide 4: Globale Quellenabdeckung (Video) -->
<div class="hero-slide" data-slide="3"> <div class="hero-slide" data-slide="3">
<div class="hero-slide-video"> <div class="hero-slide-video">
<video muted loop playsinline preload="metadata"> <video muted playsinline preload="metadata">
<source src="videos/hero-slide-4-monitoring.mp4" type="video/mp4"> <source src="videos/hero-slide-4-monitoring.mp4" type="video/mp4">
</video> </video>
</div> </div>
@@ -145,7 +145,7 @@
<!-- Slide 5: Flexibel einsetzbar (Video) --> <!-- Slide 5: Flexibel einsetzbar (Video) -->
<div class="hero-slide" data-slide="4"> <div class="hero-slide" data-slide="4">
<div class="hero-slide-video"> <div class="hero-slide-video">
<video muted loop playsinline preload="metadata"> <video muted playsinline preload="metadata">
<source src="videos/hero-slide-5-monitoring.mp4?v=2" type="video/mp4"> <source src="videos/hero-slide-5-monitoring.mp4?v=2" type="video/mp4">
</video> </video>
</div> </div>

Datei anzeigen

@@ -41,13 +41,21 @@
}); });
}); });
/* ==================== HERO SLIDER ==================== */ /* ==================== HERO SLIDER (video-driven mit Endcard) ==================== */
var heroEl = document.querySelector('.hero');
var heroSlides = document.querySelectorAll('.hero-slide'); var heroSlides = document.querySelectorAll('.hero-slide');
var heroDots = document.querySelectorAll('.hero-dot'); var heroDots = document.querySelectorAll('.hero-dot');
var heroCurrentSlide = 0; var heroCurrentSlide = 0;
var heroTimer = null; var heroEndcardTimer = null;
var HERO_INTERVAL = 15000; var heroFallbackTimer = null;
var heroIsTransitioning = false; var heroIsTransitioning = false;
var HERO_ENDCARD_MS = 3000;
var HERO_FALLBACK_MS = 25000;
function heroClearTimers() {
if (heroEndcardTimer) { clearTimeout(heroEndcardTimer); heroEndcardTimer = null; }
if (heroFallbackTimer) { clearTimeout(heroFallbackTimer); heroFallbackTimer = null; }
}
function heroPlaySlideVideo(slide) { function heroPlaySlideVideo(slide) {
var v = slide && slide.querySelector('video'); var v = slide && slide.querySelector('video');
@@ -62,16 +70,43 @@
if (v) v.pause(); if (v) v.pause();
} }
function heroEnterEndcard() {
if (!heroSlides.length) return;
var slide = heroSlides[heroCurrentSlide];
if (!slide || slide.classList.contains('ended')) return;
slide.classList.add('ended');
if (heroEl) heroEl.classList.add('endcard');
heroClearTimers();
heroEndcardTimer = setTimeout(function () {
heroEndcardTimer = null;
heroNext();
}, HERO_ENDCARD_MS);
}
function heroStartSlide() {
var slide = heroSlides[heroCurrentSlide];
if (!slide) return;
slide.classList.remove('ended');
if (heroEl) heroEl.classList.remove('endcard');
heroPlaySlideVideo(slide);
heroClearTimers();
heroFallbackTimer = setTimeout(function () {
heroFallbackTimer = null;
heroEnterEndcard();
}, HERO_FALLBACK_MS);
}
function heroGoTo(index) { function heroGoTo(index) {
if (heroIsTransitioning || index === heroCurrentSlide || !heroSlides.length) return; if (heroIsTransitioning || index === heroCurrentSlide || !heroSlides.length) return;
heroIsTransitioning = true; heroIsTransitioning = true;
heroClearTimers();
var oldIndex = heroCurrentSlide; var oldIndex = heroCurrentSlide;
heroSlides[oldIndex].classList.add('exiting'); heroSlides[oldIndex].classList.add('exiting');
heroSlides[oldIndex].classList.remove('active'); heroSlides[oldIndex].classList.remove('active', 'ended');
if (heroEl) heroEl.classList.remove('endcard');
if (heroDots[oldIndex]) heroDots[oldIndex].classList.remove('active'); if (heroDots[oldIndex]) heroDots[oldIndex].classList.remove('active');
// Altes Video sofort pausieren, damit es während des Fade-Outs nicht mehr läuft
heroPauseSlideVideo(heroSlides[oldIndex]); heroPauseSlideVideo(heroSlides[oldIndex]);
setTimeout(function () { setTimeout(function () {
@@ -79,10 +114,7 @@
heroCurrentSlide = index; heroCurrentSlide = index;
heroSlides[heroCurrentSlide].classList.add('active'); heroSlides[heroCurrentSlide].classList.add('active');
if (heroDots[heroCurrentSlide]) heroDots[heroCurrentSlide].classList.add('active'); if (heroDots[heroCurrentSlide]) heroDots[heroCurrentSlide].classList.add('active');
heroStartSlide();
// Neues Video von Anfang starten, sobald der Slide sichtbar wird
heroPlaySlideVideo(heroSlides[heroCurrentSlide]);
heroIsTransitioning = false; heroIsTransitioning = false;
}, 400); }, 400);
} }
@@ -95,55 +127,66 @@
heroGoTo((heroCurrentSlide - 1 + heroSlides.length) % heroSlides.length); heroGoTo((heroCurrentSlide - 1 + heroSlides.length) % heroSlides.length);
} }
function heroStartAutoplay() { // Pro Video: 'ended' → Endcard-Phase starten
heroStopAutoplay(); heroSlides.forEach(function (slide) {
heroTimer = setTimeout(function tick() { var v = slide.querySelector('video');
heroNext(); if (!v) return;
heroTimer = setTimeout(tick, HERO_INTERVAL); v.addEventListener('ended', function () {
}, HERO_INTERVAL); if (slide.classList.contains('active')) heroEnterEndcard();
} });
});
function heroStopAutoplay() {
if (heroTimer) { clearInterval(heroTimer); heroTimer = null; }
}
heroDots.forEach(function (dot, i) { heroDots.forEach(function (dot, i) {
dot.addEventListener('click', function () { dot.addEventListener('click', function () { heroGoTo(i); });
heroGoTo(i);
heroStartAutoplay();
});
}); });
var heroPrevBtn = document.querySelector('.hero-arrow-prev'); var heroPrevBtn = document.querySelector('.hero-arrow-prev');
var heroNextBtn = document.querySelector('.hero-arrow-next'); var heroNextBtn = document.querySelector('.hero-arrow-next');
if (heroPrevBtn) heroPrevBtn.addEventListener('click', function () { heroPrev(); heroStartAutoplay(); }); if (heroPrevBtn) heroPrevBtn.addEventListener('click', heroPrev);
if (heroNextBtn) heroNextBtn.addEventListener('click', function () { heroNext(); heroStartAutoplay(); }); if (heroNextBtn) heroNextBtn.addEventListener('click', heroNext);
var heroSlider = document.querySelector('.hero-slider'); var heroSlider = document.querySelector('.hero-slider');
if (heroSlider) { if (heroSlider) {
var heroTouchStartX = 0; var heroTouchStartX = 0;
heroSlider.addEventListener('touchstart', function (e) { heroSlider.addEventListener('touchstart', function (e) {
heroTouchStartX = e.changedTouches[0].screenX; heroTouchStartX = e.changedTouches[0].screenX;
heroStopAutoplay();
}, { passive: true }); }, { passive: true });
heroSlider.addEventListener('touchend', function (e) { heroSlider.addEventListener('touchend', function (e) {
var diff = e.changedTouches[0].screenX - heroTouchStartX; var diff = e.changedTouches[0].screenX - heroTouchStartX;
if (Math.abs(diff) > 50) { if (Math.abs(diff) > 50) {
if (diff < 0) heroNext(); else heroPrev(); if (diff < 0) heroNext(); else heroPrev();
} }
heroStartAutoplay();
}, { passive: true }); }, { passive: true });
} }
document.addEventListener('visibilitychange', function () { document.addEventListener('visibilitychange', function () {
if (document.hidden) { heroStopAutoplay(); } var slide = heroSlides[heroCurrentSlide];
else { heroStartAutoplay(); } if (!slide) return;
if (document.hidden) {
heroClearTimers();
heroPauseSlideVideo(slide);
return;
}
if (slide.classList.contains('ended')) {
heroEndcardTimer = setTimeout(function () {
heroEndcardTimer = null;
heroNext();
}, HERO_ENDCARD_MS);
} else {
var v = slide.querySelector('video');
if (v) {
var p = v.play();
if (p && typeof p.catch === 'function') p.catch(function () {});
}
heroFallbackTimer = setTimeout(function () {
heroFallbackTimer = null;
heroEnterEndcard();
}, HERO_FALLBACK_MS);
}
}); });
if (heroSlides.length > 1) heroStartAutoplay(); // Initialer Start (Slide 0 ist bereits .active im HTML)
if (heroSlides.length) heroStartSlide();
// Initialer Video-Start für Slide 0 (ersetzt das weggefallene autoplay-Attribut)
if (heroSlides.length) heroPlaySlideVideo(heroSlides[0]);
/* ==================== MAP STATE ==================== */ /* ==================== MAP STATE ==================== */
var mapInstance = null; var mapInstance = null;