diff --git a/vorschau/css/style.css b/vorschau/css/style.css index 0ae41ca..9d1570b 100644 --- a/vorschau/css/style.css +++ b/vorschau/css/style.css @@ -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.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; } .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 > * { pointer-events:auto; } -/* Brand (Titel + Tagline) als Overlay oben, über dem Top-Gradient */ -.hero-brand { position:absolute; top:calc(var(--nav-height) + 40px); left:0; right:0; padding:0 24px; text-align:center; } -.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-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); } +/* Brand (Titel + Tagline): nur während Endcard sichtbar, in Hero-Mitte */ +.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.endcard .hero-brand { opacity:1; transition-delay:0.35s; pointer-events:auto; } +.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 { 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.exiting { opacity:0; transition:opacity 0.4s ease; } -/* Video füllt den gesamten Slide */ -.hero-slide-video { position:absolute; inset:0; overflow:hidden; } -.hero-slide-video video { display:block; width:100%; height:100%; object-fit:cover; } -/* Gradient über dem Video: dunkel oben/unten, klar in der Mitte (Safe-Zone) */ -.hero-slide-video::after { - 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%); -} +/* Video füllt den Slide (contain = komplett sichtbar, Navy-Letterbox) */ +.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:contain; background:var(--navy); } +/* Beim Endcard-State Video ausfaden */ +.hero-slide.ended .hero-slide-video { opacity:0; } -/* Per-Slide-Bottom (Beispieltext + CTA) als Overlay unten, über dem Bottom-Gradient */ -.hero-slide-bottom { position:absolute; left:0; right:0; bottom:130px; padding:0 32px; text-align:center; } -.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); } +/* Per-Slide-Bottom (Beispieltext + CTA): nur während Endcard sichtbar, unter dem Titel */ +.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.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 .btn-placeholder { opacity:0.5; cursor:default; border-style:dashed; pointer-events:none; } -/* Slider-Navigation: Dots zentriert unten, Pfeile seitlich auf Hero-Mitte */ -.hero-slider-nav { position:absolute; left:0; right:0; bottom:75px; display:flex; justify-content:center; padding:0 24px; pointer-events:none; } +/* 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; z-index:5; } .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.active { background:var(--gold); } -.hero-slider-arrows { /* Container - Pfeile sind absolut auf Hero positioniert */ } -.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-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.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-prev { left: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; } /* ==================== BUTTONS ==================== */ @@ -314,7 +304,7 @@ a { color:inherit; text-decoration:none; } .mobile-menu-toggle { display:flex; } .grid-3,.grid-4 { grid-template-columns:1fr; gap:20px; } .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-tagline { font-size:0.95rem; margin-top:8px; } .hero-slide-bottom { bottom:110px; padding:0 20px; } diff --git a/vorschau/index.html b/vorschau/index.html index a9b95f8..c6a21dc 100644 --- a/vorschau/index.html +++ b/vorschau/index.html @@ -91,7 +91,7 @@
-
@@ -106,7 +106,7 @@
-
@@ -115,7 +115,7 @@
-
@@ -130,7 +130,7 @@
-
@@ -145,7 +145,7 @@
-
diff --git a/vorschau/js/app.js b/vorschau/js/app.js index 4f15281..fe2ccd9 100644 --- a/vorschau/js/app.js +++ b/vorschau/js/app.js @@ -41,13 +41,21 @@ }); }); - /* ==================== HERO SLIDER ==================== */ + /* ==================== HERO SLIDER (video-driven mit Endcard) ==================== */ + var heroEl = document.querySelector('.hero'); var heroSlides = document.querySelectorAll('.hero-slide'); var heroDots = document.querySelectorAll('.hero-dot'); var heroCurrentSlide = 0; - var heroTimer = null; - var HERO_INTERVAL = 15000; + var heroEndcardTimer = null; + var heroFallbackTimer = null; 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) { var v = slide && slide.querySelector('video'); @@ -62,16 +70,43 @@ 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) { if (heroIsTransitioning || index === heroCurrentSlide || !heroSlides.length) return; heroIsTransitioning = true; + heroClearTimers(); var oldIndex = heroCurrentSlide; 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'); - // Altes Video sofort pausieren, damit es während des Fade-Outs nicht mehr läuft heroPauseSlideVideo(heroSlides[oldIndex]); setTimeout(function () { @@ -79,10 +114,7 @@ heroCurrentSlide = index; heroSlides[heroCurrentSlide].classList.add('active'); if (heroDots[heroCurrentSlide]) heroDots[heroCurrentSlide].classList.add('active'); - - // Neues Video von Anfang starten, sobald der Slide sichtbar wird - heroPlaySlideVideo(heroSlides[heroCurrentSlide]); - + heroStartSlide(); heroIsTransitioning = false; }, 400); } @@ -95,55 +127,66 @@ heroGoTo((heroCurrentSlide - 1 + heroSlides.length) % heroSlides.length); } - function heroStartAutoplay() { - heroStopAutoplay(); - heroTimer = setTimeout(function tick() { - heroNext(); - heroTimer = setTimeout(tick, HERO_INTERVAL); - }, HERO_INTERVAL); - } - - function heroStopAutoplay() { - if (heroTimer) { clearInterval(heroTimer); heroTimer = null; } - } + // Pro Video: 'ended' → Endcard-Phase starten + heroSlides.forEach(function (slide) { + var v = slide.querySelector('video'); + if (!v) return; + v.addEventListener('ended', function () { + if (slide.classList.contains('active')) heroEnterEndcard(); + }); + }); heroDots.forEach(function (dot, i) { - dot.addEventListener('click', function () { - heroGoTo(i); - heroStartAutoplay(); - }); + dot.addEventListener('click', function () { heroGoTo(i); }); }); var heroPrevBtn = document.querySelector('.hero-arrow-prev'); var heroNextBtn = document.querySelector('.hero-arrow-next'); - if (heroPrevBtn) heroPrevBtn.addEventListener('click', function () { heroPrev(); heroStartAutoplay(); }); - if (heroNextBtn) heroNextBtn.addEventListener('click', function () { heroNext(); heroStartAutoplay(); }); + if (heroPrevBtn) heroPrevBtn.addEventListener('click', heroPrev); + if (heroNextBtn) heroNextBtn.addEventListener('click', heroNext); var heroSlider = document.querySelector('.hero-slider'); if (heroSlider) { var heroTouchStartX = 0; heroSlider.addEventListener('touchstart', function (e) { heroTouchStartX = e.changedTouches[0].screenX; - heroStopAutoplay(); }, { passive: true }); heroSlider.addEventListener('touchend', function (e) { var diff = e.changedTouches[0].screenX - heroTouchStartX; if (Math.abs(diff) > 50) { if (diff < 0) heroNext(); else heroPrev(); } - heroStartAutoplay(); }, { passive: true }); } document.addEventListener('visibilitychange', function () { - if (document.hidden) { heroStopAutoplay(); } - else { heroStartAutoplay(); } + var slide = heroSlides[heroCurrentSlide]; + 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 Video-Start für Slide 0 (ersetzt das weggefallene autoplay-Attribut) - if (heroSlides.length) heroPlaySlideVideo(heroSlides[0]); + // Initialer Start (Slide 0 ist bereits .active im HTML) + if (heroSlides.length) heroStartSlide(); /* ==================== MAP STATE ==================== */ var mapInstance = null;