Zum Inhalt
← Zugang & Robustheit

Seite „Barrierefreiheit“ als Vorlage

Vorlage für die Seite „Barrierefreiheit“: Stand auf einen Blick, bekannte Lücken mit Ausweg, Feedback-Formular und deutlich markierte Platzhalter für alles Rechtliche.

Öffentliche und öffentlich geförderte Auftraggeber, und für alle anderen als freiwilliger, bewährter Aufbau: Praxis, Verein, Kultur, Kanzlei.

Eine eigene Seite, im Footer verlinkt, die offen sagt, wie barrierefrei die Website ist: Stand der Vereinbarkeit (vollständig, teilweise, nicht), bekannte Einschränkungen mit Grund und Alternative, wie und wann geprüft wurde, ein Weg für Rückmeldungen mit kurzem Formular und Kontakt, Hinweis auf das Schlichtungsverfahren und das Datum der Erstellung. Oben eine Kurzfassung „Auf einen Blick“, daneben ein Inhaltsverzeichnis mit Sprungmarken. Gesetzt wie ein ruhiger Lesetext, nicht wie Kleingedrucktes. Die Vorlage folgt dem Aufbau der EU-Mustererklärung (Durchführungsbeschluss 2018/1523), den öffentliche Stellen nutzen; für Dienstleistungen nach BFSG heißt das Dokument „Informationen zur Barrierefreiheit“ und hat andere Pflichtteile (Anlage 3). Was davon für einen Kunden gilt, muss der Kunde rechtlich prüfen lassen.

Ehrlichkeit schafft Vertrauen: Wer Einschränkungen benennt und einen Ausweg anbietet, wirkt glaubwürdiger als ein pauschales „barrierefrei“. Menschen mit Behinderung finden schnell, was nicht geht und wen sie fragen können. Und die Seite zeigt, dass Barrierefreiheit ein laufendes Thema ist, kein Häkchen.

Wann einsetzen

Auf jeder Kundenseite als Footer-Link „Barrierefreiheit“, besonders bei Online-Terminbuchung, Shops, Buchungsstrecken und bei öffentlichen oder öffentlich geförderten Auftraggebern. Praxis, Kanzlei, Verein, Kultur, Hotel, Handwerk mit Online-Anfrage.

Wann nicht

Nie mit erfundenem Stand („vollständig barrierefrei“), der nicht geprüft ist. Nicht als Ersatz für echte Verbesserungen. Nicht ungeprüft veröffentlichen: Pflichtangaben, zuständige Stellen und Ausnahmen (z. B. für Kleinstunternehmen) hängen vom Einzelfall ab.

Varianten

  • Erklärung zur Barrierefreiheit im Aufbau der EU-Mustererklärung (öffentliche Stellen, freiwillig für alle anderen)
  • Informationen zur Barrierefreiheit nach BFSG Anlage 3 (Beschreibung der Dienstleistung, Ablauf, wie die Anforderungen erfüllt werden, Marktüberwachungsbehörde)
  • Mit Abschnitt „Barrierefreiheit vor Ort“ (Zugang, Aufzug, WC, Parkplatz) für Praxen, Hotels, Kultur
  • Mit Links zu Leichter Sprache und Gebärdensprache im Kopf

Umsetzung

Eigene Seite, im Footer überall an gleicher Stelle verlinkt (aria-current=page). Landmarken header, nav (Hauptmenü, Brotkrumen, „Auf dieser Seite“), main mit Sprunglink, footer. h1 „Erklärung zur Barrierefreiheit“ bzw. „Informationen zur Barrierefreiheit“. Kurzfassung als section mit dl (Stand, Geprüft nach, Methode, Gilt für) und einem Stufenbalken (aria-hidden, der Text sagt es). Lücken als Liste von Karten mit dl Warum / So geht es / Geplant. Daten mit <time datetime>. Abschnitte als <section aria-labelledby> mit data-abschnitt; das Inhaltsverzeichnis wird daraus gebaut, damit es zur Variante passt. Feedback: drei Wege (Telefon, E-Mail, Post) plus Formular mit nur einem Pflichtfeld; Antwortweg als Radiogruppe blendet das passende Feld ein; Fehler über eine Zusammenfassung mit Links (role=group, tabindex=-1, Fokus nach dem Absenden), am Feld aria-describedby und aria-invalid; nach dem Senden Fokus auf die Dankes-Überschrift und Statusmeldung. Alles Rechtliche als Platzhalter in eckigen Klammern mit Markierung und einem Vorlagen-Band oben, das vor dem Livegang entfernt wird. Variante BFSG ersetzt Geltung, Prüfung und Schlichtung durch Angebot, Ablauf, „Wie wir die Anforderungen erfüllen“ und zuständige Marktüberwachungsbehörde (Anlage 3).

Robust umsetzen

Telefon. Inhaltsverzeichnis als aufklappbares details oben statt fester Seitenleiste. Kurzfassung einspaltig. Telefon als tel:-Link groß. Formularfelder volle Breite, mindestens 16 px.

Ohne Bewegung. Weiches Scrollen zu Sprungmarken aus, Hinweise ohne Weg.

Barrierefrei. Die Seite selbst ist das Beispiel: WCAG 2.4.1 Sprunglink, 1.3.1 Überschriften, Listen, dl, fieldset/legend, 2.4.2 Seitentitel (mit „Fehler:“ bei offenen Fehlern), 2.4.5 Inhaltsverzeichnis plus Footer-Link, 2.4.7 und 2.4.11 sichtbarer Fokus, nicht verdeckt (scroll-margin, eigenes Scrollen mit 20 px Rand), 1.4.3 Kontraste ab 5,5 : 1 für Text, 1.4.11 Feldrahmen 3,7 : 1, 1.4.10 Umbruch bis 320 px, 3.1.5 einfache Sätze, 3.3.1 bis 3.3.3 Fehler benennen und Lösung sagen, 4.1.3 Statusmeldung nach dem Senden, 3.2.6 Hilfe (Kontaktwege) an gleicher Stelle. Barrierefreiheit vor Ort als eigener Abschnitt, weil Patienten oft das meinen.

Code

<!DOCTYPE html>
<!--
  Seite „Barrierefreiheit“ als Vorlage
  Fundus · Zugang & Robustheit · https://cecodesign.de/lab/fundus/zugang/barrierefreiheit-seite/
  Eigenständige Datei. Bilder liegen hier unter bilder/ – eigene einsetzen.
-->
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Erklärung zur Barrierefreiheit · Hausarztpraxis Wegwarte, Goslar</title>
<script>document.documentElement.classList.add('js');if(matchMedia('(prefers-reduced-motion: reduce)').matches)document.documentElement.classList.add('reduziert')</script>
<style>
@font-face { font-family: 'Hedvig Letters Serif'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/hedvig-letters-serif:vf@latest/latin-opsz-normal.woff2') format('woff2-variations'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Google Sans Flex'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/google-sans-flex:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 100 1000; font-display: swap; }
@font-face { font-family: 'Geist Mono'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/geist-mono:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 100 900; font-display: swap; }

:root {
  /* Rezept praxis-gesundheit-ruhig: gedecktes Petrol, warme Off-Whites, Grüngrau statt Schwarz, Apricot nur für Hinweise */
  --grund: #F5F7F7; --karte: #FFFFFF; --warm: #E2E0DE; --marke: #005450; --marke-zart: #E3EEED;
  --text: #363B3B; --leise: #596666; --linie: #D5DADA; --rahmen: #7C8787;   /* Feldrahmen 3,7 : 1 */
  --apricot: #FFC776; --hinweis: #FFF3DE; --hinweis-text: #6E4800;
  --fehler: #9E3A26; --fehler-zart: #FBEDE9; --gut: #1E6B3A;
  --kurve: cubic-bezier(0.2, 0, 0.38, 0.9);   /* Token tech-praezise */
  --ui: 200ms; --rein: 400ms;
  --fokus: 0 0 0 3px var(--grund), 0 0 0 6px var(--marke);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { background: var(--grund); color: var(--text); font: 400 17px/1.6 'Google Sans Flex', system-ui, sans-serif; font-variation-settings: 'ROND' 40; -webkit-font-smoothing: antialiased; scroll-padding-top: 24px; }
body { min-height: 100svh; }
button, input, textarea { font: inherit; color: inherit; }
a { color: var(--marke); text-decoration-thickness: 1.5px; text-underline-offset: .2em; }
a:focus-visible, button:focus-visible, summary:focus-visible { outline: none; box-shadow: var(--fokus); border-radius: 4px; }
:target { scroll-margin-top: 24px; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.mono { font: 500 11px/1.35 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; color: var(--leise); }
.serif { font-family: 'Hedvig Letters Serif', Georgia, serif; font-optical-sizing: auto; font-weight: 400; letter-spacing: -.01em; }
.platz { color: #363B3B; background: #FFE6B8; box-shadow: inset 0 -2px 0 #C98A1A; border-radius: 3px; padding: 0 .18em; -webkit-box-decoration-break: clone; box-decoration-break: clone; }

.sprung { position: absolute; left: 16px; top: -80px; z-index: 30; background: var(--marke); color: #fff; padding: 12px 18px; border-radius: 10px; font-weight: 600; text-decoration: none; }
.sprung:focus { top: 12px; outline: none; box-shadow: var(--fokus); }

/* Hinweis: Vorlage, Rechtliches prüfen lassen */
.vorlage { background: var(--apricot); color: #2B2F2F; }
.vorlage div { max-width: 1180px; margin: 0 auto; padding: 12px clamp(16px, 3vw, 32px); display: flex; gap: 14px; align-items: flex-start; font-size: 15px; line-height: 1.45; }
.vorlage b { font-weight: 650; }
.vorlage svg { flex: none; width: 22px; height: 22px; margin-top: 1px; }

/* Kopf */
.kopf { max-width: 1180px; margin: 0 auto; padding: 18px clamp(16px, 3vw, 32px); display: flex; align-items: center; gap: 28px; }
.marke { display: flex; align-items: center; gap: 12px; text-decoration: none; color: var(--text); }
.marke svg { width: 42px; height: 42px; flex: none; }
.marke b { display: block; font: 400 21px/1.1 'Hedvig Letters Serif', Georgia, serif; color: var(--marke); }
.marke small { display: block; font-size: 13.5px; color: var(--leise); }
.kopf nav ul { list-style: none; display: flex; gap: 22px; font-size: 15.5px; }
.kopf nav a { color: var(--text); text-decoration: none; }
.kopf nav a:hover { text-decoration: underline; }
.aktionen { margin-left: auto; display: flex; align-items: center; gap: 14px; }
.tel { font-weight: 600; text-decoration: none; color: var(--marke); white-space: nowrap; }
.knopf { display: inline-flex; align-items: center; gap: 8px; min-height: 48px; padding: 0 20px; border-radius: 999px; background: var(--marke); color: #fff; border: 0; font-weight: 600; font-size: 16px; text-decoration: none; cursor: pointer; transition: background-color var(--ui) var(--kurve); }
.knopf:hover { background: #00403D; }
.kopf-termin { gap: 0; white-space: pre; }

/* Inhalt */
.inhalt { max-width: 1180px; margin: 0 auto; padding: 8px clamp(16px, 3vw, 32px) 64px; outline: none; }
.krumen ol { list-style: none; display: flex; gap: 8px; font-size: 14.5px; color: var(--leise); padding: 6px 0 26px; }
.krumen li + li::before { content: '/'; margin-right: 8px; color: var(--rahmen); }
.raster { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: clamp(28px, 5vw, 72px); align-items: start; }

/* Inhaltsverzeichnis */
.toc { position: sticky; top: 24px; }
.toc summary { display: none; }
.toc h2 { margin-bottom: 12px; }
.toc ol { list-style: none; border-left: 2px solid var(--linie); }
.toc a { display: block; padding: 7px 0 7px 16px; margin-left: -2px; border-left: 2px solid transparent; color: var(--leise); text-decoration: none; font-size: 15.5px; line-height: 1.35; transition: color var(--ui) var(--kurve), border-color var(--ui) var(--kurve); }
.toc a:hover { color: var(--text); }
.toc a[aria-current="true"], .toc a.gedrueckt { color: var(--marke); border-left-color: var(--marke); font-weight: 600; }

article { max-width: 66ch; }
article > header h1 { font-size: clamp(2.25rem, 1.4rem + 3.2vw, 4.25rem); line-height: 1.06; color: var(--marke); text-wrap: balance; }
.lead { font-size: 19.5px; line-height: 1.55; margin-top: 18px; max-width: 58ch; text-wrap: pretty; }
.stand-zeile { margin-top: 14px; font-size: 15px; color: var(--leise); }

.blick { margin: 34px 0 10px; background: var(--karte); border-radius: 20px; padding: 26px 28px; box-shadow: 0 1px 0 rgba(0, 84, 80, .06), 0 18px 40px -28px rgba(0, 60, 58, .35); }
.blick h2 { font-size: 15px; font-family: 'Geist Mono', monospace; font-weight: 500; letter-spacing: .14em; text-transform: uppercase; color: var(--leise); margin-bottom: 16px; }
.ampel { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-bottom: 8px; }
.ampel span { height: 8px; border-radius: 4px; background: var(--warm); transition: background-color var(--rein) var(--kurve); }
.ampel[data-stufe="1"] span:nth-child(-n+1), .ampel[data-stufe="2"] span:nth-child(-n+2), .ampel[data-stufe="3"] span { background: var(--marke); }
.ampel-text { display: flex; justify-content: space-between; font-size: 13px; color: var(--leise); margin-bottom: 18px; }
.blick dl { display: grid; grid-template-columns: max-content 1fr; gap: 10px 26px; font-size: 16px; }
.blick dt { color: var(--leise); }
.blick dd { font-weight: 500; }
.blick dd.stand { font: 400 24px/1.2 'Hedvig Letters Serif', Georgia, serif; color: var(--marke); }

article section { padding-top: 44px; scroll-margin-top: 16px; }
article section > h2 { font-size: clamp(1.75rem, 1.3rem + 1.6vw, 2.5rem); line-height: 1.12; color: var(--text); margin-bottom: 14px; text-wrap: balance; }
article section > p, article section > ul:not(.luecken):not(.vorort) { max-width: 62ch; margin-bottom: 14px; text-wrap: pretty; }
article section > ul { padding-left: 1.2em; }

.luecken { list-style: none; padding-left: 0 !important; display: grid; gap: 14px; margin-top: 18px; }
.luecken li { background: var(--karte); border-radius: 16px; padding: 20px 22px; border: 1px solid var(--linie); }
.luecken h3 { font-size: 19px; font-weight: 600; margin-bottom: 8px; line-height: 1.3; }
.luecken dl { display: grid; grid-template-columns: 7.5em 1fr; gap: 6px 16px; font-size: 16px; }
.luecken dt { color: var(--leise); }
.marke-badge { display: inline-block; font: 500 10.5px/1 'Geist Mono', monospace; letter-spacing: .1em; text-transform: uppercase; padding: 5px 8px; border-radius: 999px; background: var(--hinweis); color: var(--hinweis-text); margin-left: 8px; vertical-align: 3px; }

.vorort { list-style: none; padding-left: 0 !important; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 14px; }
.vorort li { display: grid; grid-template-columns: 34px 1fr; gap: 12px; align-items: start; background: var(--marke-zart); border-radius: 14px; padding: 14px 16px; font-size: 16px; line-height: 1.45; }
.vorort svg { width: 34px; height: 34px; }

.rechtlich { margin-top: 10px; background: var(--hinweis); border: 1.5px dashed #C98A1A; border-radius: 16px; padding: 18px 20px; }
.rechtlich p { max-width: 62ch; }
.rechtlich p + p { margin-top: 10px; }
.rechtlich .mono { color: var(--hinweis-text); margin-bottom: 8px; }

/* Feedback */
.wege { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin: 18px 0 26px; }
.wege a, .wege div { display: grid; gap: 2px; background: var(--karte); border: 1px solid var(--linie); border-radius: 14px; padding: 14px 16px; text-decoration: none; color: var(--text); font-size: 15.5px; }
.wege b { font-weight: 600; color: var(--marke); font-size: 16.5px; }
.formular { background: var(--karte); border-radius: 20px; padding: clamp(20px, 3vw, 32px); }
.formular h3 { font: 400 26px/1.2 'Hedvig Letters Serif', Georgia, serif; color: var(--marke); margin-bottom: 6px; }
.formular > p { color: var(--leise); font-size: 16px; margin-bottom: 20px; }
.feld { border: 0; min-width: 0; margin-bottom: 20px; scroll-margin-top: 24px; }
.feld > label, .feld > legend { display: block; font-weight: 600; margin-bottom: 4px; }
.feld .frei { font-weight: 400; color: var(--leise); }
.hilfe { font-size: 15px; color: var(--leise); margin-bottom: 8px; }
.feld input[type="text"], .feld input[type="email"], .feld input[type="tel"], .feld textarea { width: 100%; min-height: 52px; padding: 12px 14px; font-size: 17px; border: 1.5px solid var(--rahmen); border-radius: 12px; background: var(--karte); outline: none; transition: border-color var(--ui) var(--kurve), box-shadow var(--ui) var(--kurve); }
.feld textarea { min-height: 130px; resize: vertical; line-height: 1.5; }
.feld input:focus-visible, .feld textarea:focus-visible, .feld .fokus-sim { border-color: var(--marke); box-shadow: 0 0 0 3px var(--marke-zart), 0 0 0 4.5px var(--marke); }
.feld input[aria-invalid="true"], .feld textarea[aria-invalid="true"] { border-color: var(--fehler); border-width: 2px; background: var(--fehler-zart); }
.wahl { display: flex; flex-wrap: wrap; gap: 8px; }
.wahl label { display: inline-flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 16px; border: 1.5px solid var(--rahmen); border-radius: 999px; cursor: pointer; transition: border-color var(--ui) var(--kurve), background-color var(--ui) var(--kurve); }
.wahl input { width: 20px; height: 20px; accent-color: var(--marke); }
.wahl label:has(input:checked) { border-color: var(--marke); background: var(--marke-zart); }
.wahl label:has(input:focus-visible), .wahl label.fokus-sim { box-shadow: var(--fokus); }
.fehler { display: flex; gap: 8px; color: var(--fehler); font-weight: 600; font-size: 15.5px; margin-top: 6px; }
.fehler:empty { display: none; }
.fehler::before { content: '!'; flex: none; width: 19px; height: 19px; margin-top: 2px; border-radius: 50%; background: var(--fehler); color: #fff; font: 700 12px/19px system-ui, sans-serif; text-align: center; }
.zusatz[hidden] { display: none; }
.zf { border: 2px solid var(--fehler); background: var(--fehler-zart); border-radius: 14px; padding: 16px 18px; margin-bottom: 22px; outline: none; }
.zf:focus, .zf.fokus-sim { box-shadow: var(--fokus); }
.zf h4 { font-size: 17.5px; margin-bottom: 6px; }
.zf ul { padding-left: 1.2em; }
.zf a { color: var(--fehler); font-weight: 600; }
.datenschutz { font-size: 15px; color: var(--leise); margin: 4px 0 18px; max-width: 60ch; }
.danke { display: none; gap: 10px; border-left: 4px solid var(--gut); background: #E8F3EC; border-radius: 6px 16px 16px 6px; padding: 18px 20px; }
.formular.gesendet form { display: none; }
.formular.gesendet .danke { display: grid; animation: rein var(--rein) var(--kurve) both; }
.danke h4 { font: 400 24px/1.2 'Hedvig Letters Serif', Georgia, serif; color: var(--gut); outline: none; }
@keyframes rein { from { opacity: 0; translate: 0 8px; } }
.knopf.gedrueckt { background: #00403D; }

/* Fuß */
.fuss { background: var(--marke); color: #EAF2F1; }
.fuss > div { max-width: 1180px; margin: 0 auto; padding: 40px clamp(16px, 3vw, 32px); display: grid; grid-template-columns: 1.2fr 1fr 1fr; gap: 28px; font-size: 15.5px; }
.fuss h2 { font: 400 20px/1.2 'Hedvig Letters Serif', Georgia, serif; color: #fff; margin-bottom: 8px; }
.fuss a { color: #fff; }
.fuss ul { list-style: none; display: grid; gap: 4px; }
.fuss .notfall { background: rgba(255, 255, 255, .1); border-radius: 12px; padding: 12px 14px; }
.fuss a:focus-visible { box-shadow: 0 0 0 3px var(--marke), 0 0 0 6px #fff; }

/* Pult der Demo */
.pult { position: fixed; right: 16px; bottom: 16px; z-index: 40; display: grid; gap: 10px; padding: 12px 14px; background: rgba(23, 33, 33, .92); color: #EAF2F1; border-radius: 14px; box-shadow: 0 12px 30px rgba(0, 0, 0, .25); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.pult .mono { color: rgba(234, 242, 241, .7); font-size: 10px; }
.pult div[role="group"] { display: flex; gap: 2px; background: rgba(255, 255, 255, .08); border-radius: 9px; padding: 3px; margin-top: 4px; }
.pult button { border: 0; background: none; color: rgba(234, 242, 241, .78); border-radius: 7px; padding: 7px 10px; cursor: pointer; font: 500 10.5px/1 'Geist Mono', monospace; letter-spacing: .1em; text-transform: uppercase; }
.pult button[aria-pressed="true"] { background: #EAF2F1; color: #172121; }
.pult button:focus-visible { box-shadow: 0 0 0 2px #FFC776; }

@media (min-width: 1100px) { .pult { right: auto; left: 16px; } }   /* links neben dem Inhalt, unter dem Inhaltsverzeichnis */

/* Variante BFSG / Erklärung */
[data-nur][hidden] { display: none; }

/* Reduzierte Bewegung */
.reduziert { scroll-behavior: auto; }
.reduziert .formular.gesendet .danke { animation: none; }
.reduziert .ampel span, .reduziert .toc a, .reduziert .knopf { transition: none; }

@media (hover: none) {
  .kopf nav a:hover { text-decoration: none; }
  .knopf:hover { background: var(--marke); }
}
@media (max-width: 900px) {
  /* Navigation bleibt erreichbar: eigene Zeile unter Marke und Termin-Knopf */
  .kopf { flex-wrap: wrap; row-gap: 4px; }
  .kopf > .marke { flex: 1 1 0; min-width: 0; }
  .kopf nav { order: 3; flex-basis: 100%; }
  .kopf nav ul { flex-wrap: wrap; gap: 0 18px; }
  .kopf nav a { display: inline-flex; align-items: center; min-height: 44px; }
  .raster { grid-template-columns: minmax(0, 1fr); }
  .toc { position: static; background: var(--karte); border-radius: 14px; padding: 4px 16px; }
  .toc summary { display: flex; justify-content: space-between; align-items: center; min-height: 48px; cursor: pointer; font-weight: 600; list-style: none; }
  .toc summary::-webkit-details-marker { display: none; }
  .toc summary::after { content: '+'; font-size: 22px; color: var(--marke); }
  .toc details[open] summary::after { content: '−'; }
  .toc h2 { display: none; }
  .toc ol { margin-bottom: 12px; }
  .fuss > div { grid-template-columns: 1fr; }
  .wege { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .tel { display: none; }
  .knopf .lang { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .marke small { display: none; }
  .knopf { min-height: 44px; padding: 0 16px; font-size: 15px; }
  .kopf { gap: 12px; }
  .vorort { grid-template-columns: 1fr; }
  .luecken dl, .blick dl { grid-template-columns: 1fr; gap: 0 0; }
  .luecken dd, .blick dd { margin-bottom: 8px; }
  .lead { font-size: 18px; }
}

/* Vorschau 960 × 720: nur die Bühne */
.vorschau body { overflow: hidden; }
.vorschau .kopf nav, .vorschau .krumen, .vorschau .tel { display: none; }
.vorschau .raster { grid-template-columns: 220px minmax(0, 1fr); gap: 40px; }
.vorschau .toc { position: sticky; background: none; padding: 0; }
.vorschau .toc summary { display: none; }
.vorschau .toc h2 { display: block; }
.vorschau .inhalt { padding-top: 22px; }

/* Windows-Kontrastmodus: Platzhalter bleiben als gerahmte Stellen erkennbar, Knöpfe behalten eine Kante */
@media (forced-colors: active) {
  .platz { border: 1px dashed CanvasText; }
  .knopf, .formular button { border: 1px solid ButtonText; }
}
</style>
</head>
<body>
<a class="sprung" href="#inhalt">Zum Inhalt springen</a>

<div class="vorlage" role="note" aria-label="Hinweis zur Vorlage">
  <div>
    <svg viewBox="0 0 22 22" aria-hidden="true"><path d="M11 2 21 19H1z" fill="#2B2F2F"/><path d="M11 8v5.5M11 16v.6" stroke="#FFC776" stroke-width="2.2" stroke-linecap="round"/></svg>
    <p><b>Vorlage, nicht ungeprüft veröffentlichen.</b> Alles <span class="platz">[so markiert]</span> ist ein Platzhalter. Bezeichnung, Pflichtangaben, zuständige Stellen und ob das BFSG überhaupt gilt (für Kleinstunternehmen, die Dienstleistungen anbieten, gibt es Ausnahmen), muss der Kunde rechtlich prüfen lassen.</p>
  </div>
</div>

<header class="kopf">
  <a class="marke" href="#" aria-label="Hausarztpraxis Wegwarte, Startseite">
    <svg viewBox="0 0 42 42" aria-hidden="true">
      <g fill="#005450">
        <g id="blatt"><path d="M21 21c-2-5-2.2-11 0-16 2.2 5 2 11 0 16z"/></g>
        <use href="#blatt" transform="rotate(45 21 21)"/><use href="#blatt" transform="rotate(90 21 21)"/><use href="#blatt" transform="rotate(135 21 21)"/>
        <use href="#blatt" transform="rotate(180 21 21)"/><use href="#blatt" transform="rotate(225 21 21)"/><use href="#blatt" transform="rotate(270 21 21)"/><use href="#blatt" transform="rotate(315 21 21)"/>
      </g>
      <circle cx="21" cy="21" r="4" fill="#FFC776"/>
    </svg>
    <span><b>Hausarztpraxis Wegwarte</b><small>Dr. Ilka Sommerfeld · Dr. Jonas Behrendt · Goslar</small></span>
  </a>
  <nav aria-label="Hauptmenü"><ul><li><a href="#">Praxis</a></li><li><a href="#">Sprechzeiten</a></li><li><a href="#">Leistungen</a></li><li><a href="#">Team</a></li><li><a href="#">Anfahrt</a></li></ul></nav>
  <div class="aktionen">
    <a class="tel" href="#">Tel. <span class="platz">[05321 …]</span></a>
    <a class="knopf kopf-termin" href="#">Termin <span class="lang">vereinbaren</span></a>
  </div>
</header>

<main class="inhalt" id="inhalt" tabindex="-1">
  <nav class="krumen" aria-label="Brotkrumen"><ol><li><a href="#">Startseite</a></li><li><span aria-current="page">Barrierefreiheit</span></li></ol></nav>

  <div class="raster">
    <nav class="toc" aria-labelledby="toc-titel">
      <details open data-toc>
        <summary>Auf dieser Seite</summary>
        <h2 class="mono" id="toc-titel">Auf dieser Seite</h2>
        <ol data-toc-liste></ol>
      </details>
    </nav>

    <article>
      <header>
        <p class="mono" data-nur="erklaerung">Erklärung nach EU-Mustererklärung</p>
        <p class="mono" data-nur="bfsg" hidden>Informationen nach BFSG, Anlage 3</p>
        <h1 class="serif" data-titel>Erklärung zur Barrierefreiheit</h1>
        <p class="lead">Wir möchten, dass alle Menschen unsere Website nutzen können: um Sprechzeiten nachzulesen, einen Termin zu buchen oder uns zu schreiben. Hier steht, wie weit wir sind, was noch nicht klappt und wie Sie uns Bescheid geben.</p>
        <p class="stand-zeile">Erstellt am <time datetime="2026-11-02" class="platz">[2. November 2026]</time> · zuletzt geprüft <time datetime="2026-11-02" class="platz">[2. November 2026]</time></p>
      </header>

      <section class="blick" id="auf-einen-blick" aria-labelledby="blick-titel" data-abschnitt="Auf einen Blick">
        <h2 id="blick-titel">Auf einen Blick</h2>
        <div class="ampel" data-ampel data-stufe="2" aria-hidden="true"><span></span><span></span><span></span></div>
        <div class="ampel-text" aria-hidden="true"><span>nicht</span><span>teilweise</span><span>vollständig</span></div>
        <dl>
          <dt>Stand</dt><dd class="stand" data-stand-kurz>Teilweise barrierefrei</dd>
          <dt>Geprüft nach</dt><dd><span class="platz">[WCAG 2.2, Stufe AA; EN 301 549]</span></dd>
          <dt>Methode</dt><dd>Selbstbewertung mit Tastatur, Screenreader und 200 % Zoom <span class="platz">[ggf. Prüfstelle nennen]</span></dd>
          <dt>Gilt für</dt><dd><span class="platz">[www.praxis-wegwarte.de]</span> mit Online-Terminbuchung</dd>
        </dl>
      </section>

      <!-- Variante Erklärung (Aufbau EU 2018/1523) -->
      <section id="geltung" aria-labelledby="h-geltung" data-nur="erklaerung" data-abschnitt="Wofür sie gilt">
        <h2 class="serif" id="h-geltung">Wofür diese Erklärung gilt</h2>
        <p>Sie gilt für unsere Website <span class="platz">[www.praxis-wegwarte.de]</span>. Für die Terminbuchung nutzen wir einen externen Kalender von <span class="platz">[Anbieter]</span>. Für dessen Barrierefreiheit ist der Anbieter verantwortlich; wir haben ihn auf Mängel hingewiesen.</p>
      </section>

      <!-- Variante BFSG (Anlage 3) -->
      <section id="angebot" aria-labelledby="h-angebot" data-nur="bfsg" hidden data-abschnitt="Unser Angebot">
        <h2 class="serif" id="h-angebot">Unser Angebot</h2>
        <p>Über diese Website können Sie Termine in unserer Hausarztpraxis buchen, verschieben und absagen sowie Rezepte und Überweisungen anfragen. <span class="platz">[Allgemeine Beschreibung der Dienstleistung, Anlage 3 Nr. 1 a]</span></p>
      </section>
      <section id="ablauf" aria-labelledby="h-ablauf" data-nur="bfsg" hidden data-abschnitt="So läuft es ab">
        <h2 class="serif" id="h-ablauf">So läuft die Buchung ab</h2>
        <p>Sie wählen den Grund des Besuchs, dann einen freien Termin, und geben Name, Geburtsdatum und Telefonnummer ein. Sie bekommen eine Bestätigung per E-Mail oder SMS. Absagen geht über den Link in der Bestätigung oder telefonisch. <span class="platz">[Erläuterungen zur Durchführung, Anlage 3 Nr. 1 b]</span></p>
      </section>

      <section id="stand" aria-labelledby="h-stand" data-abschnitt="Stand der Vereinbarkeit">
        <h2 class="serif" id="h-stand" data-h-stand>Stand der Vereinbarkeit</h2>
        <p data-stand-satz>Diese Website ist <strong>teilweise</strong> mit <span class="platz">[WCAG 2.2, Stufe AA]</span> vereinbar. Die folgenden Inhalte sind noch nicht barrierefrei.</p>
        <ul class="luecken" data-luecken>
          <li>
            <h3>Ältere Merkblätter als PDF <span class="marke-badge">in Arbeit</span></h3>
            <dl><dt>Warum</dt><dd>Drei Merkblätter zur Impfung sind eingescannt und haben keine Textebene.</dd>
            <dt>So geht es</dt><dd>Wir schicken Ihnen den Inhalt als Text oder erklären ihn am Telefon.</dd>
            <dt>Geplant</dt><dd>Ersetzt bis <span class="platz">[März 2027]</span></dd></dl>
          </li>
          <li>
            <h3>Kalender der Online-Terminbuchung <span class="marke-badge">Anbieter</span></h3>
            <dl><dt>Warum</dt><dd>Freie Termine lassen sich nicht ganz mit der Tastatur auswählen, ein Screenreader liest die Uhrzeiten nicht vor.</dd>
            <dt>So geht es</dt><dd>Termine auch telefonisch oder per E-Mail, gleiche Zeiten, gleiche Wartezeit.</dd>
            <dt>Geplant</dt><dd>Anbieter informiert, Stand <span class="platz">[offen]</span></dd></dl>
          </li>
          <li>
            <h3>Eingebettete Anfahrtskarte</h3>
            <dl><dt>Warum</dt><dd>Die Karte ist für Screenreader nicht nutzbar.</dd>
            <dt>So geht es</dt><dd>Die Wegbeschreibung steht als Text unter „Anfahrt“, mit Haltestelle und Parkplätzen.</dd>
            <dt>Geplant</dt><dd>Bleibt als Ergänzung, der Text ist die Hauptinformation.</dd></dl>
          </li>
        </ul>
      </section>

      <section id="vor-ort" aria-labelledby="h-vor-ort" data-abschnitt="In der Praxis">
        <h2 class="serif" id="h-vor-ort">Barrierefreiheit in der Praxis</h2>
        <p>Das gehört nicht zur Website, aber oft zur Frage dahinter.</p>
        <ul class="vorort">
          <li><svg viewBox="0 0 34 34" aria-hidden="true"><rect width="34" height="34" rx="10" fill="#fff"/><path d="M8 25h18M10 25l12-9h4" stroke="#005450" stroke-width="2.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg><span>Stufenloser Zugang über die Rampe am Hofeingang</span></li>
          <li><svg viewBox="0 0 34 34" aria-hidden="true"><rect width="34" height="34" rx="10" fill="#fff"/><rect x="11" y="8" width="12" height="18" rx="2" stroke="#005450" stroke-width="2.2" fill="none"/><path d="m14 15 3-3 3 3M14 19l3 3 3-3" stroke="#005450" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg><span>Aufzug ins 1. OG, Türbreite 90 cm</span></li>
          <li><svg viewBox="0 0 34 34" aria-hidden="true"><rect width="34" height="34" rx="10" fill="#fff"/><path d="M12 11a6 6 0 0 1 11 3c0 4-4 4-4 8a3 3 0 0 1-5 2" stroke="#005450" stroke-width="2.2" fill="none" stroke-linecap="round"/><path d="M8 26l5-5" stroke="#005450" stroke-width="2.2" stroke-linecap="round"/></svg><span>Induktionsschleife am Empfang</span></li>
          <li><svg viewBox="0 0 34 34" aria-hidden="true"><rect width="34" height="34" rx="10" fill="#fff"/><circle cx="17" cy="17" r="8" stroke="#005450" stroke-width="2.2" fill="none"/><path d="M17 12v5l3 2" stroke="#005450" stroke-width="2.2" fill="none" stroke-linecap="round"/></svg><span>Ruhige Termine ohne Wartezimmer auf Nachfrage</span></li>
        </ul>
      </section>

      <section id="pruefung" aria-labelledby="h-pruefung" data-nur="erklaerung" data-abschnitt="Wie wir geprüft haben">
        <h2 class="serif" id="h-pruefung">Wie wir geprüft haben</h2>
        <p>Die Erklärung beruht auf einer Selbstbewertung vom <time datetime="2026-11-02" class="platz">[2. November 2026]</time>. Geprüft haben wir mit Tastatur, mit den Screenreadern NVDA und VoiceOver, bei 200 % Zoom, mit erhöhten Textabständen und mit einem automatischen Prüfwerkzeug. <span class="platz">[Falls zutreffend: zusätzlich geprüft durch … am …]</span></p>
      </section>

      <section id="melden" aria-labelledby="h-melden" data-abschnitt="Barriere melden">
        <h2 class="serif" id="h-melden">Barriere melden</h2>
        <p>Ist Ihnen etwas aufgefallen, das nicht funktioniert? Oder brauchen Sie einen Inhalt in anderer Form? Schreiben Sie uns, rufen Sie an oder kommen Sie vorbei. Wir antworten innerhalb von <span class="platz">[zwei Wochen]</span>.</p>
        <div class="wege">
          <a href="#"><span>Telefon</span><b class="platz">[05321 …]</b></a>
          <a href="#"><span>E-Mail</span><b class="platz">[barrierefrei@…]</b></a>
          <div><span>Post</span><b>Praxis Wegwarte</b><span class="platz">[Straße, 38640 Goslar]</span></div>
        </div>

        <div class="formular" data-formular>
          <h3 id="form-titel">Oder hier kurz beschreiben</h3>
          <p>Nur die Beschreibung ist Pflicht. Der Rest hilft uns, Ihnen zu antworten.</p>
          <form novalidate data-form aria-labelledby="form-titel">
            <div class="zf" role="group" tabindex="-1" aria-labelledby="zf-titel" hidden data-zf>
              <h4 id="zf-titel" data-zf-titel>Bitte prüfen Sie zwei Angaben</h4>
              <ul data-zf-liste></ul>
            </div>
            <div class="feld" data-feld="was">
              <label for="f-was">Was hat nicht funktioniert?</label>
              <p class="hilfe" id="f-was-hilfe">Zum Beispiel: „Im Kalender kann ich mit der Tastatur keine Uhrzeit wählen.“</p>
              <textarea id="f-was" name="was" required aria-describedby="f-was-hilfe f-was-fehler" aria-invalid="false"></textarea>
              <p class="fehler" id="f-was-fehler"></p>
            </div>
            <div class="feld" data-feld="wo">
              <label for="f-wo">Wo war das? <span class="frei">(freiwillig)</span></label>
              <input id="f-wo" name="wo" type="text" placeholder="z. B. Terminbuchung" aria-describedby="f-wo-fehler">
              <p class="fehler" id="f-wo-fehler"></p>
            </div>
            <fieldset class="feld" data-feld="antwort" aria-describedby="f-antwort-fehler">
              <legend>Wie dürfen wir antworten?</legend>
              <div class="wahl">
                <label><input type="radio" name="antwort" value="mail" id="f-antwort-1" checked>Per E-Mail</label>
                <label><input type="radio" name="antwort" value="tel">Per Telefon</label>
                <label><input type="radio" name="antwort" value="keine">Keine Antwort nötig</label>
              </div>
              <p class="fehler" id="f-antwort-fehler"></p>
            </fieldset>
            <div class="feld zusatz" data-feld="mail" data-zusatz="mail">
              <label for="f-mail">Ihre E-Mail-Adresse</label>
              <input id="f-mail" name="mail" type="email" autocomplete="email" spellcheck="false" aria-describedby="f-mail-fehler" aria-invalid="false">
              <p class="fehler" id="f-mail-fehler"></p>
            </div>
            <div class="feld zusatz" data-feld="tel" data-zusatz="tel" hidden>
              <label for="f-tel">Ihre Telefonnummer</label>
              <input id="f-tel" name="tel" type="tel" autocomplete="tel" aria-describedby="f-tel-fehler" aria-invalid="false">
              <p class="fehler" id="f-tel-fehler"></p>
            </div>
            <div class="feld" data-feld="name">
              <label for="f-name">Ihr Name <span class="frei">(freiwillig)</span></label>
              <input id="f-name" name="name" type="text" autocomplete="name">
            </div>
            <p class="datenschutz">Wir nutzen Ihre Angaben nur, um Ihre Meldung zu bearbeiten, und löschen sie danach. Mehr in der <a href="#">Datenschutzerklärung</a>.</p>
            <button class="knopf" type="submit" data-senden>Meldung senden</button>
            <p class="sr" role="status" data-status></p>
          </form>
          <div class="danke">
            <h4 tabindex="-1" data-danke-titel>Danke, Ihre Meldung ist angekommen.</h4>
            <p data-danke-text>Wir melden uns innerhalb von <span class="platz">[zwei Wochen]</span>. Ihre Vorgangsnummer: <b>BF-2611-07</b>.</p>
          </div>
        </div>
      </section>

      <section id="schlichtung" aria-labelledby="h-schlichtung" data-nur="erklaerung" data-abschnitt="Schlichtungsverfahren">
        <h2 class="serif" id="h-schlichtung">Schlichtungsverfahren</h2>
        <div class="rechtlich">
          <p class="mono">Platzhalter · vom Kunden prüfen lassen</p>
          <p>Wenn Sie mit unserer Antwort nicht zufrieden sind, können Sie sich an eine Schlichtungsstelle wenden. Das Verfahren ist kostenlos, Sie brauchen keinen Anwalt.</p>
          <p><span class="platz">[Zuständige Stelle, z. B. Schlichtungsstelle nach § 16 BGG; Anschrift, Telefon, E-Mail, Website. Ob und welche Stelle zuständig ist, klärt der Kunde.]</span></p>
        </div>
      </section>

      <section id="behoerde" aria-labelledby="h-behoerde" data-nur="bfsg" hidden data-abschnitt="Zuständige Behörde">
        <h2 class="serif" id="h-behoerde">Zuständige Marktüberwachungsbehörde</h2>
        <div class="rechtlich">
          <p class="mono">Platzhalter · vom Kunden prüfen lassen</p>
          <p>Wenn Sie meinen, dass unser Angebot die Anforderungen nicht erfüllt, können Sie sich an die zuständige Marktüberwachungsbehörde wenden.</p>
          <p><span class="platz">[Marktüberwachungsstelle der Länder für die Barrierefreiheit von Produkten und Dienstleistungen; Anschrift und Kontakt aktuell prüfen. Hinweis auf Schlichtung nach § 34 BFSG optional.]</span></p>
        </div>
      </section>
    </article>
  </div>
</main>

<footer class="fuss">
  <div>
    <section aria-labelledby="f-praxis"><h2 id="f-praxis">Hausarztpraxis Wegwarte</h2><p><span class="platz">[Straße Hausnummer]</span><br>38640 Goslar<br>Tel. <span class="platz">[05321 …]</span></p></section>
    <section aria-labelledby="f-zeiten"><h2 id="f-zeiten">Sprechzeiten</h2><p>Mo bis Fr 8 bis 12 Uhr<br>Mo, Di, Do 15 bis 18 Uhr</p></section>
    <section aria-labelledby="f-hilfe"><h2 id="f-hilfe">Außerhalb der Sprechzeiten</h2><p class="notfall">Ärztlicher Bereitschaftsdienst <a href="tel:116117">116 117</a><br>Notfall <a href="tel:112">112</a></p>
      <ul style="margin-top:14px"><li><a href="#">Impressum</a></li><li><a href="#">Datenschutz</a></li><li><a href="#" aria-current="page">Barrierefreiheit</a></li></ul></section>
  </div>
</footer>

<div class="pult" role="group" aria-label="Demo-Steuerung">
  <div><span class="mono" id="p-v">Vorlage</span>
    <div role="group" aria-labelledby="p-v"><button type="button" data-v="erklaerung" aria-pressed="true">Erklärung</button><button type="button" data-v="bfsg" aria-pressed="false">BFSG</button></div></div>
  <div><span class="mono" id="p-s">Stand</span>
    <div role="group" aria-labelledby="p-s"><button type="button" data-s="3" aria-pressed="false">vollständig</button><button type="button" data-s="2" aria-pressed="true">teilweise</button><button type="button" data-s="1" aria-pressed="false">nicht</button></div></div>
</div>

<script>
(() => {
  const html = document.documentElement;
  const reduziert = () => html.classList.contains('reduziert');
  const $ = (s, r = document) => r.querySelector(s), $$ = (s, r = document) => [...r.querySelectorAll(s)];
  const TITEL = document.title;

  // ---------- Inhaltsverzeichnis aus den sichtbaren Abschnitten ----------
  const tocListe = $('[data-toc-liste]'), toc = $('[data-toc]');
  let beobachter;
  function baueToc() {
    const abschnitte = $$('article section[data-abschnitt]').filter(s => !s.hidden);
    tocListe.innerHTML = abschnitte.map(s => `<li><a href="#${s.id}">${s.dataset.abschnitt}</a></li>`).join('');
    beobachter?.disconnect();
    beobachter = new IntersectionObserver(eintraege => {
      eintraege.forEach(e => { if (e.isIntersecting) markiere(e.target.id); });
    }, { rootMargin: '-20% 0px -70% 0px' });
    abschnitte.forEach(s => beobachter.observe(s));
  }
  function markiere(id) { $$('a', tocListe).forEach(a => a.setAttribute('aria-current', String(a.getAttribute('href') === '#' + id))); }
  // Nur das eigene Fenster scrollen
  function rolle(el) { window.scrollTo({ top: Math.max(0, el.getBoundingClientRect().top + scrollY - 20), behavior: reduziert() ? 'auto' : 'smooth' }); }
  function fokussiere(el) {
    $$('.fokus-sim').forEach(x => x.classList.remove('fokus-sim'));
    if (html.classList.contains('vorfuehrung')) el.classList.add('fokus-sim'); else el.focus({ preventScroll: true });
  }
  tocListe.addEventListener('click', e => {
    const a = e.target.closest('a'); if (!a) return;
    e.preventDefault();
    const ziel = document.getElementById(a.getAttribute('href').slice(1));
    rolle(ziel);
    const h = ziel.querySelector('h2'); h.tabIndex = -1; fokussiere(h);
    if (matchMedia('(max-width: 900px)').matches) toc.open = false;
  });
  const schmal = matchMedia('(max-width: 900px)');
  function tocModus() { toc.open = !schmal.matches || html.classList.contains('vorschau'); }
  schmal.addEventListener('change', tocModus);
  $('.sprung').addEventListener('click', e => { e.preventDefault(); rolle($('#inhalt')); $('#inhalt').focus({ preventScroll: true }); });

  // ---------- Feedback-Formular mit Fehlerzusammenfassung ----------
  const form = $('[data-form]'), zf = $('[data-zf]'), karte = $('[data-formular]'), status = $('[data-status]');
  const zusatz = { mail: $('[data-zusatz="mail"]'), tel: $('[data-zusatz="tel"]') };
  const antwort = () => form.antwort.value;
  const REGELN = {
    was: { label: 'Beschreibung', pruefe: () => form.was.value.trim().length >= 10 ? '' : (form.was.value.trim() ? 'Beschreiben Sie das Problem bitte in ein, zwei Sätzen.' : 'Beschreiben Sie kurz, was nicht funktioniert hat.') },
    mail: { label: 'E-Mail-Adresse', aktiv: () => antwort() === 'mail', pruefe: () => { const v = form.mail.value.trim(); if (!v) return 'Geben Sie Ihre E-Mail-Adresse ein, damit wir antworten können. Oder wählen Sie „Keine Antwort nötig“.'; return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(v) ? '' : 'Die E-Mail-Adresse ist unvollständig, etwa so: name@beispiel.de'; } },
    tel: { label: 'Telefonnummer', aktiv: () => antwort() === 'tel', pruefe: () => /^[+\d][\d\s\/()-]{5,}$/.test(form.tel.value.trim()) ? '' : 'Geben Sie eine Telefonnummer mit Vorwahl ein, etwa 05321 12345.' }
  };
  const aktiv = n => !REGELN[n].aktiv || REGELN[n].aktiv();
  function setzeFehler(n, t) {
    $(`#f-${n}-fehler`).innerHTML = t ? `<span class="sr">Fehler: </span>${t}` : '';
    form.elements[n]?.setAttribute('aria-invalid', t ? 'true' : 'false');
  }
  function offene() { return Object.keys(REGELN).filter(n => aktiv(n) && REGELN[n].pruefe()); }
  function zeigeZusatz() {
    Object.entries(zusatz).forEach(([k, el]) => { el.hidden = antwort() !== k; if (el.hidden) setzeFehler(k, ''); });
  }
  form.addEventListener('change', e => { if (e.target.name === 'antwort') { zeigeZusatz(); if (versucht) liste(); } });
  let versucht = false;
  function liste() {
    const o = offene();
    $('[data-zf-liste]').innerHTML = o.map(n => `<li><a href="#f-${n}" data-zu="${n}">${REGELN[n].pruefe()}</a></li>`).join('');
    $('[data-zf-titel]').textContent = o.length === 1 ? 'Bitte prüfen Sie eine Angabe' : `Bitte prüfen Sie ${o.length === 2 ? 'zwei' : o.length} Angaben`;
    zf.hidden = !o.length;
    document.title = o.length ? 'Fehler: ' + TITEL : TITEL;
    return o;
  }
  zf.addEventListener('click', e => { const a = e.target.closest('a'); if (!a) return; e.preventDefault(); const f = form.elements[a.dataset.zu]; rolle(f.closest('.feld')); fokussiere(f); });
  form.addEventListener('input', e => {
    if (!versucht) return;
    const n = e.target.name;
    if (REGELN[n] && !REGELN[n].pruefe()) setzeFehler(n, '');
  });
  form.addEventListener('focusout', e => { if (versucht && REGELN[e.target.name]) { setzeFehler(e.target.name, aktiv(e.target.name) ? REGELN[e.target.name].pruefe() : ''); liste(); } });
  form.addEventListener('submit', e => {
    e.preventDefault(); versucht = true;
    Object.keys(REGELN).forEach(n => setzeFehler(n, aktiv(n) ? REGELN[n].pruefe() : ''));
    const o = liste();
    if (o.length) { status.textContent = ''; rolle(zf); fokussiere(zf); return; }
    karte.classList.add('gesendet');
    const t = $('[data-danke-titel]');
    status.textContent = 'Meldung gesendet.';
    fokussiere(t);
  });

  // ---------- Vorlage: Variante und Stand ----------
  const STAND = {
    3: { kurz: 'Vollständig barrierefrei', satz: 'Diese Website ist <strong>vollständig</strong> mit <span class="platz">[WCAG 2.2, Stufe AA]</span> vereinbar.', luecken: false },
    2: { kurz: 'Teilweise barrierefrei', satz: 'Diese Website ist <strong>teilweise</strong> mit <span class="platz">[WCAG 2.2, Stufe AA]</span> vereinbar. Die folgenden Inhalte sind noch nicht barrierefrei.', luecken: true },
    1: { kurz: 'Nicht barrierefrei', satz: 'Diese Website ist <strong>nicht</strong> mit <span class="platz">[WCAG 2.2, Stufe AA]</span> vereinbar. Die wichtigsten Mängel und Alternativen stehen hier; eine Überarbeitung ist <span class="platz">[bis …]</span> geplant.', luecken: true }
  };
  let variante = 'erklaerung', stufe = 2;
  function setzeStand(s) {
    stufe = STAND[s] ? +s : 2;
    $('[data-ampel]').dataset.stufe = stufe;
    $('[data-stand-kurz]').textContent = STAND[stufe].kurz;
    $('[data-stand-satz]').innerHTML = STAND[stufe].satz;
    $('[data-luecken]').hidden = !STAND[stufe].luecken;
    $$('[data-s]').forEach(b => b.setAttribute('aria-pressed', String(+b.dataset.s === stufe)));
  }
  function setzeVariante(v, url) {
    variante = v === 'bfsg' ? 'bfsg' : 'erklaerung';
    $$('[data-nur]').forEach(el => el.hidden = el.dataset.nur !== variante);
    const titel = variante === 'bfsg' ? 'Informationen zur Barrierefreiheit' : 'Erklärung zur Barrierefreiheit';
    $('[data-titel]').textContent = titel;
    $('[data-h-stand]').textContent = variante === 'bfsg' ? 'Wie wir die Anforderungen erfüllen' : 'Stand der Vereinbarkeit';
    $('#stand').dataset.abschnitt = variante === 'bfsg' ? 'Wie wir sie erfüllen' : 'Stand der Vereinbarkeit';
    document.title = TITEL.replace(/^[^·]+/, titel + ' ');
    $$('[data-v]').forEach(b => b.setAttribute('aria-pressed', String(b.dataset.v === variante)));
    if (url) { const q = new URLSearchParams(location.search); q.set('v', variante); history.replaceState(null, '', '?' + q.toString()); }
    baueToc();
  }
  $$('[data-v]').forEach(b => b.addEventListener('click', () => { const lief = html.classList.contains('vorfuehrung'); neustart(); setzeVariante(b.dataset.v, true); if (lief) vorfuehren(); }));
  $$('[data-s]').forEach(b => b.addEventListener('click', () => setzeStand(b.dataset.s)));

  function zuruecksetzen() {
    form.reset(); versucht = false; zeigeZusatz();
    Object.keys(REGELN).forEach(n => setzeFehler(n, ''));
    zf.hidden = true; karte.classList.remove('gesendet'); status.textContent = '';
    $$('.fokus-sim, .gedrueckt').forEach(x => x.classList.remove('fokus-sim', 'gedrueckt'));
    document.title = TITEL;
  }

  // ---------- Vorführung: lesen, springen, melden ----------
  let zeit = [], laeuft = false;
  const nach = (ms, f) => zeit.push(setTimeout(f, ms));
  function tocKlick(t, id) {
    nach(t, () => { const a = $(`a[href="#${id}"]`, tocListe); a?.classList.add('gedrueckt'); });
    nach(t + 350, () => { $$('.gedrueckt', tocListe).forEach(a => a.classList.remove('gedrueckt')); const z = document.getElementById(id); rolle(z); markiere(id); });
  }
  function tippe(t0, n, text, ms) {
    const f = form.elements[n];
    [...text].forEach((z, k) => nach(t0 + k * ms, () => { f.value += z; f.dispatchEvent(new Event('input', { bubbles: true })); }));
    return t0 + text.length * ms;
  }
  function runde() {
    zuruecksetzen(); window.scrollTo(0, 0); markiere('auf-einen-blick');
    let t = 3200;
    tocKlick(t, 'stand'); t += 2600;
    tocKlick(t, 'melden'); t += 1200;
    nach(t, () => rolle(karte)); t += 800;
    nach(t, () => fokussiere(form.was));
    t = tippe(t + 200, 'was', 'Kalender: Uhrzeit nicht wählbar', 40);
    nach(t + 300, () => { fokussiere(form.querySelector('[data-senden]')); $('[data-senden]').classList.add('gedrueckt'); });
    nach(t + 500, () => { $('[data-senden]').classList.remove('gedrueckt'); form.requestSubmit(); });
    t += 2600;
    nach(t, () => { rolle(form.mail.closest('.feld')); fokussiere(form.mail); });
    t = tippe(t + 400, 'mail', 'h.wolter@beispiel.de', 35);
    nach(t + 100, () => form.mail.dispatchEvent(new Event('focusout', { bubbles: true })));
    nach(t + 600, () => { $('[data-senden]').classList.add('gedrueckt'); });
    nach(t + 800, () => { $('[data-senden]').classList.remove('gedrueckt'); form.requestSubmit(); rolle(karte); });
    nach(t + 3600, () => window.scrollTo({ top: 0, behavior: reduziert() ? 'auto' : 'smooth' }));
    nach(t + 5200, runde);
  }
  function vorfuehren() { neustart(); html.classList.add('vorfuehrung'); laeuft = true; runde(); }
  function pause() { zeit.forEach(clearTimeout); zeit = []; laeuft = false; }
  function neustart() { pause(); html.classList.remove('vorfuehrung'); zuruecksetzen(); }
  function weiter() { if (!laeuft && html.classList.contains('vorfuehrung')) { laeuft = true; runde(); } }

  setzeVariante(new URLSearchParams(location.search).get('v'), false);
  setzeStand(2);
  tocModus();

})();
</script>
</body>
</html>