@@ -0,0 +1,506 @@
<!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 & Hafenstraße). Herrenschnitt, Bartpflege und mehr. Jetzt online einen Termin buchen." / >
< 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 : 14 px ;
--shadow : 0 18 px 50 px 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 : .5 px ; line-height : 1.05 ; }
a { color : inherit ; text-decoration : none ; }
. wrap { width : min ( 1120 px , 92 vw ) ; margin-inline : auto ; }
section { padding : 92 px 0 ; }
. eyebrow { color : var ( - - gold ) ; font-weight : 600 ; letter-spacing : 3 px ; text-transform : uppercase ; font-size : .72 rem ; }
/* nav */
header . nav { position : sticky ; top : 0 ; z-index : 50 ; background : rgba ( 20 , 17 , 15 , .82 ) ; backdrop-filter : blur ( 10 px ) ; border-bottom : 1 px solid var ( - - line ) ; }
. nav-inner { display : flex ; align-items : center ; justify-content : space-between ; height : 68 px ; }
. brand { font-family : 'Bebas Neue' , sans-serif ; font-size : 1.5 rem ; letter-spacing : 1.5 px ; }
. brand span { color : var ( - - gold ) ; }
nav ul { display : flex ; gap : 30 px ; list-style : none ; align-items : center ; }
nav a { color : var ( - - muted ) ; font-size : .92 rem ; font-weight : 500 ; transition : color .2 s ; }
nav a : hover { color : var ( - - ink ) ; }
. btn {
display : inline-block ; background : linear-gradient ( 180 deg , var ( - - gold -2 ) , var ( - - gold ) ) ;
color : #1a1410 ; font-weight : 700 ; padding : 12 px 22 px ; border-radius : 999 px ;
border : 0 ; cursor : pointer ; font-size : .95 rem ; transition : transform .15 s , box-shadow .2 s ;
box-shadow : 0 8 px 22 px rgba ( 200 , 160 , 90 , .28 ) ;
}
. btn : hover { transform : translateY ( -2 px ) ; box-shadow : 0 12 px 28 px rgba ( 200 , 160 , 90 , .4 ) ; }
. btn . ghost { background : transparent ; color : var ( - - ink ) ; border : 1 px solid var ( - - line ) ; box-shadow : none ; }
. nav-toggle { display : none ; background : none ; border : 0 ; color : var ( - - ink ) ; font-size : 1.6 rem ; 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 : 1 px solid var ( - - line ) ; }
. hero-inner { padding : 96 px 0 104 px ; max-width : 720 px ; }
. hero h1 { font-size : clamp ( 2.8 rem , 7.5 vw , 5 rem ) ; margin : 14 px 0 6 px ; }
. hero h1 em { color : var ( - - gold ) ; font-style : normal ; }
. hero p { color : var ( - - muted ) ; font-size : 1.18 rem ; max-width : 540 px ; margin : 18 px 0 30 px ; }
. hero-cta { display : flex ; gap : 14 px ; flex-wrap : wrap ; }
. hero-meta { margin-top : 34 px ; display : flex ; gap : 28 px ; flex-wrap : wrap ; color : var ( - - muted ) ; font-size : .9 rem ; }
. hero-meta b { color : var ( - - ink ) ; }
/* location switcher */
. loc-switch { background : var ( - - bg -2 ) ; border-top : 1 px solid var ( - - line ) ; border-bottom : 1 px solid var ( - - line ) ; }
. loc-tabs { display : flex ; gap : 10 px ; flex-wrap : wrap ; margin-bottom : 28 px ; }
. loc-tab {
background : var ( - - card ) ; border : 1 px solid var ( - - line ) ; border-radius : 999 px ;
padding : 11 px 20 px ; font-size : .92 rem ; font-weight : 600 ; color : var ( - - muted ) ;
cursor : pointer ; transition : .15 s ;
}
. 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 : 1 px solid var ( - - line ) ; border-radius : var ( - - radius ) ; padding : 30 px ; box-shadow : var ( - - shadow ) ; display : grid ; grid-template-columns : 1.2 fr 1 fr ; gap : 30 px ; }
. loc-card h3 { font-size : 1.9 rem ; margin-bottom : 4 px ; }
. loc-rating { color : var ( - - gold -2 ) ; font-weight : 600 ; font-size : .95 rem ; margin-bottom : 16 px ; }
. loc-rating span { color : var ( - - muted ) ; font-weight : 400 ; }
. loc-row { display : flex ; gap : 10 px ; margin-bottom : 10 px ; color : var ( - - muted ) ; font-size : .95 rem ; }
. loc-row b { color : var ( - - ink ) ; font-weight : 500 ; }
. loc-status { display : inline-flex ; align-items : center ; gap : 7 px ; color : #7fd18e ; font-weight : 600 ; font-size : .88 rem ; margin-top : 4 px ; }
. loc-status . dot { width : 8 px ; height : 8 px ; border-radius : 50 % ; background : #4caf7d ; box-shadow : 0 0 0 3 px rgba ( 76 , 175 , 125 , .2 ) ; }
. loc-hours td { padding : 7 px 0 ; border-bottom : 1 px solid var ( - - line ) ; color : var ( - - muted ) ; font-size : .88 rem ; }
. loc-hours td : last-child { text-align : right ; color : var ( - - ink ) ; }
. loc-actions { display : flex ; gap : 10 px ; flex-wrap : wrap ; margin-top : 16 px ; }
/* services */
. sec-head { max-width : 620 px ; margin-bottom : 46 px ; }
. sec-head h2 { font-size : clamp ( 2.2 rem , 5 vw , 3.2 rem ) ; margin-top : 8 px ; }
. sec-head p { color : var ( - - muted ) ; margin-top : 10 px ; }
. grid { display : grid ; gap : 18 px ; }
. services { grid-template-columns : repeat ( auto - fit , minmax ( 240 px , 1 fr ) ) ; }
. svc { background : var ( - - card ) ; border : 1 px solid var ( - - line ) ; border-radius : var ( - - radius ) ; padding : 26 px ; transition : transform .18 s , border-color .2 s ; }
. svc : hover { transform : translateY ( -4 px ) ; border-color : var ( - - gold ) ; }
. svc . ic { font-size : 1.8 rem ; }
. svc h3 { font-size : 1.5 rem ; margin : 14 px 0 6 px ; }
. svc p { color : var ( - - muted ) ; font-size : .92 rem ; min-height : 42 px ; }
. svc . price { color : var ( - - gold -2 ) ; font-weight : 700 ; font-size : .98 rem ; margin-top : 12 px ; font-family : 'Inter' ; }
/* booking */
. booking { border-top : 1 px solid var ( - - line ) ; border-bottom : 1 px solid var ( - - line ) ; }
. booking ul . points { list-style : none ; display : grid ; gap : 14 px ; margin : 22 px 0 28 px ; }
. booking ul . points li { padding-left : 30 px ; 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 : 1 px solid var ( - - line ) ; border-radius : var ( - - radius ) ; padding : 8 px ; box-shadow : var ( - - shadow ) ; max-width : 640 px ; margin : 0 auto ; }
. booking-embed iframe { width : 100 % ; height : 900 px ; min-height : 0 ; border : 0 ; border-radius : 10 px ; display : block ; background : #1a1611 ; }
@ media ( max-width : 800px ) { . booking-embed iframe { height : 1050 px ; } }
/* contact */
. contact { background : var ( - - bg -2 ) ; border-top : 1 px solid var ( - - line ) ; }
form . lead { background : var ( - - card ) ; border : 1 px solid var ( - - line ) ; border-radius : var ( - - radius ) ; padding : 28 px ; max-width : 560 px ; }
. field { margin-bottom : 16 px ; }
. field label { display : block ; font-size : .85 rem ; color : var ( - - muted ) ; margin-bottom : 6 px ; }
. field input , . field textarea , . field select {
width : 100 % ; background : #1a1611 ; border : 1 px solid var ( - - line ) ; border-radius : 9 px ;
color : var ( - - ink ) ; padding : 12 px 14 px ; font : inherit ; font-size : .95 rem ;
}
. field input : focus , . field textarea : focus , . field select : focus { outline : 2 px solid var ( - - gold ) ; border-color : var ( - - gold ) ; }
. form-note { font-size : .78 rem ; color : var ( - - muted ) ; margin-top : 10 px ; }
. toast { display : none ; margin-top : 14 px ; padding : 12 px 14 px ; border-radius : 9 px ; background : #1e2a1c ; border : 1 px solid #2f5a2c ; color : #bfe6b6 ; font-size : .9 rem ; }
/* footer */
footer { padding : 54 px 0 40 px ; border-top : 1 px solid var ( - - line ) ; color : var ( - - muted ) ; font-size : .9 rem ; }
. foot-grid { display : flex ; justify-content : space-between ; flex-wrap : wrap ; gap : 24 px ; }
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 : 68 px 0 auto 0 ; flex-direction : column ; background : var ( - - bg -2 ) ; padding : 18 px 6 vw ; gap : 18 px ; border-bottom : 1 px solid var ( - - line ) ; }
. loc-card { grid-template-columns : 1 fr ; }
section { padding : 64 px 0 ; }
}
< / style >
< / head >
< body >
< header class = "nav" >
< div class = "wrap nav-inner" >
< a href = "#top" class = "brand" > 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 & Öffnungszeiten< / a >
< / div >
< div class = "hero-meta" >
< span > ⭐ < b > 4,2– 4,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 & 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" .< / 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" > 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 : 18 px ; bottom : 18 px ; z-index : 900 ; background : var ( - - gold ) ; color : #1a1410 ; border : 0 ; border-radius : 999 px ; padding : 13 px 20 px ; font : 700 .95 rem system-ui , - apple-system , Segoe UI , Roboto , sans-serif ; box-shadow : 0 10 px 26 px rgba ( 200 , 160 , 90 , .32 ) ; cursor : pointer ; transition : transform .15 s , background .2 s ; }
. cb-fab : hover { transform : translateY ( -2 px ) ; background : var ( - - gold -2 ) ; }
. cb-overlay { position : fixed ; inset : 0 ; z-index : 1000 ; background : rgba ( 10 , 8 , 7 , .6 ) ; backdrop-filter : blur ( 3 px ) ; display : none ; align-items : center ; justify-content : center ; padding : 18 px ; }
. cb-overlay . open { display : flex ; }
. cb-modal { position : relative ; width : min ( 440 px , 100 % ) ; background : var ( - - card ) ; color : var ( - - ink ) ; border : 1 px solid var ( - - line ) ; border-radius : 16 px ; box-shadow : 0 24 px 60 px rgba ( 0 , 0 , 0 , .5 ) ; padding : 28 px 26 px 22 px ; font-family : system-ui , - apple-system , Segoe UI , Roboto , sans-serif ; max-height : 92 vh ; overflow : auto ; animation : cbIn .18 s ease ; }
@ keyframes cbIn { from { opacity : 0 ; transform : translateY ( 14 px ) ; } to { opacity : 1 ; transform : none ; } }
. cb-modal h3 { margin : 0 0 4 px ; font-size : 1.35 rem ; font-family : 'Bebas Neue' , sans-serif ; letter-spacing : .5 px ; }
. cb-sub { margin : 0 0 18 px ; color : var ( - - muted ) ; font-size : .9 rem ; }
. cb-x { position : absolute ; top : 10 px ; right : 13 px ; background : none ; border : 0 ; font-size : 1.7 rem ; line-height : 1 ; color : var ( - - muted ) ; cursor : pointer ; }
. cb-x : hover { color : var ( - - ink ) ; }
. cb-modal label { display : block ; font-size : .82 rem ; font-weight : 600 ; margin-bottom : 13 px ; }
. cb-modal label . o { color : var ( - - muted ) ; font-weight : 400 ; }
. cb-modal input , . cb-modal textarea { width : 100 % ; margin-top : 5 px ; font : inherit ; font-size : .94 rem ; color : var ( - - ink ) ; background : #1a1611 ; border : 1 px solid var ( - - line ) ; border-radius : 9 px ; padding : 10 px 12 px ; resize : vertical ; }
. cb-modal input : focus , . cb-modal textarea : focus { outline : none ; border-color : var ( - - gold ) ; background : #1e1a15 ; }
. cb-submit { width : 100 % ; margin-top : 4 px ; background : var ( - - gold ) ; color : #1a1410 ; border : 0 ; border-radius : 999 px ; padding : 13 px ; font : 700 1 rem system-ui ; cursor : pointer ; transition : background .2 s ; }
. cb-submit : hover { background : var ( - - gold -2 ) ; }
. cb-submit : disabled { opacity : .6 ; cursor : default ; }
. cb-toast { display : none ; margin-top : 14 px ; padding : 11 px 13 px ; border-radius : 9 px ; font-size : .88 rem ; font-weight : 500 ; }
. cb-toast . ok { background : #1e2a1c ; color : #bfe6b6 ; border : 1 px solid #2f5a2c ; }
. cb-toast . err { background : #2e1c1c ; color : #f3c7c7 ; border : 1 px solid #5a2c2c ; }
@ media ( max-width : 560px ) { . cb-fab { right : 12 px ; bottom : 12 px ; padding : 11 px 17 px ; } }
< / 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" > × < / button >
< h3 id = "cbTitle" > Rückruf anfordern< / h3 >
< p class = "cb-sub" > Name & 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 >