Files
vans-diy-bastelbedarf/public/gate.html
T
qcigano c6f8465e64 Zugangsseite: zwei eigene Fenster für qciga und VanVan statt einer gemeinsamen Box
Auf ausdrücklichen Wunsch im Stil einer bereits bestehenden Zwei-Personen-Zugangsseite umgebaut,
aber komplett an Van's eigene Marke angepasst (Farben/Schrift/Wasserzeichen unverändert: Lila/
Anthrazit/Hellblau/Gold statt fremder Projektfarben). Jede Person bekommt ihr eigenes Fenster mit
Avatar (VanVan: ihr echtes Porträtfoto; qciga: passendes Icon, da noch kein Foto in diesem Projekt
hinterlegt ist), eigenem Codefeld und eigenem "Öffnen"-Button in unterschiedlicher Akzentfarbe
(Cyan/Violett für qciga, Gold/Violett für VanVan). Technisch unverändert: /gate-auth erkennt die
Rolle weiterhin selbst anhand des eingegebenen Codes, unabhängig vom benutzten Fenster.

Dabei gefundener und behobener Bug: /img/vanvan-portrait.png wurde von der Zugangs-Schranke selbst
blockiert (302) — das für den Avatar gebrauchte Foto zeigte deshalb nur einen leeren Kreis. Gezielt
nur diese eine Datei freigegeben (kein Shop-/Kundendatum, ohnehin VanVans öffentliches Porträtfoto).

Per echtem Browsertest verifiziert: beide Fenster funktional getrennt (falscher Code im einen
Fenster zeigt den Fehler nur dort, richtiger Code im anderen Fenster loggt korrekt ein), Layout auf
Desktop nebeneinander und auf schmalen Bildschirmen sauber gestapelt.
2026-08-04 16:28:05 +02:00

357 lines
13 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Zugang — Van's DIY & Bastelbedarf</title>
<meta name="robots" content="noindex, nofollow" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<style>
:root {
--c-black: #0a0910;
--c-anthracite: #1b1a22;
--c-anthracite-light: #252333;
--c-text: #f4f1f7;
--c-text-muted: #b7aec4;
--c-accent: #5fd3ec;
--c-accent-hover: #3ca9c2;
--c-purple-glow: #9b7fd6;
--c-gold: #e3b23c;
--c-gold-hover: #c99527;
--radius-l: 22px;
--radius-m: 16px;
--ease: cubic-bezier(0.22, 1, 0.36, 1);
}
* { box-sizing: border-box; }
/* Für Screenreader vorhanden, visuell aber unsichtbar — ersetzt bei den Formularfeldern dieser
Seite den (allein nicht ausreichenden) Placeholder-Text durch ein echtes <label>. */
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
html, body { height: 100%; }
body {
margin: 0;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 1.5rem;
position: relative;
overflow: hidden;
background: var(--c-black);
background-image: radial-gradient(60% 50% at 15% 10%, color-mix(in srgb, var(--c-purple-glow) 22%, transparent), transparent 70%),
radial-gradient(50% 45% at 85% 90%, color-mix(in srgb, var(--c-accent) 16%, transparent), transparent 70%);
color: var(--c-text);
font-family: "Inter", "Manrope", system-ui, sans-serif;
line-height: 1.6;
}
/* Das echte Van's-Logo als riesiges, sehr dezentes Wasserzeichen im Hintergrund — invert()
dreht das schwarze Logo auf weißem Grund um (weiß -> schwarz, schwarz -> weiß), danach macht
mix-blend-mode:screen den (jetzt schwarzen) ehemals-weißen Kreis komplett unsichtbar und
lässt nur die (jetzt weißen) Linien leicht aufleuchten — kein Bildbearbeitungsprogramm nötig,
rein CSS. Langsame Drehung sorgt für einen dezenten "lebendigen" Glanz-Effekt. */
.gate-logo-bg {
position: absolute;
top: 50%;
left: 50%;
width: min(1400px, 200vw);
height: min(1400px, 200vw);
transform: translate(-50%, -50%);
background: url("/logo.png") center / contain no-repeat;
filter: invert(1);
mix-blend-mode: screen;
opacity: 0.09;
animation: gate-logo-spin 120s linear infinite;
pointer-events: none;
}
@keyframes gate-logo-spin {
from { transform: translate(-50%, -50%) rotate(0deg); }
to { transform: translate(-50%, -50%) rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) { .gate-logo-bg { animation: none; } }
/* 04.08.2026, auf ausdrücklichen Wunsch: statt EINER gemeinsamen Zugangscode-Box (in der beide
einfach irgendeinen der beiden Codes eintippen konnten) jetzt zwei eigene "Fenster" — eins für
qciga, eins für VanVan — im Stil einer anderen, bereits bestehenden Zwei-Personen-Zugangsseite,
aber komplett an Van's eigene Marke angepasst (Farben/Schrift/Wasserzeichen unverändert, siehe
Branding.md: kein Babyblau/Rot-Look von anderen Projekten, sondern die eigene Lila/Anthrazit/
Hellblau/Gold-Welt). Technisch ändert sich nichts: /gate-auth erkennt die Rolle ohnehin selbst
anhand DES CODES, nicht danach, welches Fenster benutzt wurde — die Aufteilung ist rein dafür
da, dass jede/r sofort das eigene Feld findet, statt raten zu müssen. */
.gate-wrap {
position: relative;
z-index: 1;
max-width: 700px;
width: 100%;
text-align: center;
}
.gate-header { margin-bottom: 1.6rem; }
.gate-eyebrow {
display: inline-block;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--c-gold);
background: color-mix(in srgb, var(--c-gold) 16%, transparent);
border: 1px solid color-mix(in srgb, var(--c-gold) 40%, transparent);
border-radius: 999px;
padding: 0.3rem 0.9rem;
margin-bottom: 1rem;
}
.gate-header h1 {
font-family: "Fraunces", "Playfair Display", Georgia, serif;
font-size: 1.7rem;
font-weight: 600;
margin: 0 0 0.6rem;
line-height: 1.2;
}
.gate-header p {
margin: 0;
color: var(--c-text-muted);
font-size: 0.96rem;
}
.gate-cards {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 1.1rem;
}
.gate-card {
position: relative;
overflow: hidden;
flex: 1 1 250px;
max-width: 300px;
padding: 1.8rem 1.5rem;
border-radius: var(--radius-l);
border: 1.5px solid transparent;
background-size: 100% 100%, 300% 100%;
animation: gate-border-shift 9s ease-in-out infinite;
box-shadow: 0 20px 50px -20px rgba(0, 0, 0, 0.7);
}
.gate-card-qciga {
background:
linear-gradient(165deg, var(--c-anthracite-light), var(--c-anthracite)) padding-box,
linear-gradient(120deg, var(--c-accent), var(--c-accent-hover), var(--c-purple-glow), var(--c-accent)) border-box;
}
.gate-card-vanvan {
background:
linear-gradient(165deg, var(--c-anthracite-light), var(--c-anthracite)) padding-box,
linear-gradient(120deg, var(--c-gold), var(--c-purple-glow), var(--c-accent), var(--c-gold)) border-box;
}
@keyframes gate-border-shift {
0%, 100% { background-position: 0 0, 0% 50%; }
50% { background-position: 0 0, 100% 50%; }
}
.gate-card::after {
content: "";
position: absolute;
top: 0;
left: -60%;
width: 35%;
height: 100%;
background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.1), transparent);
transform: skewX(-18deg);
animation: gate-shine 6s ease-in-out infinite;
pointer-events: none;
border-radius: inherit;
}
.gate-card-vanvan::after { animation-delay: 1.2s; }
@keyframes gate-shine {
0% { left: -60%; }
35%, 100% { left: 130%; }
}
.gate-card > * { position: relative; z-index: 1; }
@media (prefers-reduced-motion: reduce) { .gate-card, .gate-card::after { animation: none; } }
/* Avatar je Karte: dasselbe "Glow-Ring"-Prinzip wie beim .portrait-frame-Baustein auf der
restlichen Seite (siehe Branding.md), nur kompakt für ein kleines Zugangs-Fenster. VanVan
bekommt ihr echtes Porträtfoto, für qciga gibt es (noch) kein Foto in diesem Projekt — deshalb
ein passendes Icon in derselben Bildsprache statt eines geratenen/fremden Fotos. */
.gate-avatar {
position: relative;
width: 84px;
height: 84px;
margin: 0 auto 1rem;
}
.gate-avatar-glow {
position: absolute;
inset: -12px;
border-radius: 50%;
filter: blur(13px);
opacity: 0.6;
animation: gate-avatar-pulse 3.2s ease-in-out infinite;
}
.gate-card-qciga .gate-avatar-glow { background: radial-gradient(circle, color-mix(in srgb, var(--c-accent) 70%, transparent), transparent 72%); }
.gate-card-vanvan .gate-avatar-glow { background: radial-gradient(circle, color-mix(in srgb, var(--c-gold) 70%, transparent), transparent 72%); }
@keyframes gate-avatar-pulse {
0%, 100% { opacity: 0.45; transform: scale(1); }
50% { opacity: 0.85; transform: scale(1.12); }
}
@media (prefers-reduced-motion: reduce) { .gate-avatar-glow { animation: none; } }
.gate-avatar-photo,
.gate-avatar-icon {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
border-radius: 50%;
background: linear-gradient(160deg, var(--c-anthracite-light), var(--c-anthracite));
}
.gate-avatar-photo { object-fit: cover; object-position: top center; }
.gate-card-qciga .gate-avatar-photo,
.gate-card-qciga .gate-avatar-icon { box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent) 50%, transparent), 0 10px 26px -10px rgba(0, 0, 0, 0.7); }
.gate-card-vanvan .gate-avatar-photo,
.gate-card-vanvan .gate-avatar-icon { box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-gold) 50%, transparent), 0 10px 26px -10px rgba(0, 0, 0, 0.7); }
.gate-avatar-icon { font-size: 2.1rem; }
.gate-card h2 {
font-family: "Fraunces", "Playfair Display", Georgia, serif;
font-size: 1.2rem;
font-weight: 600;
margin: 0 0 1.1rem;
}
.gate-card-qciga h2 { color: var(--c-accent); }
.gate-card-vanvan h2 { color: var(--c-gold); }
.gate-card input {
width: 100%;
padding: 0.85rem 0.9rem;
border-radius: 12px;
text-align: center;
letter-spacing: 0.08em;
font-size: 1rem;
margin-bottom: 0.8rem;
background: rgba(244, 241, 247, 0.05);
border: 1.5px solid rgba(244, 241, 247, 0.16);
color: var(--c-text);
font-family: inherit;
}
.gate-card-qciga input:focus { outline: none; border-color: var(--c-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent) 25%, transparent); }
.gate-card-vanvan input:focus { outline: none; border-color: var(--c-gold); box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-gold) 25%, transparent); }
.gate-card button {
width: 100%;
padding: 0.8rem 1rem;
border-radius: 12px;
border: none;
font-weight: 800;
font-size: 0.96rem;
cursor: pointer;
transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.gate-card-qciga button { background: linear-gradient(120deg, var(--c-accent), var(--c-accent-hover)); color: var(--c-black); }
.gate-card-qciga button:hover { transform: translateY(-2px); box-shadow: 0 10px 24px -10px color-mix(in srgb, var(--c-accent) 60%, transparent); }
.gate-card-vanvan button { background: linear-gradient(120deg, var(--c-gold), var(--c-gold-hover)); color: var(--c-black); }
.gate-card-vanvan button:hover { transform: translateY(-2px); box-shadow: 0 10px 24px -10px color-mix(in srgb, var(--c-gold) 60%, transparent); }
.gate-fehler {
color: #ff9a9a;
font-size: 0.85rem;
margin: 0.8rem 0 0;
display: none;
}
.gate-fehler.zeige { display: block; }
.gate-logo {
font-family: "Fraunces", "Playfair Display", Georgia, serif;
font-weight: 700;
font-size: 0.95rem;
color: var(--c-text-muted);
margin: 1.6rem 0 0;
}
@media (max-width: 560px) {
.gate-card { max-width: 100%; flex-basis: 100%; }
}
</style>
</head>
<body>
<div class="gate-logo-bg" aria-hidden="true"></div>
<div class="gate-wrap">
<div class="gate-header">
<span class="gate-eyebrow">🔒 Noch nicht öffentlich</span>
<h1>Van's DIY &amp; Bastelbedarf</h1>
<p>Diese Seite ist gerade im Aufbau und noch nicht für die Öffentlichkeit freigegeben.<br />Zugangscode eingeben, um weiterzukommen.</p>
</div>
<div class="gate-cards">
<div class="gate-card gate-card-qciga">
<div class="gate-avatar" aria-hidden="true">
<span class="gate-avatar-glow"></span>
<span class="gate-avatar-icon">🧑‍💻</span>
</div>
<h2>qciga</h2>
<form class="gate-form" data-role="qciga">
<label class="sr-only" for="gate-code-qciga">Zugangscode für qciga</label>
<input type="text" id="gate-code-qciga" placeholder="Zugangscode" autocomplete="off" autocapitalize="off" spellcheck="false" />
<button type="submit">🔑 Öffnen</button>
</form>
<p class="gate-fehler" data-fehler-for="qciga" role="alert" aria-live="assertive"></p>
</div>
<div class="gate-card gate-card-vanvan">
<div class="gate-avatar" aria-hidden="true">
<span class="gate-avatar-glow"></span>
<img class="gate-avatar-photo" src="/img/vanvan-portrait.png" alt="" />
</div>
<h2>VanVan</h2>
<form class="gate-form" data-role="vanvan">
<label class="sr-only" for="gate-code-vanvan">Zugangscode für VanVan</label>
<input type="text" id="gate-code-vanvan" placeholder="Zugangscode" autocomplete="off" autocapitalize="off" spellcheck="false" />
<button type="submit">💛 Öffnen</button>
</form>
<p class="gate-fehler" data-fehler-for="vanvan" role="alert" aria-live="assertive"></p>
</div>
</div>
<p class="gate-logo">🧶 Handgemacht mit Liebe</p>
</div>
<script>
(function () {
const params = new URLSearchParams(location.search);
const next = params.get("next") || "/";
// Ein gemeinsamer Handler für beide Fenster — /gate-auth erkennt die Rolle ohnehin selbst
// anhand des eingegebenen Codes, unabhängig davon, welches der beiden Fenster benutzt wurde.
document.querySelectorAll(".gate-form").forEach(function (form) {
const role = form.dataset.role;
const input = form.querySelector("input");
const fehlerEl = document.querySelector('[data-fehler-for="' + role + '"]');
form.addEventListener("submit", async function (e) {
e.preventDefault();
fehlerEl.classList.remove("zeige");
const code = input.value.trim();
if (!code) return;
try {
const res = await fetch("/gate-auth", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ code, next }),
});
const data = await res.json();
if (!res.ok || !data.ok) {
fehlerEl.textContent = (data && data.error) || "Falscher Zugangscode.";
fehlerEl.classList.add("zeige");
return;
}
location.href = data.next || "/";
} catch {
fehlerEl.textContent = "Verbindung fehlgeschlagen. Bitte nochmal versuchen.";
fehlerEl.classList.add("zeige");
}
});
});
})();
</script>
</body>
</html>