Files
smb-online/deploy/clients/paris-barbershop/site/index.html
T
2026-09-12 03:53:29 +02:00

514 lines
28 KiB
HTML
Raw 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.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Paris Barber Shop — Nürnberg | 2 Filialen | Termin online buchen</title>
<meta name="description" content="Paris Barber Shop in Nürnberg — zwei Filialen (Röthenbach Center &amp; Hafenstraße). Herrenschnitt, Bartpflege und mehr. Jetzt online einen Termin buchen." />
<link rel="icon" type="image/png" href="logo.png" />
<link rel="apple-touch-icon" href="logo.png" />
<meta property="og:title" content="Paris Barber Shop — Nürnberg" />
<meta property="og:description" content="Zwei Filialen in Nürnberg. Herrenschnitt, Bartpflege und mehr — jetzt online einen Termin buchen." />
<meta property="og:image" content="logo.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<style>
:root {
--bg: #14110f;
--bg-2: #1d1916;
--card: #221d19;
--ink: #f4efe9;
--muted: #b3a89c;
--gold: #c8a05a;
--gold-2: #e0c184;
--line: #342d27;
--radius: 14px;
--shadow: 0 18px 50px rgba(0,0,0,.45);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
font-family: 'Inter', system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
background: var(--bg); color: var(--ink);
line-height: 1.65; -webkit-font-smoothing: antialiased;
}
h1, h2, h3, .display { font-family: 'Bebas Neue', 'Inter', sans-serif; letter-spacing: .5px; line-height: 1.05; }
a { color: inherit; text-decoration: none; }
.wrap { width: min(1120px, 92vw); margin-inline: auto; }
section { padding: 92px 0; }
.eyebrow { color: var(--gold); font-weight: 600; letter-spacing: 3px; text-transform: uppercase; font-size: .72rem; }
/* nav */
header.nav { position: sticky; top: 0; z-index: 50; background: rgba(20,17,15,.82); backdrop-filter: blur(10px); border-bottom: 1px solid var(--line); }
.nav-inner { display: flex; align-items: center; justify-content: space-between; height: 68px; }
.brand { font-family: 'Bebas Neue', sans-serif; font-size: 1.5rem; letter-spacing: 1.5px; display: flex; align-items: center; gap: 10px; }
.brand span { color: var(--gold); }
.brand img { height: 44px; width: 44px; border-radius: 50%; display: block; }
footer .brand img { height: 52px; width: 52px; }
nav ul { display: flex; gap: 30px; list-style: none; align-items: center; }
nav a { color: var(--muted); font-size: .92rem; font-weight: 500; transition: color .2s; }
nav a:hover { color: var(--ink); }
.btn {
display: inline-block; background: linear-gradient(180deg, var(--gold-2), var(--gold));
color: #1a1410; font-weight: 700; padding: 12px 22px; border-radius: 999px;
border: 0; cursor: pointer; font-size: .95rem; transition: transform .15s, box-shadow .2s;
box-shadow: 0 8px 22px rgba(200,160,90,.28);
}
.btn:hover { transform: translateY(-2px); box-shadow: 0 12px 28px rgba(200,160,90,.4); }
.btn.ghost { background: transparent; color: var(--ink); border: 1px solid var(--line); box-shadow: none; }
.nav-toggle { display: none; background: none; border: 0; color: var(--ink); font-size: 1.6rem; cursor: pointer; }
/* hero */
.hero { position: relative; background:
linear-gradient(rgba(15,12,10,.72), rgba(15,12,10,.86)),
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60'%3E%3Crect width='60' height='60' fill='%231a1512'/%3E%3Cpath d='M0 59h60M0 29h60' stroke='%23241d18' stroke-width='1'/%3E%3C/svg%3E");
border-bottom: 1px solid var(--line); }
.hero-inner { padding: 96px 0 104px; max-width: 720px; }
.hero h1 { font-size: clamp(2.8rem, 7.5vw, 5rem); margin: 14px 0 6px; }
.hero h1 em { color: var(--gold); font-style: normal; }
.hero p { color: var(--muted); font-size: 1.18rem; max-width: 540px; margin: 18px 0 30px; }
.hero-cta { display: flex; gap: 14px; flex-wrap: wrap; }
.hero-meta { margin-top: 34px; display: flex; gap: 28px; flex-wrap: wrap; color: var(--muted); font-size: .9rem; }
.hero-meta b { color: var(--ink); }
/* location switcher */
.loc-switch { background: var(--bg-2); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.loc-tabs { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 28px; }
.loc-tab {
background: var(--card); border: 1px solid var(--line); border-radius: 999px;
padding: 11px 20px; font-size: .92rem; font-weight: 600; color: var(--muted);
cursor: pointer; transition: .15s;
}
.loc-tab.active { background: var(--gold); border-color: var(--gold); color: #1a1410; }
.loc-tab:hover:not(.active) { border-color: var(--gold); color: var(--ink); }
.loc-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 30px; box-shadow: var(--shadow); display: grid; grid-template-columns: 1.2fr 1fr; gap: 30px; }
.loc-card h3 { font-size: 1.9rem; margin-bottom: 4px; }
.loc-rating { color: var(--gold-2); font-weight: 600; font-size: .95rem; margin-bottom: 16px; }
.loc-rating span { color: var(--muted); font-weight: 400; }
.loc-row { display: flex; gap: 10px; margin-bottom: 10px; color: var(--muted); font-size: .95rem; }
.loc-row b { color: var(--ink); font-weight: 500; }
.loc-status { display: inline-flex; align-items: center; gap: 7px; color: #7fd18e; font-weight: 600; font-size: .88rem; margin-top: 4px; }
.loc-status .dot { width: 8px; height: 8px; border-radius: 50%; background: #4caf7d; box-shadow: 0 0 0 3px rgba(76,175,125,.2); }
.loc-hours td { padding: 7px 0; border-bottom: 1px solid var(--line); color: var(--muted); font-size: .88rem; }
.loc-hours td:last-child { text-align: right; color: var(--ink); }
.loc-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px; }
/* services */
.sec-head { max-width: 620px; margin-bottom: 46px; }
.sec-head h2 { font-size: clamp(2.2rem, 5vw, 3.2rem); margin-top: 8px; }
.sec-head p { color: var(--muted); margin-top: 10px; }
.grid { display: grid; gap: 18px; }
.services { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.svc { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 26px; transition: transform .18s, border-color .2s; }
.svc:hover { transform: translateY(-4px); border-color: var(--gold); }
.svc .ic { font-size: 1.8rem; }
.svc h3 { font-size: 1.5rem; margin: 14px 0 6px; }
.svc p { color: var(--muted); font-size: .92rem; min-height: 42px; }
.svc .price { color: var(--gold-2); font-weight: 700; font-size: .98rem; margin-top: 12px; font-family: 'Inter'; }
/* booking */
.booking { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.booking ul.points { list-style: none; display: grid; gap: 14px; margin: 22px 0 28px; }
.booking ul.points li { padding-left: 30px; position: relative; color: var(--muted); }
.booking ul.points li::before { content: "✓"; position: absolute; left: 0; color: var(--gold); font-weight: 700; }
.booking-embed { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 8px; box-shadow: var(--shadow); max-width: 640px; margin: 0 auto; }
.booking-embed iframe { width: 100%; height: 900px; min-height: 0; border: 0; border-radius: 10px; display: block; background: #1a1611; }
@media (max-width: 800px) { .booking-embed iframe { height: 1050px; } }
/* contact */
.contact { background: var(--bg-2); border-top: 1px solid var(--line); }
form.lead { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 28px; max-width: 560px; }
.field { margin-bottom: 16px; }
.field label { display: block; font-size: .85rem; color: var(--muted); margin-bottom: 6px; }
.field input, .field textarea, .field select {
width: 100%; background: #1a1611; border: 1px solid var(--line); border-radius: 9px;
color: var(--ink); padding: 12px 14px; font: inherit; font-size: .95rem;
}
.field input:focus, .field textarea:focus, .field select:focus { outline: 2px solid var(--gold); border-color: var(--gold); }
.form-note { font-size: .78rem; color: var(--muted); margin-top: 10px; }
.toast { display: none; margin-top: 14px; padding: 12px 14px; border-radius: 9px; background: #1e2a1c; border: 1px solid #2f5a2c; color: #bfe6b6; font-size: .9rem; }
/* footer */
footer { padding: 54px 0 40px; border-top: 1px solid var(--line); color: var(--muted); font-size: .9rem; }
.foot-grid { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 24px; }
footer .brand { color: var(--ink); }
@media (max-width: 820px) {
nav ul { display: none; }
.nav-toggle { display: block; }
nav.open ul { display: flex; position: absolute; inset: 68px 0 auto 0; flex-direction: column; background: var(--bg-2); padding: 18px 6vw; gap: 18px; border-bottom: 1px solid var(--line); }
.loc-card { grid-template-columns: 1fr; }
section { padding: 64px 0; }
}
</style>
</head>
<body>
<header class="nav">
<div class="wrap nav-inner">
<a href="#top" class="brand"><img src="logo.png" alt="Paris Barber Shop" width="44" height="44" />PARIS <span>BARBER SHOP</span></a>
<nav id="nav">
<ul>
<li><a href="#filialen">Filialen</a></li>
<li><a href="#leistungen">Leistungen</a></li>
<li><a href="#buchen">Termin buchen</a></li>
<li><a href="#kontakt">Kontakt</a></li>
<li><a href="#buchen" class="btn">Termin buchen</a></li>
</ul>
</nav>
<button class="nav-toggle" aria-label="Menü" onclick="document.getElementById('nav').classList.toggle('open')"></button>
</div>
</header>
<main id="top">
<!-- HERO -->
<section class="hero" id="hero">
<div class="wrap hero-inner">
<span class="eyebrow">Herrenfriseur · 2 Filialen in Nürnberg</span>
<h1>Sauberer Schnitt.<br><em>Zwei Adressen.</em></h1>
<p>Herrenschnitt, Bartpflege und mehr — in unseren Filialen im Röthenbach Center und an der Hafenstraße. Termin online buchen, Filiale frei wählbar.</p>
<div class="hero-cta">
<a href="#buchen" class="btn">Termin online buchen</a>
<a href="#filialen" class="btn ghost">Filialen &amp; Öffnungszeiten</a>
</div>
<div class="hero-meta">
<span><b>4,24,4</b> · 500+ Bewertungen</span>
<span>✂ Herrenfriseur</span>
<span>📍 Nürnberg-West</span>
</div>
</div>
</section>
<!-- LOCATION SWITCHER -->
<section class="loc-switch" id="filialen">
<div class="wrap">
<div class="sec-head" style="margin-bottom:28px;">
<span class="eyebrow">Filialen</span>
<h2>Welche Filiale passt für Sie?</h2>
<p>Beide Filialen sind eigenständig buchbar — wählen Sie unten aus.</p>
</div>
<div class="loc-tabs" id="locTabs" role="tablist">
<button class="loc-tab active" type="button" data-loc="roethenbach">Röthenbach Center</button>
<button class="loc-tab" type="button" data-loc="hafenstrasse">Hafenstraße</button>
</div>
<div class="loc-card" id="locCard"><!-- filled by JS --></div>
</div>
</section>
<!-- SERVICES -->
<section id="leistungen">
<div class="wrap">
<div class="sec-head">
<span class="eyebrow">Leistungen</span>
<h2>Was wir für Sie tun</h2>
<p>In beiden Filialen verfügbar — Preise und Details erfahren Sie bei der Buchung oder im Studio.</p>
</div>
<div class="grid services">
<article class="svc"><div class="ic">✂️</div><h3>Herrenschnitt</h3><p>Waschen, Schnitt, Styling — individuell auf Ihren Typ abgestimmt.</p><div class="price">30 Min</div></article>
<article class="svc"><div class="ic">🧔</div><h3>Bartpflege</h3><p>Konturieren, trimmen und pflegen für den perfekten Bart.</p><div class="price">20 Min</div></article>
</div>
</div>
</section>
<!-- BOOKING -->
<section class="booking" id="buchen">
<div class="wrap">
<div class="sec-head" style="margin-bottom:28px;">
<span class="eyebrow">Termin buchen</span>
<h2>Wählen Sie Filiale, Leistung &amp; Zeit.</h2>
<p>Buchen Sie direkt hier rund um die Uhr — sofortige Bestätigung, kein Anruf nötig. Die Filialauswahl finden Sie im Buchungsfenster unter „Mitarbeiter&quot;.</p>
</div>
<div class="booking-embed">
<iframe id="booking-frame" src="https://onboard.mivanchenko.de/book/paris-barbershop?color=%23c8a05a"
title="Online-Terminbuchung" loading="lazy"></iframe>
</div>
</div>
</section>
<!-- CONTACT / LEAD FORM -->
<section class="contact" id="kontakt">
<div class="wrap">
<div class="sec-head">
<span class="eyebrow">Kontakt</span>
<h2>Frage stellen oder Rückruf anfordern</h2>
<p>Schreiben Sie uns kurz — wir melden uns am selben Tag.</p>
</div>
<form class="lead" onsubmit="return submitLead(event, this)">
<input type="hidden" name="client_id" value="C-0004" />
<input type="hidden" name="source" value="paris-barbershop-site" />
<div class="field"><label for="a-name">Name</label><input id="a-name" name="name" type="text" placeholder="Ihr Name" required /></div>
<div class="field"><label for="a-contact">E-Mail oder Telefon</label><input id="a-contact" name="contact" type="text" placeholder="name@example.de" required /></div>
<div class="field"><label for="a-loc">Bevorzugte Filiale</label>
<select id="a-loc" name="service"><option>Röthenbach Center</option><option>Hafenstraße</option><option>Egal</option></select>
</div>
<div class="field"><label for="a-msg">Nachricht (optional)</label><textarea id="a-msg" name="message" rows="3" placeholder="Wunschtermin, Frage, …"></textarea></div>
<button class="btn" type="submit">Anfrage senden</button>
<div class="toast">✓ Danke! Ihre Anfrage ist eingegangen — wir melden uns.</div>
<p class="form-note">Mit dem Absenden stimmen Sie der Verarbeitung Ihrer Angaben zur Kontaktaufnahme zu.</p>
</form>
</div>
</section>
</main>
<footer>
<div class="wrap foot-grid">
<div>
<div class="brand"><img src="logo.png" alt="Paris Barber Shop" width="52" height="52" />PARIS <span style="color:var(--gold)">BARBER SHOP</span></div>
<p style="margin-top:8px;">Herrenfriseur · Nürnberg</p>
</div>
<div>
<p><b style="color:var(--ink)">Röthenbach Center</b></p>
<p>Dombühler Str. 9 · 0911 47885170</p>
</div>
<div>
<p><b style="color:var(--ink)">Hafenstraße</b></p>
<p>Hafenstraße 12 · 0911 25387841</p>
</div>
</div>
<div class="wrap" style="margin-top:30px;opacity:.6;font-size:.8rem;">© 2026 Paris Barber Shop · Impressum · Datenschutz</div>
</footer>
<script>
// weekly: index 0=Sunday..6=Saturday (JS Date#getDay convention), minutes
// since midnight, or null for a closed day -- matches the real hours
// configured in the booking backend (Mon-Sat 09:00-20:00, Sun closed).
const OPEN_MIN = 9 * 60, CLOSE_MIN = 20 * 60;
const WEEKLY_SCHEDULE = [null, [OPEN_MIN, CLOSE_MIN], [OPEN_MIN, CLOSE_MIN], [OPEN_MIN, CLOSE_MIN],
[OPEN_MIN, CLOSE_MIN], [OPEN_MIN, CLOSE_MIN], [OPEN_MIN, CLOSE_MIN]];
const LOCATIONS = {
roethenbach: {
name: "Paris Barber Shop — Röthenbach Center",
rating: "4,2", reviews: "277",
address: "Dombühler Str. 9, 90449 Nürnberg-West",
note: "Befindet sich in: Röthenbach Center",
phone: "0911 47885170",
phoneHref: "tel:+4991147885170",
site: "hair.center.ivof.com",
hours: [["Montag Samstag", "09:00 20:00"], ["Sonntag", "geschlossen"]],
schedule: WEEKLY_SCHEDULE,
},
hafenstrasse: {
name: "Paris Barber Shop II — Hafenstraße",
rating: "4,4", reviews: "226",
address: "Hafenstraße 12, 90451 Nürnberg-West",
note: "",
phone: "0911 25387841",
phoneHref: "tel:+4991125387841",
site: "barber.de.ivof.com",
hours: [["Montag Samstag", "09:00 20:00"], ["Sonntag", "geschlossen"]],
schedule: WEEKLY_SCHEDULE,
},
};
function fmtMin(min) {
return String(Math.floor(min / 60)).padStart(2, '0') + ':' + String(min % 60).padStart(2, '0');
}
// Real open/closed status computed against the shop's own timezone
// (Europe/Berlin), not the visitor's -- a Google-Maps-style "Geöffnet ·
// schließt um 20:00" badge is misleading if it's just hardcoded text that
// never changes, e.g. still claiming "open" at 3am.
function computeStatus(schedule) {
const berlinNow = new Date(new Date().toLocaleString('en-US', { timeZone: 'Europe/Berlin' }));
const day = berlinNow.getDay();
const today = schedule[day];
const nowMin = berlinNow.getHours() * 60 + berlinNow.getMinutes();
if (today) {
if (nowMin >= today[0] && nowMin < today[1]) {
return { open: true, text: 'Geöffnet · schließt um ' + fmtMin(today[1]) + ' Uhr' };
}
if (nowMin < today[0]) {
return { open: false, text: 'Geschlossen · öffnet heute um ' + fmtMin(today[0]) + ' Uhr' };
}
}
// Closed all day today, or already past today's closing time -- find
// the next day (starting tomorrow) that has hours at all.
for (let ahead = 1; ahead <= 7; ahead++) {
const next = schedule[(day + ahead) % 7];
if (next) {
const when = ahead === 1 ? 'morgen' : 'in ' + ahead + ' Tagen';
return { open: false, text: 'Geschlossen · öffnet ' + when + ' um ' + fmtMin(next[0]) + ' Uhr' };
}
}
return { open: false, text: 'Geschlossen' };
}
function renderLoc(key) {
const l = LOCATIONS[key];
const mapsUrl = "https://www.google.com/maps/search/?api=1&query=" + encodeURIComponent(l.address);
const hoursRows = l.hours.map(function (h) {
return '<tr><td>' + h[0] + '</td><td>' + h[1] + '</td></tr>';
}).join('');
const status = computeStatus(l.schedule);
document.getElementById('locCard').innerHTML =
'<div>' +
'<h3>' + l.name + '</h3>' +
'<div class="loc-rating">⭐ ' + l.rating + ' <span>(' + l.reviews + ' Bewertungen)</span></div>' +
'<div class="loc-row">📍 <b>' + l.address + '</b></div>' +
(l.note ? '<div class="loc-row" style="margin-left:24px;">' + l.note + '</div>' : '') +
'<div class="loc-row">☎ <a href="' + l.phoneHref + '"><b>' + l.phone + '</b></a></div>' +
'<div class="loc-status" style="color:' + (status.open ? '#7fd18e' : '#c9736f') + ';">' +
'<span class="dot" style="background:' + (status.open ? '#4caf7d' : '#b3564f') + ';"></span> ' + status.text +
'</div>' +
'<div class="loc-actions">' +
'<a class="btn" href="#buchen">Termin in dieser Filiale</a>' +
'<a class="btn ghost" href="' + mapsUrl + '" target="_blank" rel="noopener">Routenplaner</a>' +
'</div>' +
'</div>' +
'<div>' +
'<span class="eyebrow">Öffnungszeiten</span>' +
'<table class="loc-hours" style="width:100%;margin-top:10px;">' + hoursRows + '</table>' +
'</div>';
}
document.getElementById('locTabs').addEventListener('click', function (e) {
const btn = e.target.closest('.loc-tab');
if (!btn) return;
document.querySelectorAll('.loc-tab').forEach(function (t) { t.classList.remove('active'); });
btn.classList.add('active');
renderLoc(btn.getAttribute('data-loc'));
});
renderLoc('roethenbach');
</script>
<script>
// Lead-Formular -> n8n Webhook -> CRM (Leads) + Telegram-Benachrichtigung.
const LEAD_WEBHOOK = 'https://n8n.mivanchenko.de/webhook/lead-intake';
async function submitLead(e, form) {
e.preventDefault();
const btn = form.querySelector('button[type=submit]');
const toast = form.querySelector('.toast');
const data = Object.fromEntries(new FormData(form).entries());
const old = btn.textContent;
btn.disabled = true; btn.textContent = 'Senden…';
try {
const r = await fetch(LEAD_WEBHOOK, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
if (!r.ok) throw new Error(r.status);
toast.textContent = '✓ Danke! Ihre Anfrage ist eingegangen — wir melden uns.';
toast.style.display = 'block';
form.reset();
} catch (err) {
toast.textContent = '⚠ Senden fehlgeschlagen — bitte erneut versuchen oder direkt anrufen.';
toast.style.display = 'block';
} finally {
btn.disabled = false; btn.textContent = old;
}
return false;
}
</script>
<script>window.CB_CTX = { client_id: "C-0004", source: "paris-barbershop-callback" };</script>
<!-- ===== Rückruf-Widget (lead capture popup) ===== -->
<style>
.cb-fab { position: fixed; right: 18px; bottom: 18px; z-index: 900; background: var(--gold); color: #1a1410; border: 0; border-radius: 999px; padding: 13px 20px; font: 700 .95rem system-ui, -apple-system, Segoe UI, Roboto, sans-serif; box-shadow: 0 10px 26px rgba(200,160,90,.32); cursor: pointer; transition: transform .15s, background .2s; }
.cb-fab:hover { transform: translateY(-2px); background: var(--gold-2); }
.cb-overlay { position: fixed; inset: 0; z-index: 1000; background: rgba(10,8,7,.6); backdrop-filter: blur(3px); display: none; align-items: center; justify-content: center; padding: 18px; }
.cb-overlay.open { display: flex; }
.cb-modal { position: relative; width: min(440px, 100%); background: var(--card); color: var(--ink); border: 1px solid var(--line); border-radius: 16px; box-shadow: 0 24px 60px rgba(0,0,0,.5); padding: 28px 26px 22px; font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; max-height: 92vh; overflow: auto; animation: cbIn .18s ease; }
@keyframes cbIn { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.cb-modal h3 { margin: 0 0 4px; font-size: 1.35rem; font-family: 'Bebas Neue', sans-serif; letter-spacing: .5px; }
.cb-sub { margin: 0 0 18px; color: var(--muted); font-size: .9rem; }
.cb-x { position: absolute; top: 10px; right: 13px; background: none; border: 0; font-size: 1.7rem; line-height: 1; color: var(--muted); cursor: pointer; }
.cb-x:hover { color: var(--ink); }
.cb-modal label { display: block; font-size: .82rem; font-weight: 600; margin-bottom: 13px; }
.cb-modal label .o { color: var(--muted); font-weight: 400; }
.cb-modal input, .cb-modal textarea { width: 100%; margin-top: 5px; font: inherit; font-size: .94rem; color: var(--ink); background: #1a1611; border: 1px solid var(--line); border-radius: 9px; padding: 10px 12px; resize: vertical; }
.cb-modal input:focus, .cb-modal textarea:focus { outline: none; border-color: var(--gold); background: #1e1a15; }
.cb-submit { width: 100%; margin-top: 4px; background: var(--gold); color: #1a1410; border: 0; border-radius: 999px; padding: 13px; font: 700 1rem system-ui; cursor: pointer; transition: background .2s; }
.cb-submit:hover { background: var(--gold-2); }
.cb-submit:disabled { opacity: .6; cursor: default; }
.cb-toast { display: none; margin-top: 14px; padding: 11px 13px; border-radius: 9px; font-size: .88rem; font-weight: 500; }
.cb-toast.ok { background: #1e2a1c; color: #bfe6b6; border: 1px solid #2f5a2c; }
.cb-toast.err { background: #2e1c1c; color: #f3c7c7; border: 1px solid #5a2c2c; }
@media (max-width: 560px) { .cb-fab { right: 12px; bottom: 12px; padding: 11px 17px; } }
</style>
<button class="cb-fab" type="button" onclick="cbOpen()" aria-label="Rückruf anfordern">📞 Rückruf</button>
<div class="cb-overlay" id="cbOverlay" onclick="cbBg(event)">
<div class="cb-modal" role="dialog" aria-modal="true" aria-labelledby="cbTitle">
<button class="cb-x" type="button" onclick="cbClose()" aria-label="Schließen">&times;</button>
<h3 id="cbTitle">Rückruf anfordern</h3>
<p class="cb-sub">Name &amp; Nummer genügen — wir melden uns bei Ihnen. Alles andere ist optional.</p>
<form onsubmit="return cbSubmit(event, this)">
<input type="hidden" name="client_id" />
<input type="hidden" name="source" />
<label>Name *
<input name="name" required autocomplete="name" placeholder="Vor- und Nachname" />
</label>
<label>Telefon *
<input name="phone" required autocomplete="tel" inputmode="tel" placeholder="+49 …" />
</label>
<label>Gewünschte Leistung <span class="o">(optional)</span>
<input name="service" placeholder="Herrenschnitt, Bartpflege …" />
</label>
<label>Nachricht <span class="o">(optional)</span>
<textarea name="message" rows="2" placeholder="Worum geht es?"></textarea>
</label>
<button class="cb-submit" type="submit">Rückruf anfordern</button>
<div class="cb-toast" id="cbToast"></div>
</form>
</div>
</div>
<script>
const CB_WEBHOOK = 'https://n8n.mivanchenko.de/webhook/lead-intake';
const cbCtx = window.CB_CTX || { client_id: 'PREVIEW', source: 'callback' };
function cbOpen() {
const o = document.getElementById('cbOverlay');
o.querySelector('[name=client_id]').value = cbCtx.client_id;
o.querySelector('[name=source]').value = cbCtx.source;
o.classList.add('open');
document.body.style.overflow = 'hidden';
setTimeout(() => o.querySelector('[name=name]').focus(), 60);
}
function cbClose() {
document.getElementById('cbOverlay').classList.remove('open');
document.body.style.overflow = '';
}
function cbBg(e) { if (e.target.id === 'cbOverlay') cbClose(); }
document.addEventListener('keydown', e => { if (e.key === 'Escape') cbClose(); });
async function cbSubmit(e, form) {
e.preventDefault();
const btn = form.querySelector('.cb-submit');
const toast = document.getElementById('cbToast');
const d = Object.fromEntries(new FormData(form).entries());
let msg = (d.message || '').trim();
const payload = {
client_id: d.client_id, source: d.source,
name: d.name, phone: d.phone,
service_interest: d.service || '', message: msg
};
const old = btn.textContent;
btn.disabled = true; btn.textContent = 'Senden…';
toast.style.display = 'none';
try {
const r = await fetch(CB_WEBHOOK, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
if (!r.ok) throw new Error(r.status);
toast.className = 'cb-toast ok';
toast.textContent = '✓ Danke! Wir rufen Sie zurück.';
toast.style.display = 'block';
form.reset();
setTimeout(cbClose, 2200);
} catch (err) {
toast.className = 'cb-toast err';
toast.textContent = '⚠ Senden fehlgeschlagen. Bitte erneut versuchen.';
toast.style.display = 'block';
} finally {
btn.disabled = false; btn.textContent = old;
}
return false;
}
</script>
<!-- ===== /Rückruf-Widget ===== -->
</body>
</html>