Files
NotPika69andClaude Opus 5.5 ad155124b1 Startseite entschlackt: weniger Text, ruhiger, besser am Handy
- Cursor-Effekt im Hero entfernt (Messfadenkreuz, Temperatur-Skala,
  Maus-Wärmespur); Wärmebild läuft nur noch ruhig im Hintergrund
- Preloader, Laufbänder, Intro, Ablauf-Block, Kennzahlen, Footer-CTA,
  kursive Akzentwörter, Verlaufstext und Nummern-Pillen entfernt
- Texte in allen Abschnitten deutlich gekürzt, schlichte Überschriften
- Leistungen: auf Handy/Tablet wischbare Kärtchen mit Zähler und Pfeilen
- Neue, zusammenhängende Illustrationen für die fünf Leistungs-Kärtchen
- Heizungs-Finder ohne Prozent-Balken, kürzere Ergebnistexte
- Energie-Haus: Tabs als Wischleiste am Handy, kein Autoplay
- GSAP, ScrollTrigger, SplitText, Lenis und Instrument Serif entfernt
- Barrierefreiheit: Kontrast, Fokusring, Fokus im Kartenstapel,
  Telefon-Button mit Namen, Menü sperrt Hintergrund
- Cache-Busting (?v=20261004) für CSS und JS, README aktualisiert

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 20:14:53 +02:00

203 lines
8.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ==========================================================================
Olzinger – Hauptskript
Navigation, mobiles Menü, dezente Einblendungen, Leistungs-Karussell (mobil)
und Kartenstapel (Desktop). Bewusst ohne Bibliotheken.
========================================================================== */
(function (w, d) {
'use strict';
var html = d.documentElement;
var $ = function (s, c) { return (c || d).querySelector(s); };
var $$ = function (s, c) { return Array.prototype.slice.call((c || d).querySelectorAll(s)); };
var reduce = w.matchMedia('(prefers-reduced-motion: reduce)').matches;
var hasIO = 'IntersectionObserver' in w;
w.__olzReady = true;
/* ---------- Dynamische Jahreszahlen ---------- */
var nowYear = new Date().getFullYear();
$$('[data-current-year]').forEach(function (el) { el.textContent = nowYear; });
$$('[data-years]').forEach(function (el) { el.textContent = nowYear - 1985; });
/* ---------- Wärmebild (ruhiger Hintergrund im Hero) ---------- */
var canvas = $('[data-thermal]');
if (canvas && w.OlzThermal) {
var thermal = w.OlzThermal.init(canvas, {
hero: $('[data-hero]'),
calm: $('.hero__aside'),
reduceMotion: reduce
});
if (thermal) thermal.heatUp();
} else if (canvas) {
html.classList.add('no-webgl');
}
/* ---------- Mobiles Menü ---------- */
var menu = $('[data-menu]');
var toggle = $('[data-menu-toggle]');
var menuOpen = false;
if (menu) { menu.hidden = false; menu.setAttribute('inert', ''); menu.setAttribute('aria-hidden', 'true'); }
function setMenu(open) {
if (!menu || !toggle || open === menuOpen) return;
menuOpen = open;
menu.classList.toggle('is-open', open);
if (open) menu.removeAttribute('inert'); else menu.setAttribute('inert', '');
menu.setAttribute('aria-hidden', open ? 'false' : 'true');
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
toggle.querySelector('.sr-only').textContent = open ? 'Menü schließen' : 'Menü öffnen';
html.classList.toggle('menu-open', open);
// Inhalt hinter dem Menü für Tastatur und Screenreader sperren
[d.getElementById('main'), $('.footer')].forEach(function (el) { if (el) el.inert = open; });
}
if (toggle) toggle.addEventListener('click', function () { setMenu(!menuOpen); });
d.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && menuOpen) { setMenu(false); toggle.focus(); }
});
// Wird das Fenster breit genug für die Desktop-Navigation (z. B. Tablet drehen), Menü schließen
var deskMQ = w.matchMedia('(min-width: 1181px)');
var onDesk = function (e) { if (e.matches) setMenu(false); };
if (deskMQ.addEventListener) deskMQ.addEventListener('change', onDesk); else if (deskMQ.addListener) deskMQ.addListener(onDesk);
/* ---------- Anker-Links: Menü schließen, Thema ans Formular geben ---------- */
d.addEventListener('click', function (e) {
var a = e.target.closest('a[href*="#"]');
if (!a) return;
if (a.dataset.topic) w.dispatchEvent(new CustomEvent('olz:topic', { detail: a.dataset.topic }));
if (menuOpen) setMenu(false);
});
/* ---------- Navigation: Hintergrund ab Scroll, beim Runterscrollen ausblenden ---------- */
var nav = $('[data-nav]');
if (nav) {
var lastY = w.scrollY, ticking = false;
var onScroll = function () {
ticking = false;
var y = w.scrollY;
nav.classList.toggle('is-scrolled', y > 40);
if (!menuOpen) {
if (y > 420 && y > lastY + 4) nav.classList.add('is-hidden');
else if (y < lastY - 4 || y <= 420) nav.classList.remove('is-hidden');
}
lastY = y;
};
w.addEventListener('scroll', function () {
if (!ticking) { ticking = true; w.requestAnimationFrame(onScroll); }
}, { passive: true });
nav.addEventListener('focusin', function () { nav.classList.remove('is-hidden'); });
onScroll();
}
// Aktiven Menüpunkt markieren
var navLinks = $$('[data-nav-link]');
if (hasIO && navLinks.length) {
var linkFor = {};
navLinks.forEach(function (l) { linkFor[l.getAttribute('href').slice(1)] = l; });
var activeIO = new IntersectionObserver(function (entries) {
entries.forEach(function (en) {
var link = linkFor[en.target.id];
if (link) link.classList.toggle('is-active', en.isIntersecting);
});
}, { rootMargin: '-45% 0px -54% 0px' });
Object.keys(linkFor).forEach(function (id) {
var sec = d.getElementById(id);
if (sec) activeIO.observe(sec);
});
}
/* ---------- Dezente Einblendungen ---------- */
var reveals = $$('[data-reveal]');
if (hasIO && !reduce) {
var revealIO = new IntersectionObserver(function (entries) {
entries.forEach(function (en) {
if (!en.isIntersecting) return;
en.target.classList.add('is-in');
revealIO.unobserve(en.target);
});
}, { rootMargin: '0px 0px -8% 0px' });
reveals.forEach(function (el) { revealIO.observe(el); });
} else {
reveals.forEach(function (el) { el.classList.add('is-in'); });
}
/* ---------- Leistungen: Karussell (mobil) bzw. Kartenstapel (Desktop) ---------- */
var stack = $('[data-stack]');
var cards = $$('.svc');
var stackNav = $('[data-stack-nav]');
var stackMQ = w.matchMedia('(min-width: 900px) and (min-height: 660px)');
if (stack && stackNav) {
var prevBtn = $('[data-stack-prev]', stackNav);
var nextBtn = $('[data-stack-next]', stackNav);
var currentEl = $('[data-stack-current]', stackNav);
var current = 0;
var isCarousel = function () { return stack.scrollWidth > stack.clientWidth + 2; };
var cardLeft = function (c) { return c.offsetLeft - cards[0].offsetLeft; };
var cardIndex = function () {
var x = stack.scrollLeft, best = 0, bestDist = Infinity;
if (x >= stack.scrollWidth - stack.clientWidth - 2) return cards.length - 1;
cards.forEach(function (c, i) {
var dist = Math.abs(cardLeft(c) - x);
if (dist < bestDist) { bestDist = dist; best = i; }
});
return best;
};
var updateNav = function () {
stackNav.hidden = !isCarousel();
current = cardIndex();
currentEl.textContent = current + 1;
prevBtn.disabled = current === 0;
nextBtn.disabled = current === cards.length - 1;
};
// Schritt relativ zur echten Scrollposition (bei zwei Karten nebeneinander
// liegen die letzten Karten jenseits der maximalen Scrollweite)
var step = function (dir) {
var x = stack.scrollLeft, i;
if (dir > 0) { for (i = 0; i < cards.length - 1; i++) if (cardLeft(cards[i]) > x + 2) break; }
else { for (i = cards.length - 1; i > 0; i--) if (cardLeft(cards[i]) < x - 2) break; }
stack.scrollTo({ left: Math.min(cardLeft(cards[i]), stack.scrollWidth - stack.clientWidth), behavior: reduce ? 'auto' : 'smooth' });
};
var navTick = false;
stack.addEventListener('scroll', function () {
if (!navTick) { navTick = true; w.requestAnimationFrame(function () { navTick = false; updateNav(); }); }
}, { passive: true });
prevBtn.addEventListener('click', function () { step(-1); });
nextBtn.addEventListener('click', function () { step(1); });
w.addEventListener('resize', updateNav);
updateNav();
}
// Desktop: hintere Karten treten beim Überdecken leicht zurück
if (stack && !reduce) {
var inners = cards.map(function (c) { return $('.svc__inner', c); });
var stackTick = false;
var paintStack = function () {
stackTick = false;
if (!stackMQ.matches) {
inners.forEach(function (el) { el.style.transform = ''; el.style.removeProperty('--shade'); });
return;
}
var vh = w.innerHeight;
cards.forEach(function (card, i) {
var next = cards[i + 1];
if (!next) return;
var stickyTop = parseFloat(getComputedStyle(next).top) || 100;
var start = vh * 0.85;
var p = (start - next.getBoundingClientRect().top) / (start - stickyTop);
p = Math.max(0, Math.min(1, p));
inners[i].style.transform = p ? 'scale(' + (1 - p * (0.1 - i * 0.012)) + ')' : '';
inners[i].style.setProperty('--shade', (p * 0.5).toFixed(3));
});
};
var requestPaint = function () {
if (!stackTick) { stackTick = true; w.requestAnimationFrame(paintStack); }
};
w.addEventListener('scroll', requestPaint, { passive: true });
w.addEventListener('resize', requestPaint);
paintStack();
}
})(window, document);