/* ============================================================ ErklaerungSection — „Kurz erklärt" als ruhige Video-Sektion. Ein 16:9-Player mit 5-Schritt-Leiste ersetzt die vormalige Scroll-Scrub-Bühne. CSS unter .sme gescopet, Look an .sma angelehnt. ============================================================ */ // Inhalt pro Welt. „ha" = Sanierung/Home-Assistant-Story (viele Fremdmarken → // ein Hub). „lox" = Loxone-Story (ein grünes Tree-Kabel aus einer Hand). Die // Welten „lox" und „nb" (Neubau) teilen sich den Loxone-Inhalt. // chips: Chips schweben während [chipsStart, chipsEnd) über den Bühnenrändern // ein. HA-Chips tragen ein Marken-Logo (logo). Loxone-Chips benennen echte // Geräte; ohne `logo` erscheint ein grüner Punkt (offizielles Produkt-PNG kann // später per `logo:'assets/loxone-devices/.png'` eingetauscht werden). const ERKL_CONTENT = { ha: { headline: 'Was ist eigentlich
Home Assistant?', lede: 'Home Assistant verbindet Geräte und Dienste, die normalerweise getrennt bleiben — für mehr Komfort, Sicherheit und Kontrolle, lokal und unabhängig. In 30 Sekunden das Wichtigste:', video: 'assets/renders/erklaerung-premium.mp4', poster: 'assets/renders/erklaerung-premium-poster.webp', segments: [ { t: 0, label: 'Viele Geräte' }, { t: 5, label: 'App-Chaos' }, { t: 10, label: 'Verbindung' }, { t: 15, label: 'Automationen' }, { t: 20, label: 'Eine Oberfläche' }, ], // Marken-Chips schweben während "Viele Geräte" + "App-Chaos" (t<10s) ein. // Marke -> Hardware: Fronius=PV, TA=Wärmepumpe, Nuki=Haustür, Sonos/Hue= // Wohnzimmer, Shelly=Rollo, KNX/Loxone=Steuerung. chipsStart: 0, chipsEnd: 10, chips: [ { logo: 'assets/brands/fronius.png', name: 'Fronius', top: '6%', left: '58%' }, { logo: 'assets/brands/ta.svg', name: 'TA', top: 'auto', bottom: '22%', left: '87%' }, { logo: 'assets/brands/knx.svg', name: 'KNX', top: '26%', left: '89%' }, { logo: 'assets/brands/nuki.svg', name: 'Nuki', top: 'auto', bottom: '32%', left: '90%' }, { logo: 'assets/brands/shelly.svg', name: 'Shelly', top: '44%', left: '66%' }, { logo: 'assets/brands/loxone.svg', name: 'Loxone', top: '32%', left: '2%' }, { logo: 'assets/brands/hue.svg', name: 'Hue', top: 'auto', bottom: '36%', left: '32%' }, { logo: 'assets/brands/sonos.svg', name: 'Sonos', top: 'auto', bottom: '18%', left: '20%' }, ], }, lox: { headline: 'Was ist eigentlich
Loxone?', lede: 'Loxone kommt aus einer Hand: ein grünes Tree-Kabel verzweigt in jeden Raum und verbindet Licht, Beschattung, Heizung, Präsenz und Energie — ohne KNX/DALI-Kaskaden. Das spart Inbetriebnahme- und Fehlersuchzeit, nicht nur Hardware. In 25 Sekunden das Prinzip:', video: 'assets/renders/erklaerung-loxone.mp4', poster: 'assets/renders/erklaerung-loxone-poster.webp', segments: [ { t: 0, label: 'Von Grund auf' }, { t: 5, label: 'Ein Tree-Kabel' }, { t: 10, label: 'Erreicht jedes Gerät' }, { t: 15, label: 'Alles aus einer Hand' }, { t: 20, label: 'Eine App' }, ], // Loxone-Geräte-Chips leuchten während "Erreicht jedes Gerät" + "Alles aus // einer Hand" (t≈10–20s) der Reihe nach auf, in der die grüne Linie sie im // Video erreicht. chipsStart: 9.5, chipsEnd: 20, chips: [ { logo: 'assets/loxone-devices/miniserver.png', name: 'Miniserver', top: '6%', left: '3%' }, { logo: 'assets/loxone-devices/nano-dimmer.png', name: 'Nano Dimmer', top: '7%', left: '42%' }, { logo: 'assets/loxone-devices/touch.png', name: 'Touch', top: '30%', left: '2%' }, { logo: 'assets/loxone-devices/praesenzmelder.png', name: 'Präsenzmelder', top: '9%', left: '72%' }, { logo: 'assets/loxone-devices/raffstore-aktor.png', name: 'Raffstore-Aktor', top: 'auto', bottom: '20%', left: '7%' }, { logo: 'assets/loxone-devices/heizungsaktor.png', name: 'Heizungsaktor', top: 'auto', bottom: '13%', left: '33%' }, ], }, }; const erklContentFor = (world) => ERKL_CONTENT[world === 'ha' ? 'ha' : 'lox']; function ErklaerungSection({ world = "ha" }) { const ref = React.useRef(null); const content = erklContentFor(world); const CSS = ` .sme{ position:relative; color:var(--ink); background:#fff; font-family:'Inter',system-ui,sans-serif; -webkit-font-smoothing:antialiased; --cyan-grad: linear-gradient(125deg,#0a6cb6 0%,#11a8d4 28%,#1fc1c0 54%,#46bd6a 80%,#6fcf54 100%); --ink-faint:#8a9caa; } body[data-world="lox"] .sme, body[data-world="nb"] .sme{ --cyan-grad: linear-gradient(125deg,#2c8424 0%,#3c9f2c 30%,#5fc23f 62%,#8fd96a 100%); } .sme a{ color:inherit; text-decoration:none; } .sme .wrap{ max-width:1120px; margin:0 auto; padding:0 40px; } .sme .ehero{ padding:92px 0 44px; max-width:760px; margin:0 auto; text-align:center; } .sme .kicker{ display:inline-flex; align-items:center; justify-content:center; gap:10px; font-family:'JetBrains Mono',monospace; font-size:.72rem; letter-spacing:.22em; text-transform:uppercase; color:var(--deep); } .sme .kicker::before{ content:""; width:26px; height:1.5px; background:currentColor; opacity:.6; } .sme .ehero h2{ margin-top:18px; font-family:'Outfit',sans-serif; font-size:clamp(2.2rem,4.8vw,3.6rem); font-weight:800; line-height:1.05; letter-spacing:-.035em; color:var(--ink); } .sme .ehero h2 .light{ color:var(--ink-soft); } .sme .ehero .lede{ margin:20px auto 0; font-size:1.08rem; line-height:1.6; color:var(--ink-soft); max-width:58ch; } .sme .ehero .lede b{ color:var(--ink); font-weight:600; } .sme .erkl-wrap{ padding:0 0 96px; } .sme .erkl-player{ position:relative; max-width:980px; margin:0 auto; aspect-ratio:16/9; border-radius:22px; overflow:hidden; background:#0c1420; box-shadow:0 30px 70px rgba(10,42,61,.16); } .sme .erkl-player video{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; background:#0c1420 center/cover no-repeat; } .sme .erkl-playpause{ position:absolute; right:18px; bottom:18px; width:46px; height:46px; border-radius:50%; border:0; padding:0; cursor:pointer; background:rgba(8,20,32,.55); backdrop-filter:blur(6px); transition:background .2s ease, transform .2s ease; } .sme .erkl-playpause::before{ content:""; display:block; margin:0 auto; width:0; height:0; border-style:solid; border-width:8px 0 8px 13px; border-color:transparent transparent transparent #fff; transform:translateX(1px); } .sme .erkl-playpause:hover{ background:rgba(8,20,32,.75); transform:scale(1.06); } .sme.erkl-novideo .erkl-playpause{ display:none; } .sme .erkl-chips{ position:absolute; inset:0; z-index:2; pointer-events:none; opacity:0; transition:opacity .6s ease; } .sme .erkl-chips.on{ opacity:1; } .sme.erkl-novideo .erkl-chips{ display:none; } .sme .erkl-chip{ position:absolute; opacity:0; transform:translateY(16px) scale(.9); transition:opacity .5s ease, transform .55s cubic-bezier(.2,.8,.2,1); } .sme .erkl-chips.on .erkl-chip{ opacity:1; transform:translateY(0) scale(1); } .sme .erkl-chip:nth-child(1){ transition-delay:.02s; } .sme .erkl-chip:nth-child(2){ transition-delay:.12s; } .sme .erkl-chip:nth-child(3){ transition-delay:.22s; } .sme .erkl-chip:nth-child(4){ transition-delay:.32s; } .sme .erkl-chip:nth-child(5){ transition-delay:.08s; } .sme .erkl-chip:nth-child(6){ transition-delay:.26s; } .sme .erkl-chip:nth-child(7){ transition-delay:.18s; } .sme .erkl-chip:nth-child(8){ transition-delay:.38s; } .sme .erkl-chip-in{ display:flex; align-items:center; gap:7px; background:rgba(255,255,255,.95); border-radius:100px; padding:6px 13px 6px 6px; box-shadow:0 10px 24px rgba(8,20,32,.3); animation:erklFloat 5.5s ease-in-out infinite; } .sme .erkl-chip:nth-child(odd) .erkl-chip-in{ animation-duration:4.6s; } .sme .erkl-chip:nth-child(3n) .erkl-chip-in{ animation-delay:-1.4s; } .sme .erkl-chip:nth-child(4n) .erkl-chip-in{ animation-delay:-2.8s; } .sme .erkl-chip img{ width:20px; height:20px; object-fit:contain; border-radius:5px; background:#fff; flex-shrink:0; } .sme[data-world="lox"] .erkl-chip img, .sme[data-world="nb"] .erkl-chip img{ width:28px; height:28px; } .sme .erkl-chip .erkl-dot{ width:10px; height:10px; border-radius:50%; background:#5fc23f; box-shadow:0 0 0 3px rgba(95,194,63,.22); flex-shrink:0; margin:0 3px; } .sme .erkl-chip span{ font-family:'Inter',sans-serif; font-size:.7rem; font-weight:700; color:#1a2530; white-space:nowrap; } @keyframes erklFloat{ 0%,100%{ transform:translateY(0); } 50%{ transform:translateY(-7px); } } @media (max-width:760px){ .sme .erkl-chip img{ width:16px; height:16px; } .sme .erkl-chip span{ font-size:.62rem; } .sme .erkl-chip-in{ padding:5px 10px 5px 5px; gap:5px; } } @media (prefers-reduced-motion: reduce){ .sme .erkl-chips{ display:flex; flex-wrap:wrap; align-content:flex-end; justify-content:center; gap:8px; inset:auto 12px 14px 12px; transition:opacity .3s ease; } .sme .erkl-chip{ position:static; transform:none !important; transition:opacity .3s ease; } .sme .erkl-chip-in{ animation:none !important; } } .sme .erkl-steps{ list-style:none; margin:26px auto 0; padding:0; max-width:980px; display:grid; grid-template-columns:repeat(5,1fr); gap:10px; } .sme .erkl-steps li{ margin:0; } .sme .erkl-steps button{ width:100%; display:flex; align-items:center; gap:10px; padding:13px 14px; border-radius:14px; border:1px solid var(--tile-line); background:var(--card-soft); cursor:pointer; text-align:left; font-family:'Inter',sans-serif; font-size:.84rem; font-weight:600; line-height:1.2; color:var(--ink-soft); transition:background .2s ease, border-color .2s ease, color .2s ease, transform .2s ease; } .sme .erkl-steps button:hover{ transform:translateY(-1px); } .sme .erkl-steps button:focus-visible{ outline:2px solid var(--deep); outline-offset:2px; } .sme .erkl-steps .n{ font-family:'JetBrains Mono',monospace; font-size:.68rem; font-weight:800; letter-spacing:.04em; color:var(--ink-faint); flex-shrink:0; } .sme .erkl-steps button.active{ background:var(--cyan-grad); border-color:transparent; color:#fff; box-shadow:0 10px 24px rgba(10,42,61,.18); } .sme .erkl-steps button.active .n{ color:rgba(255,255,255,.85); } @media (max-width:760px){ .sme .erkl-steps{ grid-template-columns:repeat(3,1fr); } .sme .erkl-steps button{ flex-direction:column; align-items:flex-start; gap:6px; font-size:.78rem; } } @media (max-width:520px){ .sme .erkl-steps{ grid-template-columns:repeat(2,1fr); } .sme .wrap{ padding:0 22px; } } `; const MARKUP = `
Kurz erklärt

${content.headline}

${content.lede}

    `; React.useEffect(() => { const root = ref.current; if (!root) return; const video = root.querySelector('#erklVideo'); const stepsEl = root.querySelector('#erklSteps'); const pp = root.querySelector('#erklPP'); const chipsEl = root.querySelector('#erklChips'); const updateChips = (t) => { if (chipsEl) chipsEl.classList.toggle('on', t >= content.chipsStart && t < content.chipsEnd); }; let videoOk = true; const onVideoError = () => { videoOk = false; root.classList.add('erkl-novideo'); }; video.addEventListener('error', onVideoError, true); // Poster-Fallback: falls das Poster-Bild fehlt/fehlerhaft ist, greift die // dunkle Player-Hintergrundfarbe statt eines kaputten Bild-Icons. const posterProbe = new Image(); posterProbe.onerror = () => { root.classList.add('erkl-noposter'); video.removeAttribute('poster'); }; posterProbe.src = video.getAttribute('poster'); stepsEl.innerHTML = content.segments.map((s, i) => `
  1. `).join(''); const stepBtns = Array.from(stepsEl.querySelectorAll('button')); const setActive = (i) => stepBtns.forEach((b, j) => b.classList.toggle('active', i === j)); const onStepClick = (e) => { const b = e.currentTarget; const i = +b.dataset.i; setActive(i); updateChips(content.segments[i].t); if (videoOk) { video.currentTime = content.segments[i].t; video.play().catch(() => {}); } }; stepBtns.forEach((b) => b.addEventListener('click', onStepClick)); const onTimeUpdate = () => { let i = 0; for (let j = 0; j < content.segments.length; j++) if (video.currentTime >= content.segments[j].t) i = j; setActive(i); updateChips(video.currentTime); }; video.addEventListener('timeupdate', onTimeUpdate); updateChips(video.currentTime || 0); const onPpClick = () => { video.paused ? video.play().catch(() => {}) : video.pause(); }; pp.addEventListener('click', onPpClick); const reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; const io = new IntersectionObserver((es) => es.forEach((e) => { if (!videoOk || reduceMotion) return; if (e.isIntersecting) { video.play().catch(() => {}); } else { video.pause(); } }), { threshold: 0.35 }); io.observe(video); setActive(0); return () => { video.removeEventListener('error', onVideoError, true); video.removeEventListener('timeupdate', onTimeUpdate); stepBtns.forEach((b) => b.removeEventListener('click', onStepClick)); pp.removeEventListener('click', onPpClick); io.disconnect(); }; }, [world]); return (
    ); } window.ErklaerungSection = ErklaerungSection; /* ============================================================ KonfiguratorTeaser — „So sieht das bei dir aus" CTA-Uebergang. Frueher Teil von ErklaerungSection (zwischen Erklaerung und Anwendungen); steht jetzt eigenstaendig direkt vor Ueber mich/Kontakt. ============================================================ */ function KonfiguratorTeaser() { const ref = React.useRef(null); const CSS = ` .smt{ position:relative; color:var(--ink); background:#fff; font-family:'Inter',system-ui,sans-serif; -webkit-font-smoothing:antialiased; --cyan-grad: linear-gradient(125deg,#0a6cb6 0%,#11a8d4 28%,#1fc1c0 54%,#46bd6a 80%,#6fcf54 100%); } body[data-world="lox"] .smt, body[data-world="nb"] .smt{ --cyan-grad: linear-gradient(125deg,#2c8424 0%,#3c9f2c 30%,#5fc23f 62%,#8fd96a 100%); } .smt a{ color:inherit; text-decoration:none; } .smt .wrap{ max-width:1120px; margin:0 auto; padding:0 40px; } .smt .eoutro{ text-align:center; padding:90px 0; } .smt .eoutro h3{ font-family:'Outfit',sans-serif; font-size:clamp(1.9rem,4.2vw,2.9rem); font-weight:800; letter-spacing:-.03em; line-height:1.08; color:var(--ink); } .smt .eoutro p{ margin:16px auto 0; max-width:48ch; font-size:1.06rem; line-height:1.55; color:var(--ink-soft); } .smt .eoutro p b{ color:var(--ink); font-weight:600; } .smt .cta-row{ margin-top:32px; display:flex; align-items:center; justify-content:center; gap:14px 22px; flex-wrap:wrap; } .smt .btn-go{ display:inline-flex; align-items:center; gap:11px; font-size:1rem; font-weight:600; padding:16px 30px; border-radius:100px; background:var(--cyan-grad); color:#fff; transition:.2s; } .smt .btn-go:hover{ transform:translateY(-2px); box-shadow:0 14px 30px rgba(10,42,61,.22); } .smt .btn-go .ar{ transition:transform .2s; } .smt .btn-go:hover .ar{ transform:translateX(4px); } .smt .text-link{ display:inline-flex; align-items:center; gap:8px; font-size:.95rem; font-weight:600; color:var(--deep); } .smt .text-link::after{ content:"→"; opacity:.8; } .smt .text-link:hover{ opacity:.8; } @media (max-width:560px){ .smt .wrap{ padding:0 22px; } } `; const MARKUP = `

    So sieht das bei dir aus.

    Jetzt der spannende Teil: dein Grundriss, deine Räume, deine Geräte. Plane dein Smart-Home im Konfigurator.

    `; React.useEffect(() => { const root = ref.current; if (!root) return; const scrollers = root.querySelectorAll('[data-scroll]'); const onScrollClick = (e) => { e.preventDefault(); const id = e.currentTarget.dataset.scroll; if (window.smoothScrollTo) window.smoothScrollTo(id); else { const el = document.getElementById(id); if (el) el.scrollIntoView({ behavior: 'smooth' }); } }; scrollers.forEach((a) => a.addEventListener('click', onScrollClick)); return () => { scrollers.forEach((a) => a.removeEventListener('click', onScrollClick)); }; }, []); return (
    ); } window.KonfiguratorTeaser = KonfiguratorTeaser;