arch-setup/files/Code - OSS/User/History/7457a526/IgyN.html

967 lines
No EOL
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>Knotenwelt Handgemachtes Makramee</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;1,300;1,400&family=DM+Sans:wght@300;400;500&display=swap" rel="stylesheet">
<style>
:root {
--cream: #faf6f0;
--warm-white: #fff9f2;
--sand: #e8ddd0;
--terra: #c4845a;
--terra-dark: #a06540;
--brown: #5c3d2e;
--text: #3a2a1f;
--text-light: #8a7060;
--rope: #d4b896;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
font-family: 'DM Sans', sans-serif;
background: var(--cream);
color: var(--text);
overflow-x: hidden;
}
/* ── NAV ── */
nav {
position: fixed; top: 0; left: 0; right: 0;
z-index: 100;
padding: 1.2rem 3rem;
display: flex; align-items: center; justify-content: space-between;
background: rgba(250,246,240,0.85);
backdrop-filter: blur(12px);
border-bottom: 1px solid rgba(196,132,90,0.15);
}
.nav-logo {
font-family: 'Cormorant Garamond', serif;
font-size: 1.6rem;
font-weight: 300;
color: var(--brown);
letter-spacing: 0.05em;
}
.nav-logo span { color: var(--terra); font-style: italic; }
.nav-links {
display: flex; gap: 2rem; list-style: none;
align-items: center;
}
.nav-links a {
text-decoration: none;
color: var(--text-light);
font-size: 0.85rem;
font-weight: 400;
letter-spacing: 0.08em;
text-transform: uppercase;
transition: color 0.2s;
}
.nav-links a:hover { color: var(--terra); }
.btn-login {
background: var(--terra);
color: white !important;
padding: 0.5rem 1.3rem;
border-radius: 50px;
transition: background 0.2s !important;
}
.btn-login:hover { background: var(--terra-dark) !important; color: white !important; }
/* ── HERO / SLIDESHOW ── */
.hero {
min-height: 100vh;
display: grid;
grid-template-columns: 1fr 1fr;
padding-top: 72px;
}
.hero-text {
display: flex; flex-direction: column; justify-content: center;
padding: 5rem 4rem 5rem 6rem;
animation: fadeUp 0.9s ease both;
}
.hero-tag {
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--terra);
margin-bottom: 1.5rem;
}
.hero-title {
font-family: 'Cormorant Garamond', serif;
font-size: clamp(3rem, 5vw, 4.5rem);
font-weight: 300;
line-height: 1.1;
color: var(--brown);
margin-bottom: 1.5rem;
}
.hero-title em { font-style: italic; color: var(--terra); }
.hero-sub {
font-size: 1rem;
color: var(--text-light);
line-height: 1.7;
max-width: 400px;
margin-bottom: 2.5rem;
}
.hero-buttons {
display: flex; gap: 1rem; flex-wrap: wrap;
}
.btn-primary {
background: var(--terra);
color: white;
border: none;
padding: 0.85rem 2rem;
border-radius: 50px;
font-family: 'DM Sans', sans-serif;
font-size: 0.9rem;
font-weight: 500;
cursor: pointer;
text-decoration: none;
transition: background 0.2s, transform 0.15s;
}
.btn-primary:hover { background: var(--terra-dark); transform: translateY(-1px); }
.btn-ghost {
background: transparent;
color: var(--brown);
border: 1.5px solid var(--sand);
padding: 0.85rem 2rem;
border-radius: 50px;
font-family: 'DM Sans', sans-serif;
font-size: 0.9rem;
font-weight: 400;
cursor: pointer;
text-decoration: none;
transition: border-color 0.2s, transform 0.15s;
}
.btn-ghost:hover { border-color: var(--terra); transform: translateY(-1px); }
/* ── SLIDESHOW ── */
.hero-slideshow {
position: relative;
overflow: hidden;
background: var(--sand);
}
.slide {
position: absolute; inset: 0;
opacity: 0;
transition: opacity 1.2s ease;
display: flex; align-items: center; justify-content: center;
}
.slide.active { opacity: 1; }
/* CSS Makramee-Muster als Platzhalter */
.slide-1 { background: linear-gradient(135deg, #e8d5c0 0%, #d4b896 50%, #c49a72 100%); }
.slide-2 { background: linear-gradient(135deg, #c9b49a 0%, #b89870 50%, #d4a878 100%); }
.slide-3 { background: linear-gradient(135deg, #dfc9ae 0%, #c8a882 50%, #b8906a 100%); }
.slide-pattern {
width: 80%;
max-width: 360px;
aspect-ratio: 3/4;
position: relative;
}
/* Makramee Rope-Knoten SVG Pattern */
.slide-pattern svg {
width: 100%; height: 100%;
opacity: 0.35;
}
.slide-caption {
position: absolute;
bottom: 2rem; left: 2rem; right: 2rem;
color: white;
font-family: 'Cormorant Garamond', serif;
font-size: 1.4rem;
font-style: italic;
font-weight: 300;
text-shadow: 0 2px 20px rgba(0,0,0,0.3);
}
.slide-dots {
position: absolute;
bottom: 1.5rem; right: 2rem;
display: flex; gap: 0.5rem;
}
.dot {
width: 6px; height: 6px;
border-radius: 50%;
background: rgba(255,255,255,0.4);
cursor: pointer;
transition: background 0.2s;
}
.dot.active { background: white; }
/* ── ABOUT SECTION ── */
.section {
padding: 7rem 6rem;
}
.section-tag {
font-size: 0.75rem;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--terra);
font-weight: 500;
margin-bottom: 1rem;
}
.section-title {
font-family: 'Cormorant Garamond', serif;
font-size: clamp(2rem, 3.5vw, 3rem);
font-weight: 300;
color: var(--brown);
margin-bottom: 1.5rem;
line-height: 1.2;
}
.about-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 5rem;
align-items: center;
}
.about-text p {
color: var(--text-light);
line-height: 1.8;
margin-bottom: 1.2rem;
font-size: 0.95rem;
}
.about-features {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
margin-top: 2rem;
}
.feature-card {
background: var(--warm-white);
border: 1px solid var(--sand);
border-radius: 16px;
padding: 1.5rem;
transition: transform 0.2s, box-shadow 0.2s;
}
.feature-card:hover { transform: translateY(-3px); box-shadow: 0 8px 30px rgba(92,61,46,0.08); }
.feature-card h4 {
font-family: 'Cormorant Garamond', serif;
font-size: 1.1rem;
font-weight: 400;
color: var(--brown);
margin-bottom: 0.3rem;
}
.feature-card p {
font-size: 0.8rem;
color: var(--text-light);
line-height: 1.5;
}
.about-visual {
position: relative;
}
.about-img-placeholder {
width: 100%;
aspect-ratio: 4/5;
background: linear-gradient(160deg, var(--sand) 0%, var(--rope) 100%);
border-radius: 24px;
display: flex; align-items: center; justify-content: center;
overflow: hidden;
position: relative;
}
.about-img-placeholder::before {
content: '';
position: absolute; inset: 0;
background: repeating-linear-gradient(
45deg,
transparent,
transparent 20px,
rgba(255,255,255,0.08) 20px,
rgba(255,255,255,0.08) 21px
);
}
.about-img-text {
font-family: 'Cormorant Garamond', serif;
font-size: 1.1rem;
font-style: italic;
color: white;
text-align: center;
padding: 2rem;
text-shadow: 0 2px 10px rgba(0,0,0,0.2);
}
.about-badge {
position: absolute;
bottom: -1rem; right: -1rem;
background: var(--terra);
color: white;
border-radius: 50%;
width: 110px; height: 110px;
display: flex; flex-direction: column; align-items: center; justify-content: center;
text-align: center;
box-shadow: 0 4px 20px rgba(196,132,90,0.4);
}
.about-badge span:first-child {
font-family: 'Cormorant Garamond', serif;
font-size: 1.8rem;
font-weight: 300;
line-height: 1;
}
.about-badge span:last-child {
font-size: 0.65rem;
letter-spacing: 0.1em;
text-transform: uppercase;
opacity: 0.9;
}
/* ── STORE INFO ── */
.store-section {
background: var(--warm-white);
padding: 5rem 6rem;
border-top: 1px solid var(--sand);
border-bottom: 1px solid var(--sand);
}
.store-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
align-items: start;
max-width: 900px;
margin: 3rem auto 0;
}
.store-info-block h3 {
font-family: 'Cormorant Garamond', serif;
font-size: 1.4rem;
font-weight: 400;
color: var(--brown);
margin-bottom: 1rem;
}
.store-info-block p, .store-info-block address {
font-style: normal;
color: var(--text-light);
line-height: 1.8;
font-size: 0.9rem;
}
.insta-link {
display: inline-flex; align-items: center; gap: 0.6rem;
margin-top: 1.5rem;
color: var(--terra);
text-decoration: none;
font-weight: 500;
font-size: 0.9rem;
transition: gap 0.2s;
}
.insta-link:hover { gap: 0.9rem; }
.insta-icon {
width: 36px; height: 36px;
background: linear-gradient(135deg, #f58529, #dd2a7b, #8134af);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white;
font-size: 1.1rem;
}
/* ── CONTACT ── */
.contact-section {
padding: 7rem 6rem;
max-width: 700px;
margin: 0 auto;
text-align: center;
}
.contact-form {
margin-top: 3rem;
text-align: left;
display: flex; flex-direction: column; gap: 1.2rem;
}
.form-row {
display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;
}
.form-group {
display: flex; flex-direction: column; gap: 0.4rem;
}
.form-group label {
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--text-light);
}
.form-group input,
.form-group textarea {
background: var(--warm-white);
border: 1.5px solid var(--sand);
border-radius: 10px;
padding: 0.8rem 1rem;
font-family: 'DM Sans', sans-serif;
font-size: 0.9rem;
color: var(--text);
outline: none;
transition: border-color 0.2s;
resize: none;
}
.form-group input:focus,
.form-group textarea:focus { border-color: var(--terra); }
.form-group textarea { min-height: 130px; }
.form-submit {
align-self: flex-start;
}
.success-msg {
display: none;
background: #f0faf5;
border: 1px solid #a8d8bc;
color: #2d6a4f;
padding: 1rem 1.5rem;
border-radius: 10px;
font-size: 0.9rem;
}
/* ── MODAL (Login/Register) ── */
.modal-overlay {
display: none;
position: fixed; inset: 0;
background: rgba(58,42,31,0.4);
backdrop-filter: blur(6px);
z-index: 200;
align-items: center; justify-content: center;
}
.modal-overlay.open { display: flex; }
.modal {
background: var(--warm-white);
border-radius: 24px;
padding: 2.5rem;
width: 90%; max-width: 420px;
position: relative;
animation: fadeUp 0.3s ease;
box-shadow: 0 20px 60px rgba(58,42,31,0.2);
}
.modal-close {
position: absolute; top: 1.2rem; right: 1.2rem;
background: none; border: none;
font-size: 1.3rem; cursor: pointer;
color: var(--text-light);
line-height: 1;
}
.modal-title {
font-family: 'Cormorant Garamond', serif;
font-size: 1.8rem;
font-weight: 300;
color: var(--brown);
margin-bottom: 0.3rem;
}
.modal-sub {
font-size: 0.85rem;
color: var(--text-light);
margin-bottom: 2rem;
}
.modal-tabs {
display: flex; gap: 0;
border: 1.5px solid var(--sand);
border-radius: 50px;
margin-bottom: 2rem;
overflow: hidden;
}
.modal-tab {
flex: 1;
padding: 0.55rem;
border: none;
background: transparent;
font-family: 'DM Sans', sans-serif;
font-size: 0.85rem;
cursor: pointer;
color: var(--text-light);
border-radius: 50px;
transition: all 0.2s;
}
.modal-tab.active { background: var(--terra); color: white; }
.modal-form { display: flex; flex-direction: column; gap: 1rem; }
.modal-form input {
background: var(--cream);
border: 1.5px solid var(--sand);
border-radius: 10px;
padding: 0.75rem 1rem;
font-family: 'DM Sans', sans-serif;
font-size: 0.9rem;
color: var(--text);
outline: none;
transition: border-color 0.2s;
width: 100%;
}
.modal-form input:focus { border-color: var(--terra); }
/* ── FOOTER ── */
footer {
background: var(--brown);
color: rgba(255,255,255,0.6);
padding: 3rem 6rem;
display: flex;
align-items: center; justify-content: space-between;
flex-wrap: wrap; gap: 1rem;
}
.footer-logo {
font-family: 'Cormorant Garamond', serif;
font-size: 1.4rem;
font-weight: 300;
color: white;
}
.footer-logo span { font-style: italic; color: var(--terra); }
footer p { font-size: 0.8rem; }
footer a { color: rgba(255,255,255,0.5); text-decoration: none; transition: color 0.2s; }
footer a:hover { color: var(--terra); }
/* ── ANIMATIONS ── */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(24px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.7s ease, transform 0.7s ease;
}
.reveal.visible { opacity: 1; transform: translateY(0); }
/* ── RESPONSIVE ── */
@media (max-width: 900px) {
nav { padding: 1rem 1.5rem; }
.nav-links { gap: 1rem; }
.hero { grid-template-columns: 1fr; min-height: auto; }
.hero-slideshow { height: 50vw; min-height: 300px; }
.hero-text { padding: 3rem 2rem; }
.section { padding: 4rem 2rem; }
.about-grid { grid-template-columns: 1fr; gap: 2rem; }
.store-section { padding: 4rem 2rem; }
.store-grid { grid-template-columns: 1fr; gap: 2rem; }
.contact-section { padding: 4rem 2rem; }
.form-row { grid-template-columns: 1fr; }
footer { padding: 2rem; flex-direction: column; text-align: center; }
}
</style>
</head>
<body>
<!-- NAV -->
<nav>
<div class="nav-logo">Knoten<span>welt</span></div>
<ul class="nav-links">
<li><a href="#about">Über uns</a></li>
<li><a href="#laden">Laden</a></li>
<li><a href="#kontakt">Kontakt</a></li>
<li><a href="#" class="btn-login" onclick="openModal(event)">Anmelden</a></li>
</ul>
</nav>
<!-- HERO -->
<section class="hero">
<div class="hero-text">
<p class="hero-tag">Handgemacht mit Liebe</p>
<h1 class="hero-title">
Makramee,<br>
<em>das Geschichten</em><br>
erzählt
</h1>
<p class="hero-sub">
Jedes Stück ein Unikat geknüpft von Hand, mit Geduld und Herzblut.
Wandbehänge, Blumenampeln, Körbe und mehr.
</p>
<div class="hero-buttons">
<a href="#laden" class="btn-primary">Laden besuchen</a>
<a href="#kontakt" class="btn-ghost">Kontakt aufnehmen</a>
</div>
</div>
<div class="hero-slideshow" id="slideshow">
<div class="slide active slide-1">
<div class="slide-pattern">
<svg viewBox="0 0 200 260" xmlns="http://www.w3.org/2000/svg">
<!-- Makramee Knoten Pattern -->
<g stroke="white" stroke-width="2.5" fill="none" stroke-linecap="round">
<!-- vertical ropes -->
<line x1="60" y1="0" x2="60" y2="260"/>
<line x1="100" y1="0" x2="100" y2="260"/>
<line x1="140" y1="0" x2="140" y2="260"/>
<!-- square knots row 1 -->
<path d="M60,40 Q80,30 100,40 Q80,50 60,40"/>
<path d="M100,40 Q120,30 140,40 Q120,50 100,40"/>
<!-- fringe bottom -->
<line x1="50" y1="200" x2="40" y2="260"/>
<line x1="60" y1="200" x2="55" y2="260"/>
<line x1="75" y1="200" x2="72" y2="260"/>
<line x1="90" y1="200" x2="90" y2="260"/>
<line x1="105" y1="200" x2="108" y2="260"/>
<line x1="120" y1="200" x2="125" y2="260"/>
<line x1="135" y1="200" x2="140" y2="260"/>
<line x1="150" y1="200" x2="160" y2="260"/>
<!-- more knots -->
<path d="M60,80 Q80,70 100,80 Q80,90 60,80"/>
<path d="M100,80 Q120,70 140,80 Q120,90 100,80"/>
<path d="M80,110 Q100,100 120,110 Q100,120 80,110"/>
<path d="M60,140 Q80,130 100,140 Q80,150 60,140"/>
<path d="M100,140 Q120,130 140,140 Q120,150 100,140"/>
<path d="M80,170 Q100,160 120,170 Q100,180 80,170"/>
</g>
</svg>
</div>
<div class="slide-caption">Wandbehänge & Dekor</div>
</div>
<div class="slide slide-2">
<div class="slide-pattern">
<svg viewBox="0 0 200 260" xmlns="http://www.w3.org/2000/svg">
<g stroke="white" stroke-width="2.5" fill="none" stroke-linecap="round">
<circle cx="100" cy="80" r="40" stroke-dasharray="8 4"/>
<line x1="70" y1="120" x2="55" y2="260"/>
<line x1="80" y1="120" x2="70" y2="260"/>
<line x1="95" y1="122" x2="90" y2="260"/>
<line x1="105" y1="122" x2="110" y2="260"/>
<line x1="120" y1="120" x2="130" y2="260"/>
<line x1="130" y1="120" x2="145" y2="260"/>
<path d="M60,140 Q100,130 140,140"/>
<path d="M65,155 Q100,145 135,155"/>
<path d="M70,170 Q100,160 130,170"/>
</g>
</svg>
</div>
<div class="slide-caption">Blumenampeln</div>
</div>
<div class="slide slide-3">
<div class="slide-pattern">
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<g stroke="white" stroke-width="2" fill="none" stroke-linecap="round">
<rect x="40" y="40" width="120" height="120" rx="8"/>
<rect x="55" y="55" width="90" height="90" rx="6"/>
<line x1="40" y1="70" x2="55" y2="70"/>
<line x1="40" y1="100" x2="55" y2="100"/>
<line x1="40" y1="130" x2="55" y2="130"/>
<line x1="145" y1="70" x2="160" y2="70"/>
<line x1="145" y1="100" x2="160" y2="100"/>
<line x1="145" y1="130" x2="160" y2="130"/>
<line x1="70" y1="40" x2="70" y2="55"/>
<line x1="100" y1="40" x2="100" y2="55"/>
<line x1="130" y1="40" x2="130" y2="55"/>
<line x1="70" y1="145" x2="70" y2="160"/>
<line x1="100" y1="145" x2="100" y2="160"/>
<line x1="130" y1="145" x2="130" y2="160"/>
<circle cx="100" cy="100" r="15"/>
</g>
</svg>
</div>
<div class="slide-caption">Körbe & Accessoires</div>
</div>
<div class="slide-dots">
<div class="dot active" onclick="goSlide(0)"></div>
<div class="dot" onclick="goSlide(1)"></div>
<div class="dot" onclick="goSlide(2)"></div>
</div>
</div>
</section>
<!-- ABOUT -->
<section class="section" id="about">
<div class="about-grid reveal">
<div class="about-text">
<p class="section-tag">Unsere Geschichte</p>
<h2 class="section-title">Handwerk mit<br>Herz & Seele</h2>
<p>Was als kleines Hobby begann, ist heute eine Leidenschaft geworden. Jedes Stück wird von Hand geknüpft mit natürlichen Materialien, viel Zeit und noch mehr Liebe.</p>
<p>Von gemütlichen Wandbehängen bis zu eleganten Blumenampeln: Du findest alles in unserem kleinen Schrankladen oder kannst direkt anfragen.</p>
<div class="about-features">
<div class="feature-card">
<h4>100 % Handarbeit</h4>
<p>Kein Stück ist wie das andere.</p>
</div>
<div class="feature-card">
<h4>Natürliche Materialien</h4>
<p>Baumwolle, Jute & Leinen.</p>
</div>
<div class="feature-card">
<h4>Auf Wunsch</h4>
<p>Individuelle Bestellungen möglich.</p>
</div>
<div class="feature-card">
<h4>Mit Liebe gemacht</h4>
<p>Von einer Mutter, mit Herz.</p>
</div>
</div>
</div>
<div class="about-visual">
<div class="about-img-placeholder">
<div class="about-img-text">
Hier kommen<br>deine schönsten<br>Produktfotos hin
</div>
</div>
<div class="about-badge">
<span>100%</span>
<span>Unikate</span>
</div>
</div>
</div>
</section>
<!-- STORE INFO -->
<section class="store-section" id="laden">
<div style="text-align:center">
<p class="section-tag">Wo du uns findest</p>
<h2 class="section-title">Im Laden & Online</h2>
</div>
<div class="store-grid reveal">
<div class="store-info-block">
<h3>Unser Schrankladen</h3>
<address>
Musterstraße 12<br>
01234 Musterstadt<br><br>
MoSa: 1018 Uhr<br>
So: nach Vereinbarung
</address>
</div>
<div class="store-info-block">
<h3>Folg uns auf Instagram</h3>
<p>Aktuelle Stücke, neue Ideen und ein Blick hinter die Kulissen täglich frisch.</p>
<a href="https://instagram.com" target="_blank" class="insta-link">
<span class="insta-icon"></span>
@knotenwelt →
</a>
</div>
</div>
</section>
<!-- CONTACT -->
<section class="contact-section" id="kontakt">
<div class="reveal">
<p class="section-tag">Schreib uns</p>
<h2 class="section-title">Kontakt</h2>
<p style="color:var(--text-light); line-height:1.7; font-size:0.95rem">
Fragen, Wunschbestellungen oder einfach ein nettes Hallo wir freuen uns über jede Nachricht.
</p>
<form class="contact-form" onsubmit="submitForm(event)">
<div class="form-row">
<div class="form-group">
<label>Name</label>
<input type="text" placeholder="Dein Name" required>
</div>
<div class="form-group">
<label>E-Mail</label>
<input type="email" placeholder="deine@email.de" required>
</div>
</div>
<div class="form-group">
<label>Nachricht</label>
<textarea placeholder="Deine Nachricht…" required></textarea>
</div>
<div class="success-msg" id="successMsg">
✓ Deine Nachricht wurde gesendet! Wir melden uns bald.
</div>
<button type="submit" class="btn-primary form-submit">Nachricht senden →</button>
</form>
</div>
</section>
<!-- FOOTER -->
<footer>
<div class="footer-logo">Knoten<span>welt</span></div>
<p>© 2025 Knotenwelt · Alle Rechte vorbehalten</p>
<div style="display:flex; gap:1.5rem; font-size:0.8rem">
<a href="#">Impressum</a>
<a href="#">Datenschutz</a>
</div>
</footer>
<!-- LOGIN MODAL -->
<div class="modal-overlay" id="modalOverlay" onclick="closeModalBg(event)">
<div class="modal">
<button class="modal-close" onclick="closeModal()"></button>
<h2 class="modal-title">Willkommen</h2>
<p class="modal-sub">Melde dich an oder erstelle ein Konto</p>
<div class="modal-tabs">
<button class="modal-tab active" onclick="switchTab(this,'login')">Anmelden</button>
<button class="modal-tab" onclick="switchTab(this,'register')">Registrieren</button>
</div>
<div id="loginForm">
<form class="modal-form" onsubmit="handleAuth(event,'login')">
<input type="email" name="email" placeholder="E-Mail-Adresse" required>
<input type="password" name="password" placeholder="Passwort" required>
<p class="auth-error" style="color:#c0392b;font-size:0.85rem;min-height:1.2em"></p>
<button type="submit" class="btn-primary" style="width:100%">Anmelden</button>
</form>
</div>
<div id="registerForm" style="display:none">
<form class="modal-form" onsubmit="handleAuth(event,'register')">
<input type="text" name="name" placeholder="Dein Name" required>
<input type="email" name="email" placeholder="E-Mail-Adresse" required>
<input type="password" name="password" placeholder="Passwort (min. 8 Zeichen)" required>
<p class="auth-error" style="color:#c0392b;font-size:0.85rem;min-height:1.2em"></p>
<button type="submit" class="btn-primary" style="width:100%">Konto erstellen</button>
</form>
</div>
</div>
</div>
<script>
// Slideshow
let current = 0;
const slides = document.querySelectorAll('.slide');
const dots = document.querySelectorAll('.dot');
function goSlide(n) {
slides[current].classList.remove('active');
dots[current].classList.remove('active');
current = n;
slides[current].classList.add('active');
dots[current].classList.add('active');
}
setInterval(() => goSlide((current + 1) % slides.length), 4000);
// Scroll reveal
const observer = new IntersectionObserver(entries => {
entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('visible'); });
}, { threshold: 0.15 });
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
// Modal
function openModal(e) { e.preventDefault(); document.getElementById('modalOverlay').classList.add('open'); }
function closeModal() { document.getElementById('modalOverlay').classList.remove('open'); }
function closeModalBg(e) { if (e.target === document.getElementById('modalOverlay')) closeModal(); }
function switchTab(btn, tab) {
document.querySelectorAll('.modal-tab').forEach(t => t.classList.remove('active'));
btn.classList.add('active');
document.getElementById('loginForm').style.display = tab === 'login' ? '' : 'none';
document.getElementById('registerForm').style.display = tab === 'register' ? '' : 'none';
}
// ── Contact form ──────────────────────────────────────────
async function submitForm(e) {
e.preventDefault();
const btn = e.target.querySelector('button[type="submit"]');
const inputs = e.target.querySelectorAll('input, textarea');
const [nameEl, emailEl, msgEl] = inputs;
btn.disabled = true;
btn.textContent = 'Senden…';
try {
const res = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: nameEl.value, email: emailEl.value, message: msgEl.value }),
});
if (!res.ok) throw new Error();
document.getElementById('successMsg').style.display = 'block';
btn.style.display = 'none';
} catch {
btn.disabled = false;
btn.textContent = 'Nachricht senden →';
alert('Fehler beim Senden. Bitte versuche es später nochmal.');
}
}
// ── Auth ───────────────────────────────────────────────────
let currentUser = null;
// JWT aus localStorage laden
(async function checkAuth() {
const token = localStorage.getItem('token');
if (!token) return;
try {
const res = await fetch('/api/auth/me', { headers: { Authorization: `Bearer ${token}` } });
if (!res.ok) { localStorage.removeItem('token'); return; }
currentUser = await res.json();
updateNavUser();
} catch {}
})();
function updateNavUser() {
const loginLink = document.querySelector('.btn-login');
if (currentUser) {
loginLink.textContent = currentUser.name.split(' ')[0];
loginLink.onclick = logout;
}
}
function logout(e) {
e.preventDefault();
localStorage.removeItem('token');
currentUser = null;
document.querySelector('.btn-login').textContent = 'Anmelden';
document.querySelector('.btn-login').onclick = openModal;
}
async function handleAuth(e, mode) {
e.preventDefault();
const form = e.target;
const btn = form.querySelector('button');
const errorEl = form.querySelector('.auth-error');
errorEl.textContent = '';
btn.disabled = true;
const body = mode === 'register'
? { name: form.querySelector('[name=name]').value, email: form.querySelector('[name=email]').value, password: form.querySelector('[name=password]').value }
: { email: form.querySelector('[name=email]').value, password: form.querySelector('[name=password]').value };
try {
const res = await fetch(`/api/auth/${mode}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const data = await res.json();
if (!res.ok) { errorEl.textContent = data.error; btn.disabled = false; return; }
localStorage.setItem('token', data.token);
currentUser = data.user;
updateNavUser();
closeModal();
} catch {
errorEl.textContent = 'Verbindungsfehler';
btn.disabled = false;
}
}
</script>
</body>
</html>