Files
vans-diy-bastelbedarf/public/verwaltung-code.html
T
qciganoandClaude Sonnet 5 b944bcf724 Barrierefreiheit (BFSG/WCAG 2.1 AA): Skip-Link, aria-live, Labels, Fokus-Sichtbarkeit, Überschriften-Hierarchie
Technisches Accessibility-Audit ergab sechs behebbare Punkte, alle jetzt gefixt:
- Skip-to-Content-Link ganz oben auf jeder Seite (WCAG 2.4.1)
- Fehler-/Statusmeldungen (Checkout, Login, Rezension, Gate-/Verwaltungs-Code) jetzt mit
  role="alert"/aria-live, damit Screenreader sie automatisch ansagen (WCAG 4.1.3)
- Warenkorb-Icon hatte fälschlich das "Konto"-Label geerbt, sagt jetzt korrekt "Warenkorb"
  (WCAG 4.1.2/2.4.4), dafür t.nav.cart in allen 4 Sprachen neu ergänzt
- Sichtbarer Fokus-Ring beim Mengenfeld auf der Produktseite wiederhergestellt (WCAG 2.4.7)
- Placeholder-only Formularfelder (Gate-Zugangscode, Verwaltungs-Suche/Filter/Tracking) haben
  jetzt echte Labels (sichtbar per sr-only-Klasse oder aria-label) statt nur Platzhaltertext
  (WCAG 1.3.1/3.3.2)
- Übersprungene Überschriften-Ebenen (h1→h3 ohne h2) in Checkout, Warenkorb, Kontakt, Konto
  korrigiert (WCAG 1.3.1)

Reine Accessibility-Nachrüstung, keine funktionale Änderung. Kleinstunternehmer-Ausnahme
(§3 Abs.3 BFSG) greift hier vermutlich, aber vorsorglich sauber umgesetzt.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-04 12:08:52 +02:00

187 lines
6.2 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Verwaltungs-Code — Bestellverwaltung</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: #e3b23c;
--c-accent-hover: #c99527;
--c-purple-glow: #9b7fd6;
--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;
}
.gate-box {
position: relative;
max-width: 430px;
width: 100%;
text-align: center;
padding: 2.4rem 2rem;
border-radius: var(--radius-l);
border: 1.5px solid transparent;
background:
linear-gradient(165deg, var(--c-anthracite-light), var(--c-anthracite)) padding-box,
linear-gradient(120deg, #e3b23c, #9b7fd6, #5fd3ec, #e3b23c) border-box;
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);
}
@keyframes gate-border-shift {
0%, 100% { background-position: 0 0, 0% 50%; }
50% { background-position: 0 0, 100% 50%; }
}
@media (prefers-reduced-motion: reduce) { .gate-box { animation: none; } }
.gate-box > * { position: relative; z-index: 1; }
.gate-eyebrow {
display: inline-block;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--c-accent);
background: color-mix(in srgb, var(--c-accent) 16%, transparent);
border: 1px solid color-mix(in srgb, var(--c-accent) 40%, transparent);
border-radius: 999px;
padding: 0.3rem 0.9rem;
margin-bottom: 1rem;
}
.gate-box h1 {
font-family: "Fraunces", "Playfair Display", Georgia, serif;
font-size: 1.5rem;
font-weight: 600;
margin: 0 0 0.6rem;
line-height: 1.2;
}
.gate-box p {
margin: 0 0 1.4rem;
color: var(--c-text-muted);
font-size: 0.94rem;
}
.gate-box input {
width: 100%;
padding: 0.9rem 1rem;
border-radius: 12px;
text-align: center;
letter-spacing: 0.08em;
font-size: 1.05rem;
margin-bottom: 0.9rem;
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-box 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-box button {
width: 100%;
padding: 0.85rem 1rem;
border-radius: 12px;
border: none;
background: linear-gradient(120deg, var(--c-accent), var(--c-accent-hover));
color: var(--c-black);
font-weight: 800;
font-size: 1rem;
cursor: pointer;
transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.gate-box button:hover { transform: translateY(-2px); box-shadow: 0 10px 24px -10px color-mix(in srgb, var(--c-accent) 60%, transparent); }
.gate-fehler {
color: #ff9a9a;
font-size: 0.88rem;
margin: 0.9rem 0 0;
display: none;
}
.gate-fehler.zeige { display: block; }
.gate-zurueck { display: inline-block; margin-top: 1.4rem; font-size: 0.85rem; color: var(--c-text-muted); }
.gate-zurueck a { color: inherit; }
</style>
</head>
<body>
<div class="gate-box">
<span class="gate-eyebrow">🔒 Zusätzlicher Code</span>
<h1>Bestellverwaltung</h1>
<p>Diese Seite ist zusätzlich mit einem eigenen, festen Code geschützt, den nur ihr beide
kennt. Der Code bleibt immer gleich — ihr müsst ihn aber einmal pro Tag neu eingeben.</p>
<form id="vw-form">
<label class="sr-only" for="vw-code">Verwaltungs-Code</label>
<input type="text" id="vw-code" placeholder="Verwaltungs-Code" autocomplete="off" autocapitalize="off" spellcheck="false" autofocus />
<button type="submit">Weiter</button>
</form>
<p class="gate-fehler" id="vw-fehler" role="alert" aria-live="assertive"></p>
<p class="gate-zurueck"><a href="/">← Zurück zur Startseite</a></p>
</div>
<script>
(function () {
const params = new URLSearchParams(location.search);
const next = params.get("next") || "/verwaltung/";
const form = document.getElementById("vw-form");
const fehlerEl = document.getElementById("vw-fehler");
form.addEventListener("submit", async function (e) {
e.preventDefault();
fehlerEl.classList.remove("zeige");
const code = document.getElementById("vw-code").value.trim();
if (!code) return;
try {
const res = await fetch("/verwaltung-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 Code.";
fehlerEl.classList.add("zeige");
return;
}
location.href = data.next || "/verwaltung/";
} catch {
fehlerEl.textContent = "Verbindung fehlgeschlagen. Bitte nochmal versuchen.";
fehlerEl.classList.add("zeige");
}
});
})();
</script>
</body>
</html>