/* ========================================================= Unger Reisen — behaviour - render data-driven sections (stats / services / fleet) - scroll-driven bus across the hero - nav solidify on scroll - reveal-on-scroll (IntersectionObserver) - interactive MapLibre map (two locations + route) ========================================================= */ (function () { 'use strict'; var ACCENT = '#C8102E'; var reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion:reduce)').matches; /* ---------- Data ---------- */ var stats = [ { big: '2', label: 'Standorte in Bayern' }, { big: '60+', label: 'Sitzplätze pro Reisebus' }, { big: '24/7', label: 'Für Sie erreichbar' }, { big: '∞', label: 'Ziele in ganz Europa' } ]; var services = [ { no: '01', title: 'Busanmietung', desc: 'Moderne Reisebusse mit Fahrer — flexibel für einzelne Fahrten oder mehrtägige Touren.' }, { no: '02', title: 'Firmenreisen', desc: 'Betriebsausflüge, Tagungen und Events. Ihr Team sicher und entspannt am Ziel.' }, { no: '03', title: 'Vereinsfahrten', desc: 'Ausflüge, Feste und Sportevents — komfortabel für die ganze Gruppe.' }, { no: '04', title: 'Transfers', desc: 'Flughafen-, Hotel- und Event-Transfers. Pünktlich und rund um die Uhr planbar.' } ]; var fleet = [ { name: 'Reisebus', seats: '60', desc: 'Der Große für lange Strecken und große Gruppen — voll ausgestattet.', tags: ['Klimaanlage', 'WC', 'Bordküche', 'WLAN'] }, { name: 'Midibus', seats: '35', desc: 'Wendig und komfortabel — ideal für mittlere Gruppen und Tagestouren.', tags: ['Klimaanlage', 'Komfortbestuhlung'] }, { name: 'Kleinbus', seats: '19', desc: 'Persönlich und flexibel für kleine Gruppen, Transfers und Sonderfahrten.', tags: ['Flexibel', 'Wendig'] } ]; function el(tag, cls, html) { var n = document.createElement(tag); if (cls) n.className = cls; if (html != null) n.innerHTML = html; return n; } /* ---------- Render sections ---------- */ function renderStats() { var grid = document.getElementById('stats-grid'); if (!grid) return; stats.forEach(function (s) { var wrap = el('div', null); wrap.setAttribute('data-reveal', ''); wrap.appendChild(el('div', 'display stat__big', s.big)); wrap.appendChild(el('div', 'stat__label', s.label)); grid.appendChild(wrap); }); } function renderServices() { var grid = document.getElementById('services-grid'); if (!grid) return; services.forEach(function (s) { var card = el('div', 'service'); card.setAttribute('data-reveal', ''); card.appendChild(el('div', 'display service__no', s.no)); card.appendChild(el('h3', 'service__title', s.title)); card.appendChild(el('p', 'service__desc', s.desc)); grid.appendChild(card); }); } function renderFleet() { var grid = document.getElementById('fleet-grid'); if (!grid) return; fleet.forEach(function (f) { var card = el('div', 'fleetCard'); card.setAttribute('data-reveal', ''); var head = el('div', 'fleetCard__head'); head.appendChild(el('h3', 'display fleetCard__name', f.name)); var seats = el('div', 'fleetCard__seats', 'bis' + '' + f.seats + '' + 'Sitze'); head.appendChild(seats); card.appendChild(head); var body = el('div', 'fleetCard__body'); body.appendChild(el('p', 'fleetCard__desc', f.desc)); var tags = el('div', 'fleetCard__tags'); f.tags.forEach(function (t) { tags.appendChild(el('span', 'tag', t)); }); body.appendChild(tags); card.appendChild(body); grid.appendChild(card); }); } /* ---------- Nav solidify on scroll ---------- */ function initNav() { var nav = document.getElementById('nav'); if (!nav) return; var onScroll = function () { nav.classList.toggle('is-scrolled', window.scrollY > 40); }; window.addEventListener('scroll', onScroll, { passive: true }); onScroll(); } /* ---------- Mobile menu ---------- */ function initMobileMenu() { var burger = document.getElementById('nav-burger'); var menu = document.getElementById('mobile-menu'); if (!burger || !menu) return; function setOpen(open) { menu.classList.toggle('is-open', open); burger.classList.toggle('is-open', open); burger.setAttribute('aria-expanded', open ? 'true' : 'false'); burger.setAttribute('aria-label', open ? 'Menü schließen' : 'Menü öffnen'); document.body.style.overflow = open ? 'hidden' : ''; } burger.addEventListener('click', function () { setOpen(!menu.classList.contains('is-open')); }); menu.querySelectorAll('a').forEach(function (a) { a.addEventListener('click', function () { setOpen(false); }); }); window.addEventListener('keydown', function (e) { if (e.key === 'Escape') setOpen(false); }); // Close if we grow past the mobile breakpoint. window.addEventListener('resize', function () { if (window.innerWidth > 680) setOpen(false); }); } /* ---------- Scroll-driven bus ---------- */ function initBus() { var bus = document.getElementById('bus'); var hero = document.getElementById('top'); if (!bus || !hero) return; function tick() { var hp = Math.min(1, Math.max(0, window.scrollY / (hero.offsetHeight * 0.9))); var scene = bus.parentNode; var sceneW = scene ? scene.offsetWidth : window.innerWidth; var busW = bus.offsetWidth || 400; var minX = -busW * 0.30; var maxX = sceneW - busW * 0.70; var x = minX + (maxX - minX) * hp; var bob = reduceMotion ? 0 : Math.sin(Date.now() / 380) * 4; bus.style.transform = 'translate(' + x.toFixed(1) + 'px,' + bob.toFixed(1) + 'px)'; requestAnimationFrame(tick); } requestAnimationFrame(tick); } /* ---------- Reveal on scroll ---------- */ function initReveal() { var els = Array.prototype.slice.call(document.querySelectorAll('[data-reveal]')); if ('IntersectionObserver' in window) { var io = new IntersectionObserver(function (entries) { entries.forEach(function (e) { if (e.isIntersecting) { e.target.classList.add('is-visible'); io.unobserve(e.target); } }); }, { threshold: 0.12 }); els.forEach(function (n) { io.observe(n); }); } else { els.forEach(function (n) { n.classList.add('is-visible'); }); } // Safety fallback: reveal everything after 2.5s regardless. setTimeout(function () { els.forEach(function (n) { n.classList.add('is-visible'); }); }, 2500); } /* ---------- Interactive map ---------- */ function initMap() { var HOME = [12.0517, 48.4703]; // Buch am Erlbach / Vatersdorf var BRANCH = [12.1508, 48.5449]; // Landshut var container = document.getElementById('unger-map'); if (!container || typeof maplibregl === 'undefined') return; function makePin(fill, ring, title, sub) { var wrap = el('div', 'pin'); wrap.appendChild(el('div', 'pin__label', '