1/* Simon Huck â Website-Interaktionen (kein Framework, minimal) */ 2(function () { 3 'use strict'; 4 5 /* ---------- Anker-Sprung beim Laden reparieren ---------- 6 Bug (gefunden 04.08.2026, siehe GOLIVE-CHECKLISTE.md): html { scroll-behavior: smooth } 7 bricht in Chrome das automatische Springen zum URL-Anker beim Seitenaufruf, weil 8 Bilder/Fonts während des Ladens die Scroll-Animation unterbrechen, bevor sie ankommt. 9 Betrifft z. B. kontakt.htmlâ/#kontakt oder digital-check.html#zusammenarbeit. 10 Fix: nach vollständigem Laden manuell (ohne Smooth-Animation) zum Ziel springen. */ 11 function scrollToHashOnLoad() { 12 if (!location.hash) return; 13 var id = decodeURIComponent(location.hash.slice(1)); 14 var target = document.getElementById(id); 15 if (!target) return; 16 target.scrollIntoView({ behavior: 'auto', block: 'start' }); 17 } 18 window.addEventListener('load', scrollToHashOnLoad); 19 20 /* ---------- Jahr im Footer ---------- */ 21 document.querySelectorAll('[data-year]').forEach(function (el) { 22 el.textContent = new Date().getFullYear(); 23 }); 24 25 /* ---------- Mobile-Menü ---------- */ 26 var mToggle = document.querySelector('[data-mobile-toggle]'); 27 var mMenu = document.querySelector('[data-mobile-menu]'); 28 if (mToggle && mMenu) { 29 mToggle.addEventListener('click', function () { 30 var open = mMenu.classList.toggle('hidden') === false; 31 mToggle.setAttribute('aria-expanded', String(open)); 32 }); 33 } 34 35 /* ---------- Dropdown (Tastatur-Zugänglichkeit; Hover per CSS) ---------- */ 36 var ddToggle = document.querySelector('[data-dropdown-toggle]'); 37 var ddMenu = document.querySelector('[data-dropdown-menu]'); 38 if (ddToggle && ddMenu) { 39 ddToggle.addEventListener('click', function (e) { 40 e.preventDefault(); 41 var open = ddMenu.classList.toggle('hidden') === false; 42 ddToggle.setAttribute('aria-expanded', String(open)); 43 }); 44 document.addEventListener('keydown', function (e) { 45 if (e.key === 'Escape') { ddMenu.classList.add('hidden'); ddToggle.setAttribute('aria-expanded', 'false'); } 46 }); 47 } 48 49 /* ---------- Fly-In ---------- 50 Das Fly-In (Foto + Termin-CTA) wird NICHT mehr im Code umgesetzt, 51 sondern als Pop-up-Formular direkt in HubSpot verwaltet und über das 52 HubSpot-Tracking-Skript ausgeliefert (Cookiebot-gated). Konfiguration: 53 siehe website-neu/HUBSPOT-FLYIN.md 54 */ 55 56 /* ---------- HubSpot-Formular (Cookiebot-konform) ---------- 57 Lädt das HubSpot-Formular erst nach Marketing-Consent. 58 Markup-Anker: #hs-form-placeholder / #hs-form-container / [data-hs-load] 59 */ 60 var HS = { region: 'eu1', portalId: '145327216', formId: '67758ebd-1db7-4225-adf9-0e5a96a7eaf7' }; 61 var hsLoaded = false; 62 63 function loadHubSpotForm() { 64 if (hsLoaded) return; 65 var container = document.getElementById('hs-form-container'); 66 if (!container) return; 67 hsLoaded = true; 68 var s = document.createElement('script'); 69 s.src = 'https://js-eu1.hsforms.net/forms/embed/v2.js'; 70 s.charset = 'utf-8'; 71 s.type = 'text/javascript'; 72 s.onload = function () { 73 if (!window.hbspt) return; 74 window.hbspt.forms.create({ 75 region: HS.region, 76 portalId: HS.portalId, 77 formId: HS.formId, 78 target: '#hs-form-container', 79 cssClass: 'hs-form', 80 onFormSubmit: function () { 81 // Google-Ads-Conversion-Tracking (aus altem kontakt.html übernommen, 04.08.2026 â 82 // ging beim Rebuild verloren, siehe GOLIVE-CHECKLISTE.md). 83 if (window.__googleAdsLeadConversionFired) return; 84 if (typeof window.gtag !== 'function') return; 85 window.__googleAdsLeadConversionFired = true; 86 window.gtag('event', 'conversion', { 87 'send_to': 'AW-17523896240/iEBTCIGr_5EbELDfhaRB', 88 'value': 1.0, 89 'currency': 'EUR' 90 }); 91 } 92 }); 93 }; 94 document.head.appendChild(s); 95 } 96 function revealForm() { 97 var ph = document.getElementById('hs-form-placeholder'); 98 var c = document.getElementById('hs-form-container'); 99 if (ph) ph.style.display = 'none'; 100 if (c) c.style.display = 'block'; 101 loadHubSpotForm(); 102 } 103 function hasMarketingConsent() { 104 return typeof window.Cookiebot !== 'undefined' && window.Cookiebot.consent && window.Cookiebot.consent.marketing; 105 } 106 window.addEventListener('CookiebotOnLoad', function () { if (hasMarketingConsent()) revealForm(); }); 107 window.addEventListener('CookiebotOnAccept', function () { if (hasMarketingConsent()) revealForm(); }); 108 var loadBtn = document.querySelector('[data-hs-load]'); 109 if (loadBtn) { 110 loadBtn.addEventListener('click', function () { 111 if (typeof window.Cookiebot !== 'undefined' && window.Cookiebot.show) window.Cookiebot.show(); 112 }); 113 } 114})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.