/* ============================================================ AnwendungSection — „Dein Alltag, einfach smart" als SPA-Sektion. Alltags-Anwendungsfälle (Story- oder App-Darstellung via variant). Markup + Logik aus „Smartmacherei - Anwendungsfälle"; CSS unter .sma. ============================================================ */ function AnwendungSection({ variant = "story" }) { const ref = React.useRef(null); const CSS = ` .sma{ 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"] .sma, body[data-world="nb"] .sma{ --cyan-grad: linear-gradient(125deg,#2c8424 0%,#3c9f2c 30%,#5fc23f 62%,#8fd96a 100%); } .sma a{ color:inherit; text-decoration:none; } .sma .wrap{ max-width:1200px; margin:0 auto; padding:0 40px; } .sma h1, .sma h2, .sma h3{ font-family:'Outfit',sans-serif; } .sma .intro{ position:relative; overflow:hidden; background:var(--cyan-grad); color:#fff; padding:84px 0 96px; } .sma .intro::after{ content:""; position:absolute; right:-8%; top:-30%; width:60vw; height:60vw; max-width:720px; max-height:720px; border-radius:50%; pointer-events:none; background:radial-gradient(circle at 50% 50%, rgba(255,255,255,.85), rgba(255,255,255,0) 66%); opacity:.9; } .sma .intro .wrap{ position:relative; z-index:2; } .sma .eyebrow{ display:inline-flex; align-items:center; gap:9px; font-family:'JetBrains Mono',monospace; font-size:.68rem; font-weight:600; letter-spacing:.16em; text-transform:uppercase; } .sma .intro .eyebrow{ color:var(--on-dim); } .sma .eyebrow .dot{ width:7px; height:7px; border-radius:50%; background:currentColor; } .sma .intro h2{ font-size:clamp(2.4rem,5.4vw,4.2rem); font-weight:800; line-height:1.0; letter-spacing:-.035em; margin-top:18px; max-width:16ch; color:#fff; } .sma .intro h2 .light{ color:rgba(255,255,255,.6); } .sma .intro .lede{ margin-top:22px; font-size:1.12rem; line-height:1.55; color:var(--on); max-width:52ch; } .sma .intro .lede b{ font-weight:600; color:#fff; } .sma .daychips{ margin-top:30px; display:flex; flex-wrap:wrap; gap:9px; } .sma .daychip{ display:inline-flex; align-items:center; gap:8px; padding:9px 15px; border-radius:100px; background:rgba(255,255,255,.16); border:1px solid rgba(255,255,255,.26); font-size:.86rem; font-weight:500; color:#fff; cursor:pointer; transition:background .2s, transform .2s; } .sma .daychip:hover{ background:rgba(255,255,255,.28); transform:translateY(-1px); } .sma .daychip .cdot{ width:9px; height:9px; border-radius:50%; } .sma section.band{ padding:88px 0; } .sma .sec-head{ max-width:720px; } .sma .sec-head h2{ font-size:clamp(1.9rem,3.6vw,3rem); font-weight:700; letter-spacing:-.03em; line-height:1.04; margin-top:14px; color:var(--ink); } .sma .sec-head .sub{ margin-top:16px; font-size:1.06rem; line-height:1.55; color:var(--ink-soft); max-width:56ch; } .sma .sec-eyebrow{ color:var(--deep); } .sma .cases{ margin-top:56px; display:flex; flex-direction:column; gap:30px; } /* Timeline (desktop): links Tagesablauf-Liste, rechts eine grosse sticky Buehne. */ .sma .cases-timeline{ display:grid; grid-template-columns:0.86fr 1.14fr; gap:54px; } .sma .tl-col{ position:relative; } .sma .tl-col::before{ content:""; position:absolute; left:6px; top:8px; bottom:8px; width:2px; background:var(--tile-line); } .sma .tl-entry{ position:relative; padding:18px 20px 18px 34px; border-radius:18px; border:1px solid transparent; transition:background .3s ease, border-color .3s ease, transform .3s ease, box-shadow .3s ease; } .sma .tl-dot{ position:absolute; left:0; top:22px; width:14px; height:14px; border-radius:50%; background:#fff; border:2px solid var(--uc-accent); transition:transform .3s ease, background .3s ease, box-shadow .3s ease; } .sma .tl-entry.active{ background:#fff; border-color:color-mix(in oklab, var(--uc-accent) 32%, transparent); box-shadow:0 14px 32px rgba(10,42,61,.10); transform:translateX(4px); } .sma .tl-entry.active .tl-dot{ background:var(--uc-accent); transform:scale(1.2); box-shadow:0 0 0 5px color-mix(in oklab, var(--uc-accent) 20%, transparent); } .sma .tl-time{ display:inline-flex; align-items:center; gap:8px; font-family:'JetBrains Mono',monospace; font-size:.7rem; font-weight:600; letter-spacing:.1em; color:var(--uc-deep); text-transform:uppercase; } .sma .tl-time .tdot{ width:7px; height:7px; border-radius:50%; background:var(--uc-accent); } .sma .tl-h{ margin-top:8px; font-family:'Outfit',sans-serif; font-size:1.18rem; font-weight:700; letter-spacing:-.02em; line-height:1.15; color:var(--ink); } .sma .tl-p{ margin-top:8px; font-size:.9rem; line-height:1.5; color:var(--ink-soft); max-width:40ch; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; } .sma .tl-chips{ margin-top:12px; display:flex; flex-wrap:wrap; gap:7px; } .sma .tl-chips .chip{ padding:6px 11px; font-size:.74rem; } .sma .tl-stage-outer{ position:relative; } .sma .tl-stage-sticky{ position:sticky; top:118px; border-radius:28px; overflow:hidden; background:linear-gradient(160deg,var(--uc-tint),var(--uc-tint2)); aspect-ratio:4/3.1; min-height:420px; } .sma .tl-badge{ position:absolute; top:18px; left:18px; z-index:8; font-family:'JetBrains Mono',monospace; font-size:.74rem; font-weight:700; letter-spacing:.08em; color:#fff; padding:8px 14px; border-radius:100px; background:rgba(10,20,30,.5); backdrop-filter:blur(4px); pointer-events:none; } .sma .tl-stage-stack{ position:absolute; inset:0; } .sma .tl-stage-item{ position:absolute; inset:0; opacity:0; transition:opacity .3s ease; pointer-events:none; } .sma .tl-stage-item.active{ opacity:1; pointer-events:auto; z-index:2; } .sma .tl-stage-item .uc-stage{ position:absolute; inset:0; min-height:0; } .sma .cases-mobile{ display:none; } .sma .uc{ --uc-accent:oklch(0.66 0.15 var(--h)); --uc-deep:oklch(0.47 0.13 var(--h)); --uc-tint:oklch(0.965 0.028 var(--h)); --uc-tint2:oklch(0.93 0.05 var(--h)); } .sma .uc-story{ display:grid; grid-template-columns:1.02fr 1fr; gap:0; border-radius:28px; overflow:hidden; background:#fff; border:1px solid var(--tile-line); box-shadow:0 1px 0 rgba(10,42,61,.02); opacity:0; transform:translateY(26px); transition:opacity .7s ease, transform .7s ease; } .sma .uc-story.in{ opacity:1; transform:none; } .sma .uc-story:nth-child(even){ grid-template-columns:1fr 1.02fr; } .sma .uc-story:nth-child(even) .uc-stage{ order:2; } .sma .uc-stage{ position:relative; min-height:340px; display:flex; align-items:center; justify-content:center; background:linear-gradient(160deg,var(--uc-tint),var(--uc-tint2)); overflow:hidden; } .sma .uc-video{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; opacity:0; z-index:3; pointer-events:none; transition:opacity .25s ease; } .sma .uc-poster{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:1; transition:opacity .2s ease; } .sma .uc-stage.playing .uc-poster{ opacity:0; } .sma .uc-stage:not(.has-video) .uc-video{ display:none; } .sma .uc-stage.playing .uc-video{ opacity:1; pointer-events:auto; } /* Vorher/Nachher-Vergleich */ .sma .uc-vorher{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:2; clip-path:inset(0 calc(100% - var(--split,50%)) 0 0); } .sma .uc-divider{ position:absolute; top:0; bottom:0; left:var(--split,50%); width:44px; margin-left:-22px; z-index:5; background:none; border:none; padding:0; cursor:ew-resize; touch-action:none; -webkit-tap-highlight-color:transparent; } .sma .uc-divider::before{ content:""; position:absolute; top:0; bottom:0; left:50%; width:2px; background:rgba(255,255,255,.92); box-shadow:0 0 0 1px rgba(10,20,30,.14); transform:translateX(-50%); } .sma .uc-divider .grip{ position:absolute; top:76%; left:50%; transform:translate(-50%,-50%); width:38px; height:38px; border-radius:50%; background:#fff; box-shadow:0 6px 18px rgba(10,42,61,.3); display:flex; align-items:center; justify-content:center; color:var(--uc-deep); } .sma .uc-divider .grip svg{ width:17px; height:17px; } .sma .uc-divider:focus-visible .grip{ outline:2px solid var(--uc-accent); outline-offset:2px; } .sma .uc-label{ position:absolute; bottom:13px; z-index:4; font-size:.68rem; font-weight:600; letter-spacing:.03em; color:#fff; padding:5px 11px; border-radius:100px; background:rgba(10,20,30,.42); backdrop-filter:blur(3px); pointer-events:none; } .sma .uc-label.vorher{ left:13px; } .sma .uc-label.nachher{ right:13px; } .sma .uc-play{ position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); z-index:6; width:54px; height:54px; border-radius:50%; background:rgba(255,255,255,.86); backdrop-filter:blur(4px); border:1px solid rgba(255,255,255,.6); display:flex; align-items:center; justify-content:center; color:var(--uc-deep); cursor:pointer; box-shadow:0 10px 26px rgba(10,42,61,.24); transition:transform .2s ease, background .2s ease, opacity .2s ease; } .sma .uc-play:hover{ transform:translate(-50%,-50%) scale(1.06); background:#fff; } .sma .uc-play svg{ width:19px; height:19px; margin-left:3px; } .sma .uc-close{ position:absolute; top:12px; right:12px; z-index:7; width:30px; height:30px; border-radius:50%; background:rgba(10,20,30,.5); color:#fff; border:none; display:flex; align-items:center; justify-content:center; cursor:pointer; opacity:0; pointer-events:none; transition:opacity .2s ease; } .sma .uc-close svg{ width:13px; height:13px; } .sma .uc-stage.playing .uc-close{ opacity:1; pointer-events:auto; } .sma .uc-stage.playing .uc-vorher, .sma .uc-stage.playing .uc-divider, .sma .uc-stage.playing .uc-label, .sma .uc-stage.playing .uc-play{ opacity:0; pointer-events:none; } .sma .uc-stage.fallback .uc-vorher, .sma .uc-stage.fallback .uc-divider, .sma .uc-stage.fallback .uc-label, .sma .uc-stage.fallback .uc-play, .sma .uc-stage.fallback .uc-close{ display:none; } .sma .uc-copy{ padding:44px 46px; display:flex; flex-direction:column; justify-content:center; } .sma .uc-time{ display:inline-flex; align-items:center; gap:9px; font-family:'JetBrains Mono',monospace; font-size:.7rem; font-weight:600; letter-spacing:.12em; color:var(--uc-deep); text-transform:uppercase; } .sma .uc-time .tdot{ width:8px; height:8px; border-radius:50%; background:var(--uc-accent); } .sma .uc-scene{ margin-top:6px; font-size:.92rem; color:var(--ink-soft); font-weight:500; } .sma .uc-h{ margin-top:14px; font-family:'Outfit',sans-serif; font-size:clamp(1.5rem,2.5vw,2.1rem); font-weight:700; letter-spacing:-.025em; line-height:1.05; color:var(--ink); text-wrap:balance; } .sma .uc-body{ margin-top:14px; font-size:1rem; line-height:1.55; color:var(--ink-soft); max-width:42ch; } .sma .uc-equip-label{ margin-top:24px; font-family:'JetBrains Mono',monospace; font-size:.62rem; letter-spacing:.14em; text-transform:uppercase; color:var(--ink-faint); } .sma .uc-equip{ margin-top:11px; display:flex; flex-wrap:wrap; gap:8px; } .sma .chip{ display:inline-flex; align-items:center; gap:8px; padding:8px 13px; border-radius:100px; background:var(--uc-tint); border:1px solid color-mix(in oklab, var(--uc-accent) 24%, transparent); font-size:.82rem; font-weight:500; color:var(--uc-deep); } .sma .chip svg{ width:14px; height:14px; } .sma .uc-app{ display:grid; grid-template-columns:300px 1fr; gap:36px; align-items:center; padding:34px; border-radius:28px; background:#fff; border:1px solid var(--tile-line); opacity:0; transform:translateY(26px); transition:opacity .7s ease, transform .7s ease; } .sma .uc-app.in{ opacity:1; transform:none; } .sma .uc-app:nth-child(even){ grid-template-columns:1fr 300px; } .sma .uc-app:nth-child(even) .app-phonewrap{ order:2; } .sma .app-phonewrap{ display:flex; justify-content:center; } .sma .app-copy{ display:flex; flex-direction:column; } .sma .miniphone{ width:264px; background:#fff; border-radius:34px; padding:9px; box-shadow:0 30px 60px rgba(10,60,100,.16),0 6px 18px rgba(10,60,100,.10); border:1.5px solid #eef3f7; } .sma .miniscreen{ background:var(--card-soft); border-radius:26px; overflow:hidden; padding:16px 14px 18px; } .sma .mp-top{ display:flex; align-items:center; justify-content:space-between; margin-bottom:14px; } .sma .mp-room{ display:flex; align-items:center; gap:8px; font-weight:600; font-size:.9rem; color:var(--ink); } .sma .mp-room .rdot{ width:9px; height:9px; border-radius:50%; background:var(--uc-accent); } .sma .mp-time{ font-family:'JetBrains Mono',monospace; font-size:.72rem; color:var(--ink-faint); } .sma .mp-tile{ background:#fff; border:1px solid var(--tile-line); border-radius:16px; padding:13px 14px; display:flex; align-items:center; gap:12px; margin-bottom:9px; } .sma .mp-tile .mpi{ width:40px; height:40px; border-radius:12px; flex-shrink:0; display:flex; align-items:center; justify-content:center; background:var(--uc-tint); color:var(--uc-deep); } .sma .mp-tile .mpi svg{ width:21px; height:21px; } .sma .mp-tile.live .mpi{ background:var(--uc-accent); color:#fff; } .sma .mp-tx{ flex:1; min-width:0; } .sma .mp-tn{ font-size:.86rem; font-weight:600; color:var(--ink); } .sma .mp-ts{ font-size:.76rem; color:var(--ink-soft); } .sma .mp-tile.live .mp-ts{ color:var(--uc-deep); font-weight:600; } .sma .mp-toggle{ width:40px; height:23px; border-radius:100px; background:var(--tile-line); position:relative; flex-shrink:0; transition:background .3s; } .sma .mp-toggle::after{ content:""; position:absolute; width:19px; height:19px; border-radius:50%; background:#fff; top:2px; left:2px; box-shadow:0 1px 3px rgba(0,0,0,.18); transition:left .3s; } .sma .mp-tile.live .mp-toggle{ background:var(--uc-accent); } .sma .mp-tile.live .mp-toggle::after{ left:19px; } .sma .mp-bars{ display:flex; align-items:flex-end; gap:3px; height:30px; margin-top:4px; } .sma .mp-bars i{ flex:1; background:var(--uc-accent); border-radius:2px 2px 0 0; opacity:.85; } .sma .app-foot{ margin-top:12px; display:inline-flex; align-items:center; gap:8px; font-size:.82rem; color:var(--uc-deep); font-weight:600; } .sma .app-foot svg{ width:16px; height:16px; flex-shrink:0; } @media (prefers-reduced-motion: reduce){ .sma .uc-story, .sma .uc-app{ animation:none !important; transition:none !important; } } .sma .flexcard{ margin-top:30px; display:grid; grid-template-columns:auto 1fr; gap:30px; align-items:center; padding:34px 40px; border-radius:28px; background:linear-gradient(135deg,var(--uc-tint),var(--uc-tint2)); border:1px solid color-mix(in oklab, var(--uc-accent) 26%, transparent); opacity:0; transform:translateY(26px); transition:opacity .7s ease, transform .7s ease; } .sma .flexcard.in{ opacity:1; transform:none; } .sma .flex-ic{ width:88px; height:88px; border-radius:24px; background:#fff; flex-shrink:0; display:flex; align-items:center; justify-content:center; color:var(--uc-deep); box-shadow:0 10px 26px color-mix(in oklab, var(--uc-accent) 22%, transparent); } .sma .flex-ic svg{ width:42px; height:42px; } .sma .flex-eye{ color:var(--uc-deep); } .sma .flex-body h3{ font-family:'Outfit',sans-serif; font-size:clamp(1.4rem,2.3vw,1.95rem); font-weight:700; letter-spacing:-.025em; color:var(--ink); margin-top:10px; line-height:1.05; } .sma .flex-body p{ font-size:1.02rem; line-height:1.55; color:var(--ink-soft); margin-top:12px; max-width:66ch; } .sma .flex-equip{ margin-top:18px; } @media (max-width:880px){ .sma .flexcard{ grid-template-columns:1fr; padding:28px; } } .sma .reassure{ background:var(--cyan-grad); color:#fff; position:relative; overflow:hidden; } .sma .reassure::after{ content:""; position:absolute; left:-10%; bottom:-40%; width:50vw; height:50vw; max-width:600px; max-height:600px; border-radius:50%; background:radial-gradient(circle, rgba(255,255,255,.7), transparent 66%); opacity:.7; pointer-events:none; } .sma .reassure .wrap{ position:relative; z-index:2; } .sma .reassure h2{ color:#fff; } .sma .reassure .sub{ color:var(--on); } .sma .rgrid{ margin-top:48px; display:grid; grid-template-columns:repeat(3,1fr); gap:18px; } .sma .rcard{ background:rgba(255,255,255,.12); border:1px solid rgba(255,255,255,.22); border-radius:20px; padding:26px; } .sma .rcard .rn{ font-family:'JetBrains Mono',monospace; font-size:.72rem; letter-spacing:.14em; color:var(--on-dim); } .sma .rcard h3{ font-size:1.22rem; font-weight:600; margin-top:12px; color:#fff; } .sma .rcard p{ margin-top:9px; font-size:.96rem; line-height:1.55; color:var(--on); } @media (max-width:880px){ .sma .uc-story, .sma .uc-story:nth-child(even){ grid-template-columns:1fr; } .sma .uc-story:nth-child(even) .uc-stage{ order:0; } .sma .uc-app, .sma .uc-app:nth-child(even){ grid-template-columns:1fr; gap:24px; } .sma .uc-app:nth-child(even) .app-phonewrap{ order:0; } .sma .uc-copy{ padding:32px 28px; } .sma .rgrid{ grid-template-columns:1fr; } .sma .cases-timeline{ display:none; } .sma .cases-mobile{ display:flex; flex-direction:column; gap:30px; } } @media (max-width:560px){ .sma .wrap{ padding:0 22px; } } `; const MARKUP = `
Dein Tag, einfach smart

Nicht Technik.
Sondern dein Alltag.

Smart Home ist kein Schaltschrank voller Kabel — es sind die kleinen Momente, in denen dein Zuhause einfach mitdenkt. Hier ein paar davon. Such dir aus, was dich am meisten nervt:

Anwendungsfälle

Sieben Situationen, in denen es sich sofort lohnt.

Jeder Fall einzeln umsetzbar — du musst nicht alles auf einmal machen. Wir starten dort, wo dein Alltag am meisten gewinnt.

Egal, was schon da ist

Kein Kabel? Dann eben Funk.

Nicht jedes Haus lässt sich aufstemmen — muss es auch nicht. Wo Kabel liegen, nutzen wir sie. Wo keine sind, läuft alles per Funk. Oft ein Mix aus beidem. Wir binden uns an keinen Hersteller: pro Raum wählen wir die saubere Lösung, alle gängigen Standards sind möglich.

So läuft's

Du erlebst den Alltag. Die Technik bleibt unsichtbar.

Welches System im Hintergrund arbeitet, entscheiden wir gemeinsam — du musst dich damit nie beschäftigen. Versprochen.

01 · Kennenlernen

Wir hören zu

Kurzes Gespräch, was dich im Alltag stört und was du dir wünschst. Kostenlos und ohne Fachchinesisch.

02 · Vorschlag

Du bekommst einen Plan

Pro Anwendungsfall ein klarer Vorschlag mit Ausstattung und Preisrahmen. Du wählst, was zuerst dran ist.

03 · Umsetzung

Wir machen's smart

Sauber installiert, alles dokumentiert, eine einfache App für die ganze Familie. Erweiterbar, wann immer du willst.

`; React.useEffect(() => { const root = ref.current; if (!root) return; const ICON = { bulb:'', heat:'', blind:'', energy:'', car:'', shield:'', audio:'', check:'', bolt:'', signal:'', play:'', close:'', grip:'', }; const CASES = [ { id:'licht', h:75, icon:'bulb', anim:'lamp', time:'17:30', scene:'Du kommst heim', h2:'Das Licht ist schon an.', body:'Tür auf — und es ist hell, warm, gemütlich. Abends dimmt sich alles von selbst herunter. Eine Szene für Kino, eine fürs Essen, eine für „alle ins Bett".', equip:['Stimmungs-Szenen','Automatisch nach Tageszeit','App, Taster & Sprache'], nachher:'hero-licht-an.webp', vorher:'hero-licht-aus.webp' }, { id:'heizung', h:32, icon:'heat', anim:'heat', time:'06:45', scene:'Bevor der Wecker klingelt', h2:'Das Bad ist schon warm.', body:'Jeder Raum nur dann geheizt, wenn du ihn brauchst. Fenster auf? Heizung pausiert. Spart spürbar Energie — ohne dass du je an ein Thermostat denken musst.', equip:['Raum für Raum geregelt','Fenster-auf-Erkennung','15–25 % weniger Heizkosten'], nachher:'hero-heizung-warm.webp', vorher:'hero-heizung-kalt.webp' }, { id:'beschattung', h:245, icon:'blind', anim:'blinds', time:'13:00', scene:'Die Mittagssonne knallt', h2:'Die Rollläden wissen Bescheid.', body:'Im Sommer fährt die Beschattung bei Sonne automatisch runter, es bleibt kühl. Wird es windig, fahren die Markisen rechtzeitig ein. Du musst nichts mehr nachlaufen.', equip:['Reagiert auf Sonne & Wind','Pro Fenster oder Fassade','Manuell jederzeit übersteuerbar'] }, { id:'energie', h:150, icon:'energy', anim:'energy', time:'12:20', scene:'Die Sonne liefert', h2:'Dein Strom geht nicht verloren.', body:'Du siehst auf einen Blick, woher dein Strom kommt und wohin er fließt. Überschuss lädt automatisch den Speicher, die Wärmepumpe oder das Auto — statt billig ins Netz zu wandern.', equip:['PV, Speicher & Verbrauch live','Eigenverbrauch automatisch','Klare Energie-Kosten'] }, { id:'wallbox', h:188, icon:'car', anim:'wallbox', time:'18:10', scene:'Auto an die Wallbox', h2:'Geladen wird, wenn Strom da ist.', body:'Das E-Auto tankt bevorzugt den eigenen Sonnenstrom — oder nachts, wenn er günstig ist. Lastspitzen werden vermieden, damit nie die Sicherung fliegt.', equip:['Laden mit PV-Überschuss','Günstige Zeitfenster','Lastmanagement im Haus'] }, { id:'sicherheit', v:'r5', h:285, icon:'shield', anim:'secure', time:'22:30', scene:'„Alle im Bett"', h2:'Ein Tipp — und alles ist sicher.', body:'Licht aus, Türen zu, Rollläden unten, Anwesenheit simuliert. Bist du weg und etwas öffnet sich, bekommst du sofort eine Nachricht — mit Videobild von der Tür.', equip:['Tür- & Fensterstatus','Push bei Auffälligkeiten','Video-Türklingel'] }, { id:'audio', h:322, icon:'audio', anim:'audio', time:'08:00', scene:'Guten Morgen', h2:'Deine Musik folgt dir durchs Haus.', body:'Im Bad die Nachrichten, in der Küche die Playlist, beim Rausgehen alles aus. In jedem Raum die richtige Lautstärke — gesteuert per App, Taster oder Sprache.', equip:['Multiroom in jedem Raum','Eigene Lautstärke pro Raum','Sonos, Loxone & mehr'] }, ]; const CHIP_ICON = ICON.check; const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; const ver = (c) => (c.v ? ('?v=' + c.v) : ''); // Cache-Bust pro Karte, wenn Video/Poster neu gerendert wurde const nachherSrc = (c) => 'assets/renders/' + (c.nachher || ('anw-' + c.id + '-start.webp')) + ver(c); const vorherSrc = (c) => 'assets/renders/' + (c.vorher || ('anw-' + c.id + '-vorher.webp')); const videoHTML = (c) => ''; const chipsHTML = (equip) => equip.map((e) => ''+CHIP_ICON+e+'').join(''); const compareHTML = (c) => '
'+ICON.grip+'
' + 'VorherNachher' + (reducedMotion ? '' : ''); const stageInnerHTML = (c) => '' + '' + compareHTML(c) + (reducedMotion ? '' : videoHTML(c)); const renderStory = (c) => '
' + stageInnerHTML(c) + '
'+c.time+''+c.scene+'

'+c.h2+'

'+c.body+'

Das ist dabei
'+chipsHTML(c.equip)+'
'; const renderTlEntry = (c, i) => '
' + '' + '
'+c.time+'

'+c.h2+'

'+c.body+'

'+chipsHTML(c.equip)+'
'; const renderTlStageItem = (c, i) => '
' + stageInnerHTML(c) + '
'; const tileHTML = (c) => { const state = ({ licht:['Stehlampe','Szene · Abend','live','toggle'], heizung:['Bad','21,5° · warm','live','toggle'], beschattung:['Rollläden','fahren herunter','live','toggle'], energie:['PV-Überschuss','2,4 kW → Speicher','live','bars'], wallbox:['Wallbox','lädt mit Sonne','live','bars'], sicherheit:['Alles sicher','Türen zu · Nacht','live','toggle'], audio:['Multiroom','Playlist · 3 Räume','live','toggle'] })[c.id] || ['','']; const ctrl = state[3] === 'bars' ? '
' : ''; const barsTile = state[3] === 'bars'; return '
'+c.scene+''+c.time+'
'+(barsTile?'
'+ICON[c.icon]+'
'+state[0]+'
'+state[1]+'
'+ctrl:''+ICON[c.icon]+'
'+state[0]+'
'+state[1]+'
'+ctrl)+'
'+ICON.check+'
Automatik
'+c.scene+'
'; }; const renderApp = (c) => '
'+tileHTML(c)+'
'+c.time+' · '+c.scene+'

'+c.h2+'

'+c.body+'

Das ist dabei
'+chipsHTML(c.equip)+'
'+ICON.bolt+' Eine App für alles — die ganze Familie
'; const CASES_SORTED = CASES.slice().sort((a,b) => { const m=(t)=>{const p=t.split(':');return (+p[0])*60+(+p[1]);}; return m(a.time)-m(b.time); }); const chipsEl = root.querySelector('#dayChips'); chipsEl.innerHTML = CASES_SORTED.map((c) => ''+c.scene+'').join(''); let io = null; const observe = () => { if (io) io.disconnect(); io = new IntersectionObserver((entries) => { entries.forEach((en) => { if (en.isIntersecting) en.target.classList.add('in'); }); }, { threshold: 0.25 }); root.querySelectorAll('.uc').forEach((u) => io.observe(u)); }; const host = root.querySelector('#cases'); if (variant === 'app') { host.innerHTML = CASES_SORTED.map(renderApp).join(''); } else { const timelineHTML = '
' + '
' + CASES_SORTED.map(renderTlEntry).join('') + '
' + '
'+(CASES_SORTED[0] ? CASES_SORTED[0].time : '')+'' + '
' + CASES_SORTED.map(renderTlStageItem).join('') + '
' + '
'; host.innerHTML = timelineHTML + '
' + CASES_SORTED.map(renderStory).join('') + '
'; } // Vorher/Nachher-Vergleich + Play-on-demand (nur variant="story"). const teardowns = []; const on = (el, ev, handler, opts) => { el.addEventListener(ev, handler, opts); teardowns.push(() => el.removeEventListener(ev, handler, opts)); }; const clamp01 = (n) => Math.max(0, Math.min(100, n)); root.querySelectorAll('.uc-stage').forEach((stage) => { const card = stage.closest('.uc'); const video = stage.querySelector('.uc-video'); const divider = stage.querySelector('.uc-divider'); const playBtn = stage.querySelector('.uc-play'); const closeBtn = stage.querySelector('.uc-close'); const isFallback = () => stage.classList.contains('fallback'); const playVideo = () => { if (!video) return; try { video.currentTime = 0; } catch (err) {} video.play().catch(() => {}); }; const resetVideo = () => { if (!video) return; video.pause(); try { video.currentTime = 0; } catch (err) {} }; // Fallback (fehlendes Vorher-Bild): altes Poster+Hover-Video-Verhalten. if (card && video) { on(card, 'pointerenter', () => { if (isFallback()) playVideo(); }); on(card, 'focusin', () => { if (isFallback()) playVideo(); }); on(card, 'pointerleave', () => { if (isFallback()) resetVideo(); }); on(card, 'focusout', () => { if (isFallback()) resetVideo(); }); } // Play-Overlay: klick blendet Vergleich aus, spielt Video, bis ✕ geklickt wird. if (playBtn) on(playBtn, 'click', () => { stage.classList.add('playing'); playVideo(); }); if (closeBtn) on(closeBtn, 'click', () => { stage.classList.remove('playing'); resetVideo(); }); // Drag-Divider fuer den Bildvergleich. if (!divider) return; const setSplit = (pct) => { const clamped = clamp01(pct); stage.style.setProperty('--split', clamped + '%'); divider.setAttribute('aria-valuenow', String(Math.round(clamped))); }; const pctFromClientX = (clientX) => { const rect = stage.getBoundingClientRect(); return ((clientX - rect.left) / rect.width) * 100; }; let dragging = false; const onPointerDown = (e) => { dragging = true; try { divider.setPointerCapture(e.pointerId); } catch (err) {} setSplit(pctFromClientX(e.clientX)); e.preventDefault(); }; const onPointerMove = (e) => { if (dragging) setSplit(pctFromClientX(e.clientX)); }; const onPointerUp = (e) => { if (!dragging) return; dragging = false; try { divider.releasePointerCapture(e.pointerId); } catch (err) {} }; const onKeydown = (e) => { const current = parseFloat(divider.getAttribute('aria-valuenow')) || 50; if (e.key === 'ArrowLeft') { setSplit(current - 5); e.preventDefault(); } else if (e.key === 'ArrowRight') { setSplit(current + 5); e.preventDefault(); } }; on(divider, 'pointerdown', onPointerDown); on(divider, 'pointermove', onPointerMove); on(divider, 'pointerup', onPointerUp); on(divider, 'pointercancel', onPointerUp); on(divider, 'keydown', onKeydown); }); // Timeline-Scrollsync (nur variant="story"): IntersectionObserver auf den // linken Eintraegen schaltet die rechte sticky Buehne + das Zeit-Badge um. let tlIo = null; let tlStageIo = null; let mobileVideoIo = null; if (variant !== 'app') { const tlEntries = Array.from(root.querySelectorAll('.tl-entry')); const tlStageItems = Array.from(root.querySelectorAll('.tl-stage-item')); const tlBadge = root.querySelector('#tlBadge'); let activeCaseId = CASES_SORTED[0] && CASES_SORTED[0].id; let stageInView = true; const startStageVideo = (stage, video, restart) => { if (!stage || !video || reducedMotion) return; if (!stage.classList.contains('fallback')) stage.classList.add('playing'); video.loop = true; video.muted = true; video.setAttribute('muted', ''); video.setAttribute('playsinline', ''); if (restart) { try { video.currentTime = 0; } catch (err) {} } const attemptPlay = () => video.play().catch(() => {}); if (video.readyState < 2) { video.load(); video.addEventListener('canplay', attemptPlay, { once: true }); } attemptPlay(); }; const stopStageVideo = (stage, video, reset) => { if (stage) stage.classList.remove('playing'); if (!video) return; video.pause(); if (reset) { try { video.currentTime = 0; } catch (err) {} } }; const playActiveCase = (restart) => { const activeItem = tlStageItems.find((si) => si.dataset.id === activeCaseId); if (!activeItem) return; const stage = activeItem.querySelector('.uc-stage'); const video = stage && stage.querySelector('.uc-video'); startStageVideo(stage, video, restart); }; const setActiveCase = (id) => { const changed = activeCaseId !== id; activeCaseId = id; tlEntries.forEach((en) => en.classList.toggle('active', en.dataset.id === id)); tlStageItems.forEach((si) => { const isActive = si.dataset.id === id; si.classList.toggle('active', isActive); const st = si.querySelector('.uc-stage'); const v = st && st.querySelector('.uc-video'); if (!isActive) { stopStageVideo(st, v, true); } else if (stageInView) { // Autoplay: das aktive Anwendungsvideo laeuft automatisch (muted, loop) statt Play-Klick. startStageVideo(st, v, changed); } }); const active = CASES_SORTED.find((c) => c.id === id); if (tlBadge && active) tlBadge.textContent = active.time; }; if (tlEntries.length) { setActiveCase(activeCaseId); const stageBox = root.querySelector('.tl-stage-sticky'); if (stageBox) { tlStageIo = new IntersectionObserver((stageEntries) => { stageInView = stageEntries.some((en) => en.isIntersecting); if (stageInView) playActiveCase(false); else { tlStageItems.forEach((si) => { const st = si.querySelector('.uc-stage'); const v = st && st.querySelector('.uc-video'); stopStageVideo(st, v, false); }); } }, { threshold: 0.2 }); tlStageIo.observe(stageBox); } tlIo = new IntersectionObserver((ioEntries) => { const visible = ioEntries.filter((en) => en.isIntersecting); if (!visible.length) return; const centerY = window.innerHeight * 0.5; let best = visible[0], bestDist = Infinity; visible.forEach((en) => { const r = en.target.getBoundingClientRect(); const dist = Math.abs((r.top + r.height / 2) - centerY); if (dist < bestDist) { bestDist = dist; best = en; } }); setActiveCase(best.target.dataset.id); }, { rootMargin: '-40% 0px -40% 0px', threshold: 0 }); tlEntries.forEach((en) => tlIo.observe(en)); // F4: Timeline-Eintraege klickbar — pinnt die Szene gezielt (statt nur per Scroll), // damit man eine Anwendung anwaehlen und deren Video abspielen kann. Behebt das // User-Feedback "klickbar machen" + "Audio-Video liess sich nicht abspielen" (Scroll // sprang vorher weg, bevor man Play treffen konnte). tlEntries.forEach((en) => { en.style.cursor = 'pointer'; on(en, 'click', () => { setActiveCase(en.dataset.id); en.scrollIntoView({ behavior: 'smooth', block: 'center' }); }); }); } const mobileStages = Array.from(root.querySelectorAll('.cases-mobile .uc-stage')); if (mobileStages.length && !reducedMotion) { mobileVideoIo = new IntersectionObserver((stageEntries) => { const mobileLayout = window.matchMedia('(max-width: 880px)').matches; stageEntries.forEach((entry) => { const st = entry.target; const v = st.querySelector('.uc-video'); if (mobileLayout && entry.isIntersecting) startStageVideo(st, v, false); else stopStageVideo(st, v, false); }); }, { threshold: 0.45 }); mobileStages.forEach((st) => mobileVideoIo.observe(st)); } } // flex card const ic = root.querySelector('.flex-ic'); if (ic) ic.innerHTML = ICON.signal; const eq = root.querySelector('.flex-equip'); if (eq) eq.innerHTML = ['Funk, Kabel oder Mix','Herstellerneutral','Alle gängigen Standards'].map((e) => ''+CHIP_ICON+e+'').join(''); observe(); // Anchor-scroll for daychips: zielt je nach Breakpoint auf den Timeline-Eintrag // (Desktop) oder die gestapelte Karte (Mobile-Fallback). const onChip = (e) => { const a = e.target.closest('.daychip'); if (!a) return; e.preventDefault(); const id = (a.getAttribute('href') || '').replace('#uc-', ''); const isDesktop = window.matchMedia('(min-width:881px)').matches; const el = isDesktop ? root.querySelector('.tl-entry[data-id="'+id+'"]') : root.querySelector('#uc-'+id); if (el) el.scrollIntoView({ behavior:'smooth', block:'center' }); }; chipsEl.addEventListener('click', onChip); return () => { if (io) io.disconnect(); if (tlIo) tlIo.disconnect(); if (tlStageIo) tlStageIo.disconnect(); if (mobileVideoIo) mobileVideoIo.disconnect(); chipsEl.removeEventListener('click', onChip); teardowns.forEach((fn) => fn()); }; }, [variant]); return (
); } window.AnwendungSection = AnwendungSection;