Baufinanzierung Augsburg & Königsbrunn · Yasin Demir Finanzierungen
Baufinanzierung Augsburg · Königsbrunn

Dein Zuhause. Finanziert wie von einem guten Freund.

Ich vergleiche für dich über 400 Bankpartner und suche die Kondition, die wirklich zu dir passt. Persönlich, ehrlich und für dich komplett kostenlos.

seit 2012in der Finanzierung
400+Bankpartner im Vergleich
0 €Kosten für dich
%Finanzierung - %Augsburg
€
Beratung kostenlosund komplett unverbindlich
%
Du entscheidestaus den besten Angeboten
So entsteht dein Zuhause

Stein für Stein finanziert.

1Fundament

Dein Eigenkapital

Erspartes, Bausparvertrag oder Eigenleistung. Wir schauen gemeinsam, was du sinnvoll einbringst.

2Wände

Das passende Darlehen

Aus über 400 Bankpartnern suche ich die bestmögliche Kondition und stelle dir die besten Angebote vor.

3Dach

Staatliche Förderungen

Passende Förderprogramme binde ich direkt mit ein, damit nichts liegen bleibt.

4Schlüssel

Dein Zuhause

Du hast immer das letzte Wort. Und auch nach dem Abschluss bin ich gerne weiter für dich da.

%Finanzierung - %Augsburg
Geschafft

Willkommen daheim.

Von der ersten Idee bis zum Schlüssel: Ich begleite dich auf dem Weg zur passenden Baufinanzierung, individuell, persönlich und schnell.

Jetzt Termin vereinbaren

Nicht einfach die Hausbank. Die beste Bank für dich.

Der Markt ist unübersichtlich, die Zahl der Anbieter enorm. Viele finanzieren deshalb nur über ihre Hausbank. Ich nehme dir diese Suche ab.

Unabhängig am Markt

Ein Gespräch. Hunderte Banken.

Statt einem Angebot bekommst du einen echten Vergleich. Ich stelle dir die besten Konditionen vor, du wählst aus.

400+

Bankpartner im Vergleich

Tätig für: Deutsche Bank · Interhyp · Check24 · Raiffeisenbank

%Finanzierung - %Augsburg
GroßbankenSparkassenVolks- & RaiffeisenbankenDirektbankenBausparkassenVersichererFörderbankenRegionalbanken
Budget-Rechner

Wie viel Haus kann ich mir leisten?

Schieb die Regler und sieh live, welcher Kaufpreis für dich drin ist. Danach schauen wir gemeinsam, welche Bank das am günstigsten möglich macht.

Faustregel: etwa ein Drittel des Nettoeinkommens.
Frei wählbarer Beispielwert. Deinen echten Zins ermittle ich im Vergleich.

Möglicher Kaufpreis

0 €
bei einer Monatsrate von
EigenkapitalDarlehenNebenkosten
Darlehen
Kaufnebenkosten
Restschuld nach 10 Jahren
Schuldenfrei nach etwa
10 J.
Dein Eigenkapital deckt die Kaufnebenkosten noch nicht. Das ist lösbar, sprich mich einfach darauf an.
Ergebnis an Yasin schicken

Unverbindliche Beispielrechnung, kein Angebot. Kaufnebenkosten für Bayern: Grunderwerbsteuer 3,5 %, Notar und Grundbuch ca. 2 %, optional Makler 3,57 %. Konditionen hängen von Bonität, Objekt und Marktlage ab.

Kurze Pause gefällig?

Jag die besten Zinsen.

Zwei kleine Spiele rund ums Finanzieren. Im echten Leben übernehme ich das Jagen für dich.

Zinsjäger

⏱ 30 s★ 0

Fang die niedrigen Zinsen!

Bewege das Haus mit Maus, Finger oder Pfeiltasten. Blaue Zinsen und Münzen bringen Punkte, rote Zinsen kosten welche. Du hast 30 Sekunden.

Mythos oder Fakt?

0 / 6
So läuft's ab

Einfach reden. Den Rest mache ich.

1
KennenlernenIm ersten Gespräch erkläre ich dir die nächsten Schritte. Termine sind jederzeit individuell vereinbar.
2
VergleichIch suche aus über 400 Bankpartnern die bestmögliche Kondition für dein Vorhaben.
3
AuswahlIch stelle dir die besten Angebote vor, mit Vor- und Nachteilen. Du wählst aus.
4
BegleitungAuch nach der Vermittlung betreue ich dich gerne weiter.
%Finanzierung - %Augsburg
Yasin Demir● online

Hi Yasin, wir wollen ein Haus kaufen. Wo fangen wir an?

Mit einem ersten Gespräch. Da erkläre ich euch die nächsten Schritte, unverbindlich und komplett kostenlos.

Warum nicht einfach zu unserer Hausbank?

Könnt ihr machen. Ich vergleiche aber über 400 Bankpartner und zeige euch die besten Angebote. Ihr sucht aus.

Fallen beim Abschluss Kosten für uns an?

Nein, keine weiteren Kosten. Und ihr habt immer das letzte Wort.

Abgeschlossene Projekte

Zu Hause in Königsbrunn. Unterwegs für ganz Deutschland.

Von Bobingen bis Hamburg: Hier habe ich bereits Finanzierungen erfolgreich begleitet. Das Radar zeigt Richtung und Entfernung von meinem Büro aus.

%Finanzierung - %AugsburgPorträtfoto von Yasin hier einsetzen (Hochformat, freundlich, gerne im Gespräch)
„Beraten wie bei einem guten Freund. Fair & ehrlich.“Yasin Demir
Über mich

Hi, ich bin Yasin.

Seit 2012 begleite ich meine Kunden rund um das Thema Finanzierung. Jeder hat andere Wünsche und Vorstellungen. Meine Aufgabe ist es, den passenden Finanzierungspartner dafür zu finden. Ich nehme mir viel Zeit für dich und zeige dir auch Alternativen, damit wir über Vor- und Nachteile sprechen können.

  • Individuelle Finanzierungslösungen
  • Offene, ehrliche und faire Meinung
  • Mobil & flexibel, Termine nach Absprache
  • Unabhängig am Markt
  • Einbindung staatlicher Förderungen
14Jahre Erfahrung
400+Bankpartner
Kundenstimmen

Was Kunden sagen.

Echte Google-Bewertung einsetzen (Text wörtlich übernehmen)

Name, Ort

Echte Google-Bewertung einsetzen

Name, Ort

Echte Google-Bewertung einsetzen

Name, Ort
Häufige Fragen

Kurz beantwortet.

Fallen beim Abschluss eines Darlehens Kosten für mich an?

Nein, keine weiteren Kosten. Meine Beratung ist unverbindlich und komplett kostenlos.

Ist das Anfordern eines Angebots verbindlich?

Nein, komplett unverbindlich. Du hast immer das letzte Wort.

Mit welchen Banken arbeitest du?

Ich vergleiche über 400 Bankpartner und stelle dir im Anschluss die besten Angebote vor. So findest du nicht nur das Angebot deiner Hausbank, sondern die bestmögliche Kondition für dich.

Wie geht es nach der Vermittlung weiter?

Gerne betreue ich dich weiterhin bei deinem Anliegen.

Wo findet die Beratung statt?

Mein Büro ist in Königsbrunn bei Augsburg. Ich bin mobil und flexibel, Termine sind jederzeit individuell vereinbar. Finanzierungen begleite ich auch deutschlandweit.

Kontakt

Lass uns über dein Zuhause sprechen.

Jetzt unverbindlich und kostenlos beraten lassen. Ich freue mich auf dich.

Mo–Fr 8:30–17:00 Uhr
Dein Vorhaben
Formular wird beim Einbau angebunden.
`; I('zAgain').onclick = start; return; } requestAnimationFrame(step); } function start() { items = []; pops = []; score = 0; spawn = 0; over.style.display = 'none'; running = true; last = performance.now(); end = last + 30000; requestAnimationFrame(step); } I('zStart').onclick = start; })(); /* ---------- QUIZ ---------- */ (() => { const Q = [ ['Die Hausbank hat automatisch die besten Konditionen.', 0, 'Das muss nicht sein. Konditionen unterscheiden sich von Bank zu Bank, deshalb lohnt sich ein Vergleich.'], ['Ein Darlehen mit langer Zinsbindung kann man nach 10 Jahren mit einer Frist von 6 Monaten kündigen.', 1, 'Stimmt. Das gesetzliche Kündigungsrecht nach § 489 BGB gilt zehn Jahre nach vollständigem Empfang des Darlehens.'], ['Ohne Eigenkapital ist eine Baufinanzierung unmöglich.', 0, 'Nicht unbedingt. Je nach Bonität sind auch Finanzierungen mit wenig Eigenkapital möglich, meist aber zu einem höheren Zins.'], ['In Bayern beträgt die Grunderwerbsteuer 3,5 %.', 1, 'Richtig. Bayern hat mit 3,5 % den niedrigsten Satz in Deutschland.'], ['Sondertilgungen sind immer kostenlos möglich.', 0, 'Nur, wenn sie im Darlehensvertrag vereinbart sind. Darauf achten wir beim Vergleich.'], ['Meine Beratung bei Yasin kostet nichts.', 1, 'Fakt. Die Beratung ist unverbindlich und komplett kostenlos, und du hast immer das letzte Wort.']]; let i = 0, ok = 0; const box = I('quiz'), prog = I('qProg'); prog.innerHTML = Q.map(() => '').join(''); function show() { $$('#qProg i').forEach((el, k) => el.classList.toggle('cur', k === i)); if (i >= Q.length) { box.innerHTML = `
Ergebnis

${ok} von ${Q.length} richtig. ${ok >= 5 ? 'Du kennst dich aus!' : ok >= 3 ? 'Gut gemacht!' : 'Jetzt weißt du mehr als vorher.'}

`; I('qAgain').onclick = () => { i = 0; ok = 0; $$('#qProg i').forEach(e => e.className = ''); I('qScore').textContent = '0 / ' + Q.length; show(); }; return; } const [s] = Q[i]; box.innerHTML = `
Aussage ${i + 1} von ${Q.length}

${s}

`; $$('.qbtns button', box).forEach(b => b.onclick = () => answer(+b.dataset.v)); } function answer(v) { const [, f, e] = Q[i], right = v === f; if (right) ok++; $$('#qProg i')[i].className = right ? 'ok' : 'no'; I('qScore').textContent = ok + ' / ' + Q.length; const c = $('.qcard', box); c.querySelector('.qbtns').outerHTML = `
${right ? 'Richtig!' : 'Nicht ganz.'} Das ist ein ${f ? 'Fakt' : 'Mythos'}.${e}
`; I('qNext').onclick = () => { i++; show(); }; } show(); })(); /* ---------- CHAT TAKEOVER ---------- */ $$('.ct').forEach(ct => { if (RM || !hasG) return; const msgs = $$('.ct-m', ct); gsap.set(msgs, { display: 'none' }); ScrollTrigger.create({ trigger: ct, start: 'top 75%', once: true, onEnter: () => { const tl = gsap.timeline(); msgs.forEach(m => { const out = m.dataset.side === 'out', ty = document.createElement('div'); ty.className = 'ct-typing' + (out ? ' out' : ''); ty.style.color = out ? '#fff' : '#0d1b2e'; ty.innerHTML = ''; ty.setAttribute('aria-hidden', 'true'); tl.call(() => m.before(ty)).to({}, { duration: Math.min(1.2, .35 + m.textContent.length * .012) }).call(() => { ty.remove(); gsap.set(m, { display: 'block' }); }) .from(m, { scale: .85, opacity: 0, y: 8, duration: .35, ease: 'back.out(1.8)' }).to({}, { duration: .25 }); }); tl.call(() => ScrollTrigger.refresh()); } }); }); /* ---------- CHECKLIST POP ---------- */ $$('.cl li').forEach(li => { const p = li.querySelector('path'), l = p.getTotalLength(); p.style.strokeDasharray = l; p.style.strokeDashoffset = RM || !hasG ? 0 : l; }); if (hasG && !RM) ScrollTrigger.batch('.cl li', { start: 'top 88%', once: true, onEnter: batch => { const tl = gsap.timeline(); batch.forEach((li, k) => tl.from(li, { x: -18, opacity: 0, duration: .5, ease: 'expo.out' }, k * .12).from(li.querySelector('circle'), { scale: .3, duration: .5, ease: 'back.out(2.4)' }, k * .12 + .05).to(li.querySelector('path'), { strokeDashoffset: 0, duration: .35, ease: 'power2.out' }, k * .12 + .25)); } }); /* ---------- RADAR: Projekte nach Richtung und Entfernung ---------- */ (() => { const HOME = [48.268, 10.889]; const C = [['Bobingen', 48.271, 10.835], ['Wehringen', 48.25, 10.80], ['Großaitingen', 48.228, 10.78], ['Augsburg', 48.371, 10.898], ['Göggingen', 48.34, 10.87], ['Graben', 48.19, 10.83], ['Lagerlechfeld', 48.214, 10.856], ['Untermeitingen', 48.16, 10.80], ['Schwabmünchen', 48.18, 10.76], ['Dinkelscherben', 48.35, 10.59], ['Landsberg', 48.05, 10.87], ['Fürstenfeldbruck', 48.18, 11.25], ['München', 48.14, 11.58], ['Ingolstadt', 48.77, 11.42], ['Ulm', 48.40, 9.99], ['Nürnberg', 49.45, 11.08], ['Leipzig', 51.34, 12.37], ['Köln', 50.94, 6.96], ['Osnabrück', 52.28, 8.05], ['Hannover', 52.37, 9.73], ['Berlin', 52.52, 13.40], ['Hamburg', 53.55, 9.99]]; const svg = I('radar'), ns = 'http://www.w3.org/2000/svg', el = (n, a, p) => { const e = document.createElementNS(ns, n); for (const k in a) e.setAttribute(k, a[k]); (p || svg).appendChild(e); return e; }; const R = 270, maxKm = 700, rr = km => R * Math.log(1 + km / 6) / Math.log(1 + maxKm / 6); const toRad = d => d * Math.PI / 180; const geo = (la, lo) => { const dy = (la - HOME[0]) * 111.2, dx = (lo - HOME[1]) * 111.2 * Math.cos(toRad(HOME[0])); return [Math.hypot(dx, dy), Math.atan2(dx, dy)]; }; const defs = el('defs'); const g = el('linearGradient', { id: 'sw', x1: '0', y1: '0', x2: '1', y2: '0' }, defs); el('stop', { offset: '0', 'stop-color': 'rgba(26,138,212,0)' }, g); el('stop', { offset: '1', 'stop-color': 'rgba(26,138,212,.35)' }, g); el('circle', { cx: 300, cy: 300, r: R + 8, fill: '#fff' }); [10, 50, 200, 600].forEach(km => { el('circle', { class: 'ring', cx: 300, cy: 300, r: rr(km) }); const t = el('text', { class: 'rl', x: 304, y: 300 - rr(km) + 14 }); t.textContent = km + ' km'; }); ['N', 'O', 'S', 'W'].forEach((d, i) => { const a = i * Math.PI / 2, t = el('text', { class: 'rl', x: 300 + Math.sin(a) * (R + 22) - 4, y: 300 - Math.cos(a) * (R + 22) + 4 }); t.textContent = d; }); const sweep = el('g', { class: 'sweep' }); el('path', { d: `M300 300 L${300 + R} 300 A${R} ${R} 0 0 0 ${300 + R * Math.cos(-.6)} ${300 + R * Math.sin(-.6)} Z`, fill: 'url(#sw)' }, sweep); el('line', { x1: 300, y1: 300, x2: 300 + R, y2: 300, stroke: 'rgba(26,138,212,.6)', 'stroke-width': 2 }, sweep); const home = el('g', { class: 'pin home lab' }); el('circle', { cx: 300, cy: 300, r: 8 }, home); const ht = el('text', { x: 312, y: 318 }, home); ht.textContent = 'Königsbrunn'; const pins = C.map(([n, la, lo]) => { const [d, b] = geo(la, lo), r = rr(d), x = 300 + Math.sin(b) * r, y = 300 - Math.cos(b) * r, gp = el('g', { class: 'pin' }); const halo = el('circle', { class: 'halo', cx: x, cy: y, r: 9 }, gp); el('circle', { cx: x, cy: y, r: 5 }, gp); const t = el('text', { x: x + 9, y: y - 8 }, gp); t.textContent = n + ' · ' + Math.round(d) + ' km'; return { n, ang: (b * 180 / Math.PI + 360) % 360, gp, halo }; }); const list = I('cities'); pins.forEach(p => { const s = document.createElement('span'); s.textContent = p.n; p.chip = s; list.appendChild(s); }); if (RM) { pins.forEach(p => p.chip.classList.add('hit')); return; } let a0 = 0, vis = false; new IntersectionObserver(es => vis = es[0].isIntersecting).observe(svg); (function tick() { requestAnimationFrame(tick); if (!vis) return; a0 = (a0 + .6) % 360; sweep.setAttribute('transform', `rotate(${a0 - 90} 300 300)`); pins.forEach(p => { const diff = (a0 - p.ang + 360) % 360; const k = diff < 30 ? 1 - diff / 30 : 0; p.halo.setAttribute('r', 9 + k * 10); p.halo.style.opacity = k; p.gp.classList.toggle('lab', k > .15); if (diff < 4) { p.chip.classList.add('hit'); setTimeout(() => p.chip.classList.remove('hit'), 900); } }); })(); })(); /* ---------- HÄNGENDER SCHLÜSSELANHÄNGER (Verlet) ---------- */ $$('[data-hang]').forEach(root => { const svg = $('svg', root), strap = $('path.strap', root), hl = $('path.hl', root), card = $('.tag', root); const N = 14, G = .55, IT = 10; let W, Hh, ax, sg, pts = [], drag = null, moved = false, ang = 0, angV = 0, mouse = null, lm = null; function init() { W = root.clientWidth; Hh = root.clientHeight; ax = W * +(mobile() ? .84 : root.dataset.x); sg = Hh * +(mobile() ? .16 : root.dataset.len) / N; pts = []; for (let i = 0; i <= N; i++) { const y = RM ? i * sg : -Hh * .3 + i * sg * .3, x = ax + (RM ? 0 : i / N * 40); pts.push({ x, y, ox: x, oy: y }); } svg.setAttribute('viewBox', `0 0 ${W} ${Hh}`); } function step() { const last = pts[N]; for (let i = 1; i <= N; i++) { const p = pts[i]; if (drag && i === N) continue; let vx = (p.x - p.ox) * .985, vy = (p.y - p.oy) * .985; const sp = Math.hypot(vx, vy); if (sp > 17) { vx *= 17 / sp; vy *= 17 / sp; } if (mouse) { const dx = p.x - mouse.x, dy = p.y - mouse.y; if (dx * dx + dy * dy < 9000) { vx += mouse.vx * .04; vy += mouse.vy * .02; } } p.ox = p.x; p.oy = p.y; p.x += vx; p.y += vy + G * (i === N ? 2.2 : 1); } if (drag) { last.x = drag.x; last.y = drag.y; } for (let k = 0; k < IT; k++) { pts[0].x = ax; pts[0].y = 0; for (let i = 0; i < N; i++) { const a = pts[i], b = pts[i + 1], dx = b.x - a.x, dy = b.y - a.y, d = Math.hypot(dx, dy) || 1e-4; if (d < sg) continue; const df = (d - sg) / d, fa = i === 0 ? 0 : (drag && i + 1 === N ? 1 : .5), fb = (drag && i + 1 === N) ? 0 : (i === 0 ? 1 : .5); a.x += dx * df * fa; a.y += dy * df * fa; b.x -= dx * df * fb; b.y -= dy * df * fb; } } const p1 = pts[N - 2], p2 = pts[N], tg = -Math.atan2(p2.x - p1.x, p2.y - p1.y); angV = (angV + (tg - ang) * .12) * .86; ang += angV; } function draw() { let d = `M ${pts[0].x} ${pts[0].y}`; for (let i = 1; i < N; i++) { const mx = (pts[i].x + pts[i + 1].x) / 2, my = (pts[i].y + pts[i + 1].y) / 2; d += ` Q ${pts[i].x} ${pts[i].y} ${mx} ${my}`; } d += ` L ${pts[N].x} ${pts[N].y}`; strap.setAttribute('d', d); hl.setAttribute('d', d); card.style.transform = `translate(${pts[N].x - card.offsetWidth / 2}px, ${pts[N].y - 6}px) rotate(${ang}rad)`; } const loc = e => { const r = root.getBoundingClientRect(); return { x: e.clientX - r.left, y: e.clientY - r.top }; }; card.addEventListener('pointerdown', e => { e.preventDefault(); card.setPointerCapture(e.pointerId); drag = loc(e); moved = false; card.classList.add('drag'); }); card.addEventListener('pointermove', e => { if (!drag) return; const q = loc(e); if (Math.hypot(q.x - drag.x, q.y - drag.y) > 3) moved = true; drag = { x: q.x, y: q.y - 20 }; }); const up = () => { drag = null; card.classList.remove('drag'); }; card.addEventListener('pointerup', up); card.addEventListener('pointercancel', up); card.addEventListener('click', e => { if (moved) { e.preventDefault(); e.stopImmediatePropagation(); } }, true); card.addEventListener('keydown', e => { if (e.key === ' ') { e.preventDefault(); pts[N].ox = pts[N].x - 18; } }); root.parentElement.addEventListener('pointermove', e => { const q = loc(e); mouse = lm ? { x: q.x, y: q.y, vx: q.x - lm.x, vy: q.y - lm.y } : null; lm = q; }); root.parentElement.addEventListener('pointerleave', () => { mouse = null; lm = null; }); let lastW = 0; const resize = () => { const w = root.clientWidth; if (!lastW) { init(); lastW = w; return; } const oax = ax; W = w; Hh = root.clientHeight; ax = W * +(mobile() ? .84 : root.dataset.x); sg = Hh * +(mobile() ? .16 : root.dataset.len) / N; pts.forEach(q => { q.x += ax - oax; q.ox += ax - oax; }); svg.setAttribute('viewBox', `0 0 ${W} ${Hh}`); lastW = w; }; resize(); new ResizeObserver(() => { resize(); if (RM) { for (let k = 0; k < 200; k++) step(); draw(); } }).observe(root); if (RM) { for (let k = 0; k < 200; k++) step(); draw(); return; } let vis = true; new IntersectionObserver(es => vis = es[0].isIntersecting).observe(root); let lt = performance.now(); (function loop(now) { now = now || performance.now(); const n = Math.min(8, Math.max(1, Math.round((now - lt) / 16.7))); lt = now; if (vis) { for (let k = 0; k < n; k++) step(); draw(); } requestAnimationFrame(loop); })(); }); /* ---------- Formular ---------- */ I('form').addEventListener('submit', e => { e.preventDefault(); const f = e.target, req = $$('[required]', f), bad = req.filter(x => x.type === 'checkbox' ? !x.checked : !x.value.trim()); req.forEach(x => x.style.borderColor = ''); bad.forEach(x => x.style.borderColor = '#d0473a'); I('fNote').textContent = bad.length ? 'Bitte fülle die markierten Felder aus.' : 'Danke! Ich melde mich so schnell wie möglich bei dir.'; }); /* ---------- NAV: Blob folgt Hover und aktivem Bereich ---------- */ (() => { const nav = $('#nav'), blob = $('.nav-blob', nav), links = $$('a', nav), secs = links.map(a => $(a.getAttribute('href'))); let cur = -1, hov = -1; const put = i => { if (i < 0) { blob.style.opacity = 0; return; } const a = links[i]; blob.style.opacity = 1; blob.style.width = a.offsetWidth + 'px'; blob.style.transform = `translateX(${a.offsetLeft}px)`; blob.classList.toggle('h', hov >= 0 && hov !== cur); }; const upd = () => { put(hov >= 0 ? hov : cur); links.forEach((a, i) => a.classList.toggle('on', i === (hov >= 0 ? hov : cur))); }; links.forEach((a, i) => { a.addEventListener('pointerenter', () => { hov = i; upd(); }); a.addEventListener('focus', () => { hov = i; upd(); }); a.addEventListener('blur', () => { hov = -1; upd(); }); }); nav.addEventListener('pointerleave', () => { hov = -1; upd(); }); const spy = () => { let c = -1; secs.forEach((sec, i) => { if (sec && sec.getBoundingClientRect().top < innerHeight * .4) c = i; }); if (c !== cur) { cur = c; upd(); } }; addEventListener('scroll', spy, { passive: true }); addEventListener('resize', upd); spy(); })(); /* ---------- VOLLBILD-MENÜ: Kreis öffnet sich aus dem Button ---------- */ (() => { const btn = $('#menuBtn'), menu = $('#menu'), prev = $('#mlPrev'), links = $$('a', menu); $('#menuOffice').textContent = $('#office span').textContent; const set = open => { const r = btn.getBoundingClientRect(); menu.style.setProperty('--mx', (r.left + r.width / 2) + 'px'); menu.style.setProperty('--my', (r.top + r.height / 2) + 'px'); menu.classList.toggle('open', open); menu.setAttribute('aria-hidden', !open); btn.setAttribute('aria-expanded', open); document.body.classList.toggle('menu-open', open); hdr.classList.remove('hide'); hdr.style.zIndex = open ? 120 : ''; if (lenis) open ? lenis.stop() : lenis.start(); if (open) setTimeout(() => links[0].focus({ preventScroll: true }), 400); else { prev.style.opacity = 0; btn.focus({ preventScroll: true }); } }; btn.addEventListener('click', () => set(!menu.classList.contains('open'))); addEventListener('keydown', e => { if (e.key === 'Escape' && menu.classList.contains('open')) set(false); if (e.key === 'Tab' && menu.classList.contains('open')) { const f = [btn, ...links], i = f.indexOf(document.activeElement); if (e.shiftKey && i <= 0) { e.preventDefault(); f[f.length - 1].focus(); } else if (!e.shiftKey && i === f.length - 1) { e.preventDefault(); f[0].focus(); } } }); links.forEach(a => a.addEventListener('click', () => set(false), true)); if (RM || !hasG || !matchMedia('(hover:hover) and (pointer:fine)').matches) return; $$('.ml a[data-img]').forEach(a => { new Image().src = a.dataset.img; }); const xTo = gsap.quickTo(prev, 'x', { duration: .5, ease: 'power3.out' }), yTo = gsap.quickTo(prev, 'y', { duration: .5, ease: 'power3.out' }); $('.ml').addEventListener('pointermove', e => { xTo(e.clientX + 30); yTo(e.clientY - 180); }); $$('.ml a[data-img]').forEach(a => { a.addEventListener('pointerenter', () => { prev.src = a.dataset.img; gsap.to(prev, { opacity: 1, scale: 1, rotation: gsap.utils.random(-6, 6), duration: .35, ease: 'expo.out', overwrite: 'auto' }); }); a.addEventListener('pointerleave', () => gsap.to(prev, { opacity: 0, scale: .9, duration: .2, overwrite: 'auto' })); }); })(); /* ---------- BUTTONS: Pfeil, Ripple, Glanzpunkt, Magnet ---------- */ (() => { const AR = ''; $$('.btn').forEach(b => { if (b.querySelector('.bt')) return; const t = document.createElement('span'); t.className = 'bt'; while (b.firstChild) t.appendChild(b.firstChild); b.appendChild(t); if (b.classList.contains('btn-blue')) t.insertAdjacentHTML('beforeend', ``); b.addEventListener('pointerdown', e => { const r = b.getBoundingClientRect(), d = Math.max(r.width, r.height) * 2.2, s = document.createElement('span'); s.className = 'rip'; s.style.cssText = `width:${d}px;height:${d}px;left:${e.clientX - r.left - d / 2}px;top:${e.clientY - r.top - d / 2}px`; b.appendChild(s); setTimeout(() => s.remove(), 750); }); b.addEventListener('pointermove', e => { const r = b.getBoundingClientRect(); b.style.setProperty('--bx', (e.clientX - r.left) + 'px'); b.style.setProperty('--by', (e.clientY - r.top) + 'px'); }); }); if (RM || !hasG || !matchMedia('(hover:hover) and (pointer:fine)').matches) return; $$('.btn:not([data-goo]), .menu-btn, .tel').forEach(b => { const xT = gsap.quickTo(b, 'x', { duration: .5, ease: 'elastic.out(1,.45)' }), yT = gsap.quickTo(b, 'y', { duration: .5, ease: 'elastic.out(1,.45)' }); b.addEventListener('pointermove', e => { const r = b.getBoundingClientRect(); xT((e.clientX - r.left - r.width / 2) * .25); yT((e.clientY - r.top - r.height / 2) * .35); }); b.addEventListener('pointerleave', () => { xT(0); yT(0); }); }); })(); /* ---------- KLEBRIGER BUTTON (Goo) im Hero ---------- */ (() => { const btns = $$('[data-goo]'); if (RM || !btns.length) { $$('.goo-hint').forEach(h => h.remove()); return; } const cv = document.createElement('canvas'); cv.className = 'goo-canvas'; cv.setAttribute('aria-hidden', 'true'); document.body.appendChild(cv); const ctx = cv.getContext('2d'); let W = 0, H = 0; const resize = () => { const d = Math.min(devicePixelRatio || 1, 2); W = innerWidth; H = innerHeight; cv.width = W * d; cv.height = H * d; ctx.setTransform(d, 0, 0, d, 0, 0); }; resize(); addEventListener('resize', resize); const SEG = 12, GRAV = .35, rnd = (a, b) => a + Math.random() * (b - a), strands = []; let raf = 0; const mk = (st, ax, ay, hx, hy) => { const pts = []; for (let i = 0; i <= SEG; i++) { const t = i / SEG, x = ax + (hx - ax) * t, y = ay + (hy - ay) * t; pts.push({ x, y, ox: x, oy: y }); } return { st, lx: ax - st.cx, ly: ay - st.cy, hox: rnd(-9, 9), hoy: rnd(-6, 10), w: rnd(4, 9), max: rnd(220, 520), pts, mode: 'held', rest: 0, life: 1 }; }; const snap = s => { s.mode = 'snap'; let L = 0; for (let i = 1; i < s.pts.length; i++) L += Math.hypot(s.pts[i].x - s.pts[i - 1].x, s.pts[i].y - s.pts[i - 1].y); s.rest = L / SEG; }; function grab(b, e) { const r = b.getBoundingClientRect(), st = { btn: b, cx: r.left + r.width / 2, cy: r.top + r.height / 2, px: e.clientX, py: e.clientY, sx: e.clientX, sy: e.clientY, tx: 0, ty: 0, rx: 0, ry: 0, vx: 0, vy: 0, down: true, moved: false }; b.setPointerCapture(e.pointerId); const n = Math.round(rnd(7, 11)); for (let i = 0; i < n; i++) { let ax = e.clientX + rnd(-.22, .22) * r.width, ay = e.clientY + rnd(-.3, .3) * r.height; ax = cl(ax, r.left + r.height * .45, r.right - r.height * .45); ay = cl(ay, r.top + r.height * .2, r.bottom - r.height * .2); strands.push(mk(st, ax, ay, e.clientX, e.clientY)); } st.strands = strands.filter(s => s.st === st); b._goo = st; loop(); } const release = b => { const st = b._goo; if (!st) return; st.down = false; st.strands.forEach(s => s.mode === 'held' && snap(s)); }; btns.forEach(b => { b.addEventListener('pointerdown', e => { if (e.button === 0) { e.preventDefault(); grab(b, e); } }); b.addEventListener('pointermove', e => { const st = b._goo; if (!st || !st.down) return; st.px = e.clientX; st.py = e.clientY; if (Math.hypot(st.px - st.sx, st.py - st.sy) > 6) st.moved = true; }); b.addEventListener('pointerup', () => release(b)); b.addEventListener('pointercancel', () => release(b)); b.addEventListener('click', e => { if (b._goo && b._goo.moved) { e.preventDefault(); e.stopImmediatePropagation(); } }, true); }); const anchor = s => ({ x: s.st.cx + s.st.tx + s.lx * (1 - Math.abs(s.st.ry) / 120), y: s.st.cy + s.st.ty + s.ly * (1 - Math.abs(s.st.rx) / 120) }); function step() { const sts = new Set(strands.map(s => s.st)); btns.forEach(b => b._goo && sts.add(b._goo)); sts.forEach(st => { const dx = st.down ? st.px - st.sx : 0, dy = st.down ? st.py - st.sy : 0, d = Math.hypot(dx, dy), k = d ? Math.min(d, 600) / d : 0; st.vx = (st.vx + (dx * k * .16 - st.tx) * .18) * .72; st.vy = (st.vy + (dy * k * .16 - st.ty) * .18) * .72; st.tx += st.vx; st.ty += st.vy; st.rx += ((st.down ? cl(-dy * .07, -28, 28) : 0) - st.rx) * (st.down ? .2 : .12); st.ry += ((st.down ? cl(dx * .06, -28, 28) : 0) - st.ry) * (st.down ? .2 : .12); const sq = st.down ? Math.min(.06, d / 4000) : 0; st.btn.style.transform = `perspective(700px) translate(${st.tx}px,${st.ty}px) rotateX(${st.rx}deg) rotateY(${st.ry}deg) scale(${1 + sq},${1 - sq})`; if (!st.down && Math.abs(st.tx) + Math.abs(st.ty) + Math.abs(st.rx) + Math.abs(st.ry) < .05 && !strands.some(s => s.st === st)) { st.btn.style.transform = ''; st.btn._goo = null; } }); for (let j = strands.length - 1; j >= 0; j--) { const s = strands[j], p = s.pts, a = anchor(s), st = s.st; for (let i = 1; i < p.length; i++) { const q = p[i]; if (s.mode === 'held' && i === p.length - 1) continue; const vx = (q.x - q.ox) * .96, vy = (q.y - q.oy) * .96; q.ox = q.x; q.oy = q.y; q.x += vx; q.y += vy + GRAV * .5; } p[0].x = p[0].ox = a.x; p[0].y = p[0].oy = a.y; if (s.mode === 'held') { const h = p[p.length - 1]; h.x = h.ox = st.px + s.hox; h.y = h.oy = st.py + s.hoy; const dist = Math.hypot(h.x - a.x, h.y - a.y); if (dist > s.max) snap(s); else s.rest = dist / SEG * 1.01; } else { s.rest *= .86; s.life -= .012; } for (let it = 0; it < 6; it++) { for (let i = 0; i < SEG; i++) { const A = p[i], B = p[i + 1], ddx = B.x - A.x, ddy = B.y - A.y, dd = Math.hypot(ddx, ddy) || 1e-4, df = (dd - s.rest) / dd * .5, fA = i === 0, fB = s.mode === 'held' && i + 1 === SEG; if (fA && fB) continue; if (fA) { B.x -= ddx * df * 2; B.y -= ddy * df * 2; } else if (fB) { A.x += ddx * df * 2; A.y += ddy * df * 2; } else { A.x += ddx * df; A.y += ddy * df; B.x -= ddx * df; B.y -= ddy * df; } } p[0].x = a.x; p[0].y = a.y; } if (s.mode === 'snap' && (s.rest < .25 || s.life <= 0)) strands.splice(j, 1); } } function draw() { ctx.clearRect(0, 0, W, H); for (const s of strands) { const p = s.pts, h = p[p.length - 1], a = p[0], len = Math.hypot(h.x - a.x, h.y - a.y), thin = s.mode === 'held' ? Math.max(.3, Math.min(1, 110 / (len + 30))) : Math.max(.3, s.life); ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.strokeStyle = ctx.fillStyle = '#1a8ad4'; ctx.shadowColor = 'rgba(13,27,46,.25)'; ctx.shadowBlur = 8; ctx.shadowOffsetY = 7; for (let i = 0; i < SEG; i++) { const t = (i + .5) / SEG, pr = .22 + .78 * Math.pow(Math.abs(2 * t - 1), 2.2) + (t < .15 ? .35 : 0); ctx.lineWidth = Math.max(1.1, s.w * pr * (.5 + .5 * thin)); ctx.beginPath(); ctx.moveTo(p[i].x, p[i].y); ctx.lineTo(p[i + 1].x, p[i + 1].y); ctx.stroke(); } ctx.beginPath(); ctx.ellipse(a.x, a.y, s.w * 1.05, s.w * .8, 0, 0, 7); ctx.fill(); ctx.beginPath(); ctx.arc(h.x, h.y, s.w * (s.mode === 'held' ? .9 : .55), 0, 7); ctx.fill(); ctx.shadowColor = 'transparent'; ctx.strokeStyle = 'rgba(255,255,255,.35)'; ctx.lineWidth = .9; ctx.beginPath(); ctx.moveTo(p[1].x - 1, p[1].y); for (let i = 2; i < SEG - 1; i++) ctx.lineTo(p[i].x - s.w * .25, p[i].y); ctx.stroke(); } } function loop() { if (raf) return; const tick = () => { step(); draw(); const busy = strands.length || btns.some(b => b._goo); raf = busy ? requestAnimationFrame(tick) : 0; if (!busy) ctx.clearRect(0, 0, W, H); }; raf = requestAnimationFrame(tick); } addEventListener('scroll', () => btns.forEach(b => b._goo && b._goo.down && release(b)), { passive: true }); })(); /* ---------- FLÜSSIGE TAB-LEISTE (Handy) ---------- */ (() => { const nav = $('#ltb'), svg = $('svg.shape', nav), path = $('path', svg), dot = $('circle', svg), tabs = $$('a', nav).filter(a => !a.hasAttribute('data-call')), call = $('[data-call]', nav), all = $$('a', nav); const secs = tabs.map(a => $(a.getAttribute('href'))), css = getComputedStyle(nav), n = all.length; let W, Ht, barH, R, top, idx = 0; const st = { x: 0, vx: 0, lift: 0, vl: 0, tx: 0, tl: 0 }, FIL = 12; const center = i => (i + .5) * W / n; const measure = () => { W = nav.clientWidth; Ht = nav.clientHeight; barH = parseFloat(css.getPropertyValue('--h')); R = parseFloat(css.getPropertyValue('--R')); top = Ht - barH; svg.setAttribute('viewBox', `0 0 ${W} ${Ht}`); st.tx = center(idx); if (!st.x) st.x = st.tx; st.tl = R * .95; }; function shape(cx, lift) { const rr = barH / 2, y0 = top, y1 = Ht, cy = top - lift + R * .55, fy = top - FIL, dy = cy - fy, D = R + FIL; let bump = ''; if (lift > 2 && Math.abs(dy) < D) { const d = Math.sqrt(D * D - dy * dy), f1 = cx - d, f2 = cx + d, p1 = [f1 + (cx - f1) * FIL / D, fy + (cy - fy) * FIL / D], p2 = [f2 + (cx - f2) * FIL / D, fy + (cy - fy) * FIL / D], lg = (cy - p1[1]) > 0 ? 0 : 1; bump = `L ${f1} ${y0} A ${FIL} ${FIL} 0 0 0 ${p1[0]} ${p1[1]} A ${R} ${R} 0 ${lg} 1 ${p2[0]} ${p2[1]} A ${FIL} ${FIL} 0 0 0 ${f2} ${y0} `; } path.setAttribute('d', `M ${rr} ${y0} ${bump}L ${W - rr} ${y0} A ${rr} ${rr} 0 0 1 ${W - rr} ${y1} L ${rr} ${y1} A ${rr} ${rr} 0 0 1 ${rr} ${y0} Z`); dot.setAttribute('cx', cx); dot.setAttribute('cy', cy); dot.setAttribute('r', Math.max(0, R - 5) * Math.min(1, lift / (R * .5))); all.forEach((t, i) => { const k = i === idx ? Math.max(0, 1 - Math.abs(cx - center(i)) / (W / n * .5)) : 0; $('svg', t).style.transform = k ? `translateY(${(cy - (top + barH / 2)) * k}px)` : ''; }); } let raf = 0; const tick = () => { const dist = Math.abs(st.tx - st.x), want = dist > 6 ? Math.max(R * .5, R * .95 - dist * .3) : st.tl; st.vx = (st.vx + (st.tx - st.x) * .045) * .8; st.x += st.vx; st.vl = (st.vl + (want - st.lift) * .14) * .72; st.lift += st.vl; shape(st.x, st.lift); raf = Math.abs(st.vx) + Math.abs(st.vl) + Math.abs(st.tx - st.x) > .05 ? requestAnimationFrame(tick) : 0; }; const select = i => { if (i === idx) return; all[idx].setAttribute('aria-current', 'false'); idx = i; all[i].setAttribute('aria-current', 'true'); st.tx = center(i); if (RM) { st.x = st.tx; shape(st.x, st.lift); return; } if (!raf) raf = requestAnimationFrame(tick); }; let lock = 0; tabs.forEach((t, i) => t.addEventListener('click', () => { select(i); lock = Date.now() + 1200; })); call.addEventListener('click', () => { select(n - 1); setTimeout(() => spy(true), 1500); }); const spy = force => { if (!force && Date.now() < lock) return; let c = 0; secs.forEach((s, i) => { if (s && s.getBoundingClientRect().top < innerHeight * .5) c = i; }); select(c); }; addEventListener('scroll', () => spy(), { passive: true }); measure(); st.lift = st.tl; shape(st.x, st.lift); new ResizeObserver(() => { measure(); st.x = st.tx; shape(st.x, st.lift); }).observe(nav); })(); /* ---------- Formular-Button: Laden, dann Häkchen ---------- */ (() => { const f = I('form'), b = $('button[type=submit]', f); f.addEventListener('submit', () => { setTimeout(() => { if (!/Danke/.test(I('fNote').textContent)) return; const t = $('.bt', b), old = t.innerHTML; b.disabled = true; t.innerHTML = 'Wird gesendet'; setTimeout(() => { b.classList.add('done'); t.innerHTML = '✓ Gesendet'; if (hasG && !RM) gsap.fromTo(b, { scale: .92 }, { scale: 1, duration: .6, ease: 'elastic.out(1,.4)' }); }, 1100); }, 0); }); })(); if (hasG) { ScrollTrigger.sort(); ScrollTrigger.refresh(); addEventListener('load', () => ScrollTrigger.refresh()); } })();