Zum Inhalt
← Sektionen & Funktionen

Rechtstexte lesbar setzen

Impressum und Datenschutz als lesbares Dokument: Stand-Datum, Inhaltsverzeichnis mit mitlaufender Markierung, Anker zum Kopieren, deutsche Trennung, Druckfassung und gezählte, deutlich markierte Platzhalter statt erfundener Rechtstexte.

Lange Rechtstexte (Datenschutz, AGB, Teilnahmebedingungen) mit mehr als vier Abschnitten.

Gerüst für Impressum und Datenschutzerklärung als lesbares Dokument statt Textwand. Oben stehen Titel, Stand-Datum und ein Inhaltsverzeichnis mit Sprungmarken; am Desktop bleibt es seitlich stehen und markiert den aktuellen Abschnitt. Jede Überschrift hat einen eigenen Anker zum Teilen. Lange Wörter wie „Auftragsverarbeitungsvertrag“ werden deutsch getrennt, Adressen und E-Mails nicht. Eine Druckfassung zeigt Links als Adresse und lässt Kopf und Fuß weg. Alle Inhalte, die der Kunde liefern oder prüfen lassen muss, sind als Platzhalter markiert und gezählt; das Gerüst erfindet keine Rechtstexte.

Rechtstexte werden selten gelesen, aber gezielt gesucht: Wer ist verantwortlich, welche Dienste laufen, wie widerspreche ich. Ein Inhaltsverzeichnis mit Ankern bringt Besucher direkt an die Stelle; ein sichtbares Stand-Datum zeigt, ob der Text gepflegt ist. Für Generatoren ist das Gerüst wichtig, weil hier sonst frei erfundene Rechtstexte entstehen. Markierte Platzhalter machen sichtbar, was vor dem Start fehlt.

Wann einsetzen

Auf jeder Kundenseite für Impressum und Datenschutzerklärung, ebenso für AGB, Widerrufsbelehrung, Barrierefreiheitserklärung oder Teilnahmebedingungen. Besonders wenn die Texte aus einem Generator oder von einer Kanzlei kommen und nur gesetzt werden müssen.

Wann nicht

Nicht als Ersatz für geprüfte Texte: Die Demo zeigt Gerüst und Platzhalter, keine Rechtsberatung, vom Kunden prüfen lassen. Kein Inhaltsverzeichnis bei sehr kurzen Seiten (unter vier Abschnitten). Kein Text im Bild oder als PDF allein. Keine Akkordeons, die Text vor der Browser-Suche verstecken.

Varianten

  • Datenschutzerklärung: langes Dokument mit seitlichem Inhaltsverzeichnis, Abschnittsmarkierung und Platzhalter-Zähler
  • Impressum: kurze Seite, Angaben als Definitionsliste, ohne Seitenleiste
  • Druckfassung über @media print: Links als Adresse, Seitenumbruch vor Hauptabschnitten, Stand-Datum im Kopf
  • Mehrere Fassungen mit Stand-Datum und Änderungshinweis

Umsetzung

Ein article mit h1, Stand-Datum als time und einem nav aria-label="Inhalt" mit ol. Am Desktop zwei Spalten: Inhaltsverzeichnis position: sticky, darunter der Text mit max. 68ch. Ein IntersectionObserver mit rootMargin "0px 0px -70% 0px" setzt aria-current="location" auf den Eintrag des sichtbaren Abschnitts. Jede h2 hat eine id und einen kleinen Anker-Knopf, der die Adresse mit #abschnitt kopiert. scroll-margin-top für alle Ziele. Text mit lang=de, hyphens: auto, hyphenate-limit-chars: 10 4 4 und overflow-wrap: break-word; Adressen, E-Mails, Telefonnummern und Registernummern bekommen hyphens: manual und white-space: nowrap bzw. wbr. Platzhalter als mark.platzhalter mit sichtbarem Label und gestrichelter Kante, ein Zähler oben springt von Platzhalter zu Platzhalter. Druck: @media print blendet Kopf, Fuß, Inhaltsverzeichnis und Knöpfe aus, setzt Links mit a[href^=http]::after { content: " (" attr(href) ")" }, break-before: page für Hauptabschnitte, break-inside: avoid für Definitionslisten, @page mit Rand. Auf dem Telefon klappt das Inhaltsverzeichnis in ein details-Element über dem Text.

Robust umsetzen

Telefon. Inhaltsverzeichnis als aufklappbares details-Element unter dem Titel, Text einspaltig in voller Breite mit Trennung. Anker-Knöpfe bleiben sichtbar (kein Hover nötig). Ein Knopf „Nach oben“ erscheint erst nach dem ersten Abschnitt.

Ohne Bewegung. Sprungmarken springen ohne weiches Scrollen, die Markierung im Inhaltsverzeichnis wechselt ohne Gleiten.

Barrierefrei. Eine h1, Abschnitte als h2 und h3 in sauberer Reihenfolge. Inhaltsverzeichnis als nav mit eigenem Namen und aria-current=location. Nach einem Sprung liegt der Fokus auf der Überschrift. Platzhalter sind auch ohne Farbe erkennbar (Label „Platzhalter“, gestrichelte Kante, eckige Klammern). Kein Text in Akkordeons versteckt, damit die Browser-Suche alles findet. Kontrast ≥ 4,5 : 1 auch im Druck.

Code

<!DOCTYPE html>
<!--
  Rechtstexte lesbar setzen
  Fundus · Sektionen & Funktionen · https://cecodesign.de/lab/fundus/sektionen/rechtstext-layout/
  Eigenständige Datei. Bilder liegen hier unter bilder/ – eigene einsetzen.
-->
<html lang="de" data-v="datenschutz">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Rechtstexte lesbar setzen · Fundus-Demo</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: 'Strichpunkt Sans'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/strichpunkt-sans:vf@latest/latin-full-normal.woff2') format('woff'); font-weight: 400 900; font-stretch: 100% 200%; font-display: swap; }
@font-face { font-family: 'Archivo'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/archivo:vf@latest/latin-full-normal.woff2') format('woff2-variations'); font-weight: 100 900; font-stretch: 62% 125%; 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; }

/* Rezept industrie-b2b-mittelstand: Blechgrau, Graphit, Stahlblau, Verkehrsblau nur für Handlung, aktiven Eintrag und Fokus */
:root {
  --grund: #f3f3f0; --papier: #fbfbf9; --kopf: #e4e5e1; --text: #111417; --leise: #4e555b; --raster: rgba(17, 20, 23, .13);
  --stahl: #16202a; --stahl-text: #f3f3f0; --stahl-leise: #b4bcc4; --stahl-linie: rgba(243, 243, 240, .16);
  --blau: #0e518d; --blau-tief: #0a3f6e;
  --ph-grund: #f6ecc4; --ph-kante: #7a6410; --ph-text: #3d3205;
  --ein: cubic-bezier(0.25, 1, 0.5, 1); --aus: cubic-bezier(0.5, 0, 0.75, 0);
  --hover: 200ms; --klapp: 350ms; --klapp-zu: 245ms; --sprung: 500ms;
  --h: 'Strichpunkt Sans', 'Arial Narrow', sans-serif; --t: 'Archivo', system-ui, sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { background: var(--grund); color: var(--text); font-family: var(--t); -webkit-font-smoothing: antialiased; }
:root:has(:focus-visible) { scroll-behavior: auto; }
body { font-size: 17px; line-height: 1.55; }
a { color: inherit; text-underline-offset: 3px; text-decoration-thickness: 1px; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
:focus-visible { outline: 2px solid var(--blau); outline-offset: 3px; }
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.vh:focus { position: fixed; left: 12px; top: 12px; width: auto; height: auto; clip-path: none; white-space: normal; z-index: 100; padding: 10px 14px; background: #fff; color: #111; outline: 3px solid #111; }
.ziffern { font-variant-numeric: tabular-nums lining-nums; }
.huelle { max-width: 1240px; margin: 0 auto; padding: 0 clamp(18px, 3.4vw, 44px); }
.code { font: 600 12.5px/1 var(--h); font-stretch: 130%; letter-spacing: .04em; color: var(--leise); font-variant-numeric: tabular-nums; }

/* Kopf */
.kopf { background: var(--stahl); color: var(--stahl-text); }
.kopf .huelle { display: flex; align-items: center; gap: 26px; min-height: 64px; }
.marke { display: flex; align-items: center; gap: 12px; text-decoration: none; margin-right: auto; }
.marke svg { width: 32px; height: 32px; flex: none; }
.marke b { font: 700 18px/1 var(--h); font-stretch: 125%; letter-spacing: -.02em; display: block; }
.marke small { font-size: 12.5px; color: var(--stahl-leise); display: block; margin-top: 3px; }
.kopf nav ul { display: flex; gap: 24px; list-style: none; }
.kopf nav a { text-decoration: none; font-size: 15px; font-stretch: 94%; color: var(--stahl-leise); transition: color var(--hover) var(--ein); }
.kopf nav a:hover { color: var(--stahl-text); }
.sprache { font-size: 14px; color: var(--stahl-leise); }
.sprache b { color: var(--stahl-text); }
.anfragen { display: inline-flex; align-items: center; min-height: 42px; padding: 0 16px; background: var(--blau); color: #fff; font-weight: 600; font-size: 15px; text-decoration: none; transition: background-color var(--hover) var(--ein); }
.anfragen:hover { background: var(--blau-tief); }
.kopf :focus-visible { outline-color: #fff; }

/* Dokumentkopf */
.krumen { padding: 18px 0 0; font-size: 14.5px; color: var(--leise); }
.krumen ol { display: flex; flex-wrap: wrap; list-style: none; }
.krumen li + li::before { content: '/'; margin: 0 10px; opacity: .6; }
.krumen [aria-current] { color: var(--text); }
.dokkopf { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 18px 40px; align-items: end; padding: clamp(24px, 3vw, 44px) 0 clamp(22px, 2.6vw, 34px); border-bottom: 1px solid var(--raster); }
.dokkopf .code { display: block; margin-bottom: 14px; }
h1 { font: 650 clamp(2.4rem, 1.5rem + 3.6vw, 4.4rem)/.98 var(--h); font-stretch: 116%; letter-spacing: -.03em; hyphens: auto; overflow-wrap: break-word; }
h1:focus, h1:focus-visible { outline: none; }
.stand { display: flex; flex-wrap: wrap; gap: 6px 22px; margin-top: 16px; font-size: 15.5px; color: var(--leise); }
.stand b { color: var(--text); font-weight: 600; }
.werkzeuge { display: flex; flex-wrap: wrap; gap: 10px; }
.knopf { display: inline-flex; align-items: center; gap: 9px; min-height: 44px; padding: 0 14px; border: 1px solid var(--text); font-weight: 600; font-size: 15px; text-decoration: none; background: transparent; transition: background-color var(--hover) var(--ein), color var(--hover) var(--ein); }
.knopf:hover { background: var(--text); color: var(--grund); }
.knopf svg { width: 17px; height: 17px; flex: none; }

/* Platzhalter-Hinweis */
.entwurf { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; margin: 20px 0 0; padding: 14px 16px; border: 1.5px dashed var(--ph-kante); background: var(--ph-grund); color: var(--ph-text); font-size: 15px; }
.entwurf strong { font-weight: 700; }
.entwurf .zaehler { font-variant-numeric: tabular-nums; font-weight: 700; padding: 3px 8px; border: 1px solid var(--ph-kante); background: #fffbe9; }
.entwurf button { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; min-height: 40px; padding: 0 12px; border: 1px solid var(--ph-text); font-weight: 600; font-size: 14.5px; transition: background-color var(--hover) var(--ein), color var(--hover) var(--ein); }
.entwurf button:hover { background: var(--ph-text); color: var(--ph-grund); }
.entwurf button svg { width: 15px; height: 15px; }
mark.platzhalter { hyphens: manual; -webkit-hyphens: manual; background: repeating-linear-gradient(-45deg, var(--ph-grund) 0 7px, #f1e3ad 7px 14px); color: var(--ph-text); padding: 1px 4px; border: 1px dashed var(--ph-kante); font-weight: 500; -webkit-box-decoration-break: clone; box-decoration-break: clone; scroll-margin: 40vh 0; transition: box-shadow var(--hover) var(--ein); }
mark.platzhalter:focus { outline: none; }
mark.platzhalter.ziel, mark.platzhalter:focus-visible { box-shadow: 0 0 0 3px var(--blau); }
.ph-block { margin: 14px 0 0; padding: 14px 16px 14px 18px; border: 1.5px dashed var(--ph-kante); background: repeating-linear-gradient(-45deg, var(--ph-grund) 0 8px, #f3e7b8 8px 16px); color: var(--ph-text); scroll-margin: 30vh 0; transition: box-shadow var(--hover) var(--ein); }
.ph-block:focus { outline: none; }
.ph-block.ziel, .ph-block:focus-visible { box-shadow: 0 0 0 3px var(--blau); }
.ph-block .ph-label { display: inline-block; font: 600 11.5px/1 var(--h); font-stretch: 130%; letter-spacing: .06em; text-transform: uppercase; padding: 4px 7px; background: var(--ph-text); color: var(--ph-grund); margin-bottom: 9px; }
.ph-block p { font-size: 15.5px; }
.ph-block ul { margin: 6px 0 0 1.1em; font-size: 15.5px; }

/* Satzspiegel */
.dokument { display: grid; grid-template-columns: minmax(220px, 290px) minmax(0, 1fr); gap: clamp(28px, 5vw, 80px); padding-top: clamp(28px, 3.4vw, 48px); padding-bottom: clamp(64px, 8vw, 120px); }
.inhalt-nav { position: sticky; top: 20px; align-self: start; max-height: calc(100svh - 40px); overflow: auto; }
.inhalt-nav details > summary { list-style: none; font: 600 13px/1 var(--h); font-stretch: 130%; letter-spacing: .06em; text-transform: uppercase; color: var(--leise); padding: 0 0 12px; border-bottom: 1px solid var(--raster); pointer-events: none; }
.inhalt-nav summary::-webkit-details-marker { display: none; }
.inhalt-liste { position: relative; padding: 8px 0 0; }
.inhalt-nav ol { list-style: none; }
.inhalt-nav li a { display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: 8px; padding: 7px 10px 7px 12px; text-decoration: none; font-size: 15px; line-height: 1.3; color: var(--leise); position: relative; z-index: 1; transition: color var(--hover) var(--ein); hyphens: auto; }
.inhalt-nav li a .code { padding-top: 3px; }
.inhalt-nav li a:hover { color: var(--text); }
.inhalt-nav li a[aria-current] { color: var(--text); font-weight: 600; }
.inhalt-nav li a[aria-current] .code { color: var(--blau); }
.marker { position: absolute; left: 0; top: 0; width: 100%; height: 0; background: var(--kopf); border-left: 3px solid var(--blau); transform: translateY(0); transition: transform var(--hover) var(--ein), height var(--hover) var(--ein); pointer-events: none; }
.inhalt-nav .unten { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--raster); font-size: 14px; color: var(--leise); display: grid; gap: 6px; }

.text { max-width: 68ch; hyphens: auto; -webkit-hyphens: auto; hyphenate-limit-chars: 10 4 4; overflow-wrap: break-word; }
.ohne-trennung .text, .ohne-trennung h1, .ohne-trennung .inhalt-nav a { hyphens: manual; -webkit-hyphens: manual; }
.text > section { padding: 0 0 34px; margin-bottom: 34px; border-bottom: 1px solid var(--raster); scroll-margin-top: 20px; }
.text > section:last-child { border-bottom: 0; }
.text h2 { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 14px; align-items: baseline; font: 620 clamp(1.5rem, 1.15rem + 1.3vw, 2.1rem)/1.08 var(--h); font-stretch: 110%; letter-spacing: -.02em; margin-bottom: 14px; }
.text h2:focus { outline: none; }
.text h2 .code { font-size: 13px; }
.anker { display: inline-grid; place-items: center; width: 34px; height: 34px; border: 1px solid transparent; color: var(--leise); opacity: .7; transition: opacity var(--hover) var(--ein), border-color var(--hover) var(--ein), color var(--hover) var(--ein); align-self: center; }
.anker svg { width: 16px; height: 16px; }
.text h2:hover .anker, .anker:focus-visible { opacity: 1; border-color: var(--raster); color: var(--text); }
.anker:hover { border-color: var(--text) !important; }
.text h3 { font: 600 1.2rem/1.25 var(--t); margin: 22px 0 6px; }
.text p + p { margin-top: .8em; }
.text p { max-width: 68ch; }
.text .rahmen { color: var(--leise); }
.daten { display: grid; margin-top: 14px; border-top: 1px solid var(--text); }
.daten div { display: grid; grid-template-columns: minmax(0, 13em) minmax(0, 1fr); gap: 14px; padding: 10px 0; border-bottom: 1px solid var(--raster); break-inside: avoid; }
.daten dt { color: var(--leise); font-size: 15.5px; hyphens: auto; }
.daten dd { font-weight: 500; }
.nowrap { white-space: nowrap; hyphens: manual; }
.tabelle-huelle { margin-top: 14px; overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: 15px; font-stretch: 94%; }
th, td { text-align: left; vertical-align: top; padding: 9px 12px 9px 0; border-bottom: 1px solid var(--raster); }
thead th { background: var(--kopf); padding-left: 10px; font-weight: 600; font-size: 14px; }
tbody th { font-weight: 600; padding-left: 10px; }
.fassungen { margin-top: 12px; }
.fassungen summary { cursor: pointer; font-weight: 600; display: inline-flex; gap: 10px; align-items: center; padding: 6px 0; }
.fassungen summary::-webkit-details-marker { display: none; }
.fassungen summary::before { content: '+'; width: 22px; height: 22px; display: grid; place-items: center; border: 1px solid var(--text); font-weight: 500; transition: transform var(--klapp-zu) var(--aus); }
.fassungen[open] summary::before { content: '–'; }
.fassungen ol { list-style: none; margin-top: 8px; border-top: 1px solid var(--raster); }
.fassungen li { display: grid; grid-template-columns: 7em minmax(0, 1fr) auto; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--raster); font-size: 15.5px; }
.fassungen[open] ol { animation: klapp var(--klapp) var(--ein); }
@keyframes klapp { from { opacity: 0; transform: translateY(-6px); } }
.nach-oben { position: fixed; right: 18px; bottom: 18px; z-index: 15; display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 14px; background: var(--stahl); color: var(--stahl-text); font-weight: 600; font-size: 14.5px; text-decoration: none; transform: translateY(12px); opacity: 0; pointer-events: none; transition: opacity var(--klapp-zu) var(--aus), transform var(--klapp-zu) var(--aus); }
.nach-oben.an { opacity: 1; transform: none; pointer-events: auto; transition: opacity var(--klapp) var(--ein), transform var(--klapp) var(--ein); }
.nach-oben svg { width: 16px; height: 16px; }

/* Impressum: kurze Seite, keine Seitenleiste */
:root[data-v="impressum"] .dokument { grid-template-columns: minmax(0, 1fr); }
:root[data-v="impressum"] .text { max-width: 980px; }
:root[data-v="impressum"] .inhalt-nav { display: none; }
.blatt { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border-top: 2px solid var(--text); }
.blatt section { padding: 18px 24px 22px 0; border-bottom: 1px solid var(--raster); }
.blatt section:nth-child(odd) { padding-right: 32px; border-right: 1px solid var(--raster); }
.blatt section:nth-child(even) { padding-left: 32px; }
.blatt h2 { display: flex; gap: 12px; align-items: baseline; font: 620 1.3rem/1.15 var(--h); font-stretch: 110%; letter-spacing: -.015em; margin-bottom: 10px; }
.blatt dl { display: grid; gap: 10px; }
.blatt dl div { display: grid; gap: 1px; font-size: 17px; }
.blatt dt { color: var(--leise); font-size: 14.5px; }
.blatt p { font-size: 16px; }
.blatt .voll { grid-column: 1 / -1; border-right: 0 !important; padding-left: 0 !important; }

/* Fuß */
.fuss { background: var(--stahl); color: var(--stahl-leise); font-size: 14.5px; padding: 36px 0 44px; }
.fuss .huelle { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr)); gap: 20px 36px; }
.fuss b { color: var(--stahl-text); display: block; margin-bottom: 6px; font-weight: 600; }
.fuss ul { list-style: none; display: grid; gap: 4px; }
.fuss a { color: var(--stahl-text); }
.fuss a[aria-current] { text-decoration-thickness: 2px; }
.fuss :focus-visible { outline-color: #fff; }

.meldung { position: fixed; left: 50%; bottom: 22px; z-index: 30; transform: translate(-50%, 10px); opacity: 0; background: var(--text); color: var(--grund); padding: 10px 14px; font-weight: 600; font-size: 15px; pointer-events: none; transition: opacity var(--klapp-zu) var(--aus), transform var(--klapp-zu) var(--aus); max-width: calc(100vw - 32px); }
.meldung.an { opacity: 1; transform: translate(-50%, 0); transition: opacity var(--klapp) var(--ein), transform var(--klapp) var(--ein); }

/* Pult */
.pult { position: fixed; right: 14px; bottom: 14px; z-index: 40; width: 250px; padding: 12px; display: grid; gap: 9px; background: rgba(17, 20, 23, .94); color: #f3f3f0; box-shadow: 0 12px 34px rgba(0, 0, 0, .24); }
.pult .mono { font: 500 10.5px/1.4 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; color: rgba(243, 243, 240, .72); }
.pult .reihe { display: grid; grid-template-columns: 1fr 1fr; border: 1px solid rgba(243, 243, 240, .24); }
.pult button { padding: 8px 6px; font: 500 11.5px/1.2 'Geist Mono', monospace; color: rgba(243, 243, 240, .84); transition: background-color var(--hover) var(--ein), color var(--hover) var(--ein); }
.pult .reihe button + button { border-left: 1px solid rgba(243, 243, 240, .24); }
.pult button[aria-pressed="true"] { background: #f3f3f0; color: #111417; }
.pult .einzeln { border: 1px solid rgba(243, 243, 240, .24); text-align: left; padding: 8px 10px; display: flex; justify-content: space-between; }
.pult :focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.pult .werte { font: 400 10.5px/1.5 'Geist Mono', monospace; color: rgba(243, 243, 240, .72); }

@media (max-width: 1080px) { .kopf nav { display: none; } }
@media (max-width: 860px) {
  .dokkopf { grid-template-columns: minmax(0, 1fr); }
  .dokument { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .inhalt-nav { position: static; max-height: none; background: var(--papier); border: 1px solid var(--raster); padding: 0 14px; }
  .inhalt-nav details > summary { pointer-events: auto; cursor: pointer; padding: 14px 0; border-bottom: 0; display: flex; justify-content: space-between; }
  .inhalt-nav details > summary::after { content: '+'; font-size: 18px; }
  .inhalt-nav details[open] > summary::after { content: '–'; }
  .inhalt-nav details[open] .inhalt-liste { animation: klapp var(--klapp) var(--ein); border-top: 1px solid var(--raster); }
  .marker { display: none; }
  .inhalt-nav .unten { display: none; }
  .blatt { grid-template-columns: minmax(0, 1fr); }
  .blatt section, .blatt section:nth-child(odd), .blatt section:nth-child(even) { padding: 16px 0 18px; border-right: 0; }
}
@media (max-width: 560px) {
  .sprache { display: none; }
  .anfragen { padding: 0 12px; font-size: 14px; }
  .marke small { display: none; }
  .daten div { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .text h2 { grid-template-columns: minmax(0, 1fr) auto; }
  .text h2 .code { grid-column: 1 / -1; }
  .fassungen li { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .entwurf button { margin-left: 0; }
  thead { display: none; }
  table, tbody, tr, th, td { display: block; }
  tr { border-bottom: 1px solid var(--text); padding: 8px 0; }
  tbody th { padding: 4px 0; border: 0; font-size: 16px; }
  td { border: 0; padding: 3px 0; display: grid; grid-template-columns: 8.5em minmax(0, 1fr); gap: 8px; }
  td::before { content: attr(data-spalte); color: var(--leise); }
}
@media (hover: none) { .anker { opacity: 1; border-color: var(--raster); } }

.vorschau body { overflow: hidden; }
.vorschau .nach-oben, .vorschau .meldung { display: none; }

/* Druckfassung (auch als Ansicht im Pult: .druckansicht) */
@media print {
  @page { margin: 18mm 16mm 20mm; }
  html, body { background: #fff; color: #000; font-size: 11pt; }
  .kopf nav, .sprache, .anfragen, .krumen, .werkzeuge, .inhalt-nav, .anker, .nach-oben, .pult, .meldung, .entwurf button, .fuss, .fassungen summary::before { display: none !important; }
  .kopf { background: #fff; color: #000; border-bottom: 1px solid #000; }
  .kopf .marke small { color: #333; }
  .dokument { display: block; padding-top: 8mm; }
  .text { max-width: none; }
  .text > section { break-inside: auto; }
  .text > section.haupt { break-before: page; }
  .text h2 { break-after: avoid; }
  .daten div, tr { break-inside: avoid; }
  .text a[href^="http"]::after { content: ' (' attr(href) ')'; font-size: .9em; color: #333; }
  .fassungen ol { display: block !important; }
}
.druckansicht body { background: #8c9196; }
.druckansicht .kopf nav, .druckansicht .sprache, .druckansicht .anfragen, .druckansicht .krumen, .druckansicht .werkzeuge, .druckansicht .inhalt-nav, .druckansicht .anker, .druckansicht .nach-oben, .druckansicht .entwurf button, .druckansicht .fuss { display: none !important; }
.druckansicht .seite { max-width: 794px; margin: 28px auto; background: #fff; color: #000; box-shadow: 0 10px 40px rgba(0, 0, 0, .3); padding: 0 0 40px; }
.druckansicht .kopf { background: #fff; color: #000; border-bottom: 1px solid #000; }
.druckansicht .kopf .marke small { color: #333; }
.druckansicht .huelle { padding: 0 56px; }
.druckansicht .dokument { display: block; }
.druckansicht .text { max-width: none; }
.druckansicht .text a[href^="http"]::after { content: ' (' attr(href) ')'; font-size: .9em; color: #333; }
.druckansicht .text > section.haupt { border-top: 2px dashed #8c9196; padding-top: 30px; position: relative; }
.druckansicht .text > section.haupt::before { content: 'Seitenumbruch'; position: absolute; top: -10px; right: 0; background: #fff; padding: 0 6px; font: 500 10px/1.4 'Geist Mono', monospace; letter-spacing: .12em; text-transform: uppercase; color: #5b6166; }

.reduziert *, .reduziert *::before, .reduziert *::after { animation: none !important; transition-duration: .01ms !important; }
@media (forced-colors: active) {
  button, [role=button], [role=tab], [role=switch], input, select, textarea, .knopf, .anfragen { border: 1px solid ButtonText !important; }
  mark.platzhalter, .ph-block { border: 2px dashed CanvasText; }
  .marker { border-left-color: Highlight; }
}
</style>
</head>
<body>
<div class="seite">
<a class="vh" href="#text">Zum Text springen</a>
<header class="kopf">
  <div class="huelle">
    <a class="marke" href="#" aria-label="Wiedenau Spanntechnik, Startseite">
      <svg viewBox="0 0 32 32" aria-hidden="true"><rect x="3" y="6" width="26" height="6" fill="#f3f3f0"/><rect x="3" y="20" width="26" height="6" fill="#f3f3f0"/><rect x="13" y="12" width="6" height="8" fill="#0e518d"/><path d="M8 12v8M24 12v8" stroke="#f3f3f0" stroke-width="2"/></svg>
      <span><b>Wiedenau</b><small>Spanntechnik GmbH · Schmalkalden</small></span>
    </a>
    <nav aria-label="Hauptmenü"><ul><li><a href="#">Produkte</a></li><li><a href="#">Anwendungen</a></li><li><a href="#">Service</a></li><li><a href="#">Unternehmen</a></li><li><a href="#">Kontakt</a></li></ul></nav>
    <span class="sprache"><b>DE</b> / <a href="#" hreflang="en" lang="en">EN</a></span>
    <a class="anfragen" href="#">Projekt anfragen</a>
  </div>
</header>

<main id="haupt">
  <div class="huelle">
    <nav class="krumen" aria-label="Brotkrumen"><ol><li><a href="#">Startseite</a></li><li><a href="#">Rechtliches</a></li><li><span aria-current="page" id="krume"></span></li></ol></nav>
    <div class="dokkopf">
      <div>
        <span class="code" id="dok-code"></span>
        <h1 id="titel" tabindex="-1"></h1>
        <p class="stand" id="stand"></p>
      </div>
      <div class="werkzeuge">
        <button type="button" class="knopf" id="drucken"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M7 9V3h10v6M7 17H4v-7h16v7h-3"/><rect x="7" y="14" width="10" height="7"/></svg>Drucken oder als PDF</button>
      </div>
    </div>
    <div class="entwurf" role="note" id="entwurf">
      <strong>Gerüst mit Platzhaltern.</strong>
      <span>Texte liefert der Kunde bzw. seine Rechtsberatung. Vor dem Start vom Kunden prüfen lassen.</span>
      <span class="zaehler" id="zaehler" aria-live="polite"></span>
      <button type="button" id="naechster"><span>Nächster Platzhalter</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-hidden="true"><path d="M12 5v14M6 13l6 6 6-6"/></svg></button>
    </div>
  </div>
  <div class="huelle dokument">
    <nav class="inhalt-nav" aria-label="Inhalt dieser Seite" id="inhalt-nav">
      <details id="inhalt-details" open><summary>Inhalt</summary><div class="inhalt-liste"><span class="marker" id="marker" aria-hidden="true"></span><ol id="inhalt"></ol></div></details>
      <div class="unten"><span>Fragen zum Datenschutz?</span><a href="#">datenschutz@wiedenau-spanntechnik.de</a></div>
    </nav>
    <article class="text" id="text" aria-labelledby="titel"></article>
  </div>
</main>

<footer class="fuss">
  <div class="huelle">
    <div><b>Wiedenau Spanntechnik GmbH</b>Am Hammergraben 9<br>98574 Schmalkalden</div>
    <div><b>Zentrale</b><span class="ziffern">03683 6904-0</span><br>Mo bis Fr 7 bis 16 Uhr</div>
    <ul><li><a href="?v=impressum" data-zu="impressum">Impressum</a></li><li><a href="?v=datenschutz" data-zu="datenschutz">Datenschutz</a></li><li><a href="#">AGB und Lieferbedingungen</a></li><li><a href="#">Barrierefreiheit</a></li></ul>
  </div>
</footer>
</div>

<a class="nach-oben" href="#titel" id="nach-oben"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-hidden="true"><path d="M12 19V5M6 11l6-6 6 6"/></svg>Nach oben</a>
<div class="meldung" id="meldung" role="status" aria-live="polite"></div>

<div class="pult" aria-label="Steuerung der Demo" role="group">
  <span class="mono">Dokument</span>
  <div class="reihe" id="pult-v">
    <button type="button" data-v="datenschutz" aria-pressed="true">Datenschutz</button>
    <button type="button" data-v="impressum" aria-pressed="false">Impressum</button>
  </div>
  <button type="button" class="einzeln" id="pult-trennung" aria-pressed="true"><span>Silbentrennung</span><span aria-hidden="true">an</span></button>
  <button type="button" class="einzeln" id="pult-druck" aria-pressed="false"><span>Druckansicht</span><span aria-hidden="true">aus</span></button>
  <p class="werte" id="pult-werte">hyphens: auto · hyphenate-limit-chars 10 4 4 · Markierung 200 ms (0.25,1,0.5,1) · Sprung 500 ms</p>
</div>

<script>
(() => {
  const h = document.documentElement;
  const reduziert = () => h.classList.contains('reduziert');
  const $ = (s, w = document) => w.querySelector(s);
  const $$ = (s, w = document) => [...w.querySelectorAll(s)];
  const P = (t) => `<mark class="platzhalter" tabindex="-1">[${t}]</mark>`;
  const B = (titel, inhalt) => `<div class="ph-block" tabindex="-1"><span class="ph-label">Platzhalter · vom Kunden prüfen lassen</span><p><b>${titel}</b></p>${inhalt}</div>`;
  const ANKER = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1"/></svg>';

  /* Gliederung und Platzhalter. Keine Rechtstexte: nur, was an welche Stelle gehört. */
  const DOKS = {
    datenschutz: {
      code: 'R-02 · Rechtliches', titel: 'Datenschutzerklärung', krume: 'Datenschutz',
      stand: { iso: '2026-10-15', text: '15. Oktober 2026', fassung: 3 },
      abschnitte: [
        { id: 'verantwortlich', t: 'Verantwortliche Stelle', haupt: true, inhalt: `<p class="rahmen">Wer über die Daten auf dieser Website entscheidet. Die Angaben kommen aus demselben Datensatz wie das Impressum.</p>
          <dl class="daten"><div><dt>Unternehmen</dt><dd>Wiedenau Spanntechnik GmbH</dd></div><div><dt>Anschrift</dt><dd>Am Hammergraben 9, <span class="nowrap">98574 Schmalkalden</span></dd></div><div><dt>Vertreten durch</dt><dd>${P('Geschäftsführung, Vor- und Nachname')}</dd></div><div><dt>E-Mail</dt><dd><a class="nowrap" href="#">datenschutz@<wbr>wiedenau-spanntechnik.de</a></dd></div><div><dt>Telefon</dt><dd class="ziffern nowrap">03683 6904-0</dd></div></dl>` },
        { id: 'beauftragte', t: 'Datenschutzbeauftragte Person', inhalt: B('Angaben zur oder zum Datenschutzbeauftragten', `<p>Ob eine Person benannt ist und wie sie erreichbar ist. Falls extern: Name des Dienstleisters und Kontaktweg.</p>`) },
        { id: 'aufruf', t: 'Aufruf der Website und Server-Logdateien', inhalt: B('Text zum Hosting und zu Logdateien', `<ul><li>welche Daten beim Aufruf anfallen und wofür</li><li>Rechtsgrundlage und Speicherdauer</li><li>Hoster mit Name und Sitz, ${P('Auftragsverarbeitungsvertrag ja oder nein')}</li></ul>`) },
        { id: 'einwilligung', t: 'Cookies und Einwilligungsverwaltung', inhalt: `<p class="rahmen">Diese Website setzt ohne Einwilligung nur, was für den Betrieb nötig ist. Was darunter fällt, steht in der Tabelle unter „Eingebundene Dienste“.</p>${B('Text zur Einwilligungsverwaltung', `<p>Wie Besucher Einwilligungen erteilen, ändern und widerrufen. Link zu den Einstellungen: ${P('Pfad zum Einstellungsdialog')}.</p>`)}` },
        { id: 'anfrage', t: 'Projektanfrage und Kontaktformular', haupt: true, inhalt: `<p class="rahmen">Gilt für das Formular „Projekt anfragen“, für E-Mails und Anrufe.</p>${B('Text zu Anfragen', `<ul><li>welche Felder Pflicht sind und wofür sie gebraucht werden</li><li>Weitergabe an Vertriebspartner im Ausland ${P('ja, an wen, oder nein')}</li><li>Speicherdauer nach Abschluss der Anfrage</li></ul>`)}` },
        { id: 'bewerbung', t: 'Bewerbungen', inhalt: B('Text zu Bewerbungsunterlagen', `<p>Wer die Unterlagen sieht, wie lange sie nach einer Absage gespeichert werden und ob ein Talentpool mit Einwilligung besteht.</p>`) },
        { id: 'messen', t: 'Newsletter mit Messeterminen', inhalt: B('Text zum Newsletter', `<p>Anmeldung mit Bestätigung per E-Mail, Versanddienst ${P('Anbieter und Sitz')}, Abmeldung in jeder Ausgabe.</p>`) },
        { id: 'dienste', t: 'Eingebundene Dienste', haupt: true, inhalt: `<p class="rahmen">Karten und Videos laden erst nach Klick. Die Tabelle wächst mit jedem Dienst; Angaben vom Kunden prüfen lassen.</p>
          <div class="tabelle-huelle"><table><caption class="vh">Eingebundene Dienste mit Zweck, Anbieter, Rechtsgrundlage und Speicherdauer</caption><thead><tr><th scope="col">Dienst</th><th scope="col">Zweck</th><th scope="col">Anbieter</th><th scope="col">Rechtsgrundlage</th><th scope="col">Speicherdauer</th></tr></thead><tbody>
          <tr><th scope="row">Karte Anfahrt</th><td data-spalte="Zweck">Anfahrt zum Werk zeigen, nach Klick</td><td data-spalte="Anbieter">${P('Name, Sitz')}</td><td data-spalte="Rechtsgrundlage">${P('eintragen')}</td><td data-spalte="Speicherdauer">${P('eintragen')}</td></tr>
          <tr><th scope="row">Produktvideos</th><td data-spalte="Zweck">Spanner im Einsatz zeigen, nach Klick</td><td data-spalte="Anbieter">${P('Name, Sitz')}</td><td data-spalte="Rechtsgrundlage">${P('eintragen')}</td><td data-spalte="Speicherdauer">${P('eintragen')}</td></tr>
          <tr><th scope="row">Schriften</th><td data-spalte="Zweck">Darstellung, vom eigenen Server</td><td data-spalte="Anbieter">kein Dritter</td><td data-spalte="Rechtsgrundlage">${P('eintragen')}</td><td data-spalte="Speicherdauer">keine</td></tr>
          </tbody></table></div>` },
        { id: 'rechte', t: 'Ihre Rechte', inhalt: B('Text zu den Betroffenenrechten', `<p>Welche Rechte Besucher haben, wie sie sie ausüben und welche Aufsichtsbehörde zuständig ist: ${P('Behörde und Anschrift')}. Die Kontaktadresse oben gilt auch für Widerspruch und Widerruf.</p>`) },
        { id: 'aenderungen', t: 'Änderungen dieser Erklärung', inhalt: `<p>Ändern sich Dienste oder Abläufe, bekommt die Erklärung eine neue Fassung mit Datum. Frühere Fassungen bleiben abrufbar.</p>
          <details class="fassungen"><summary>Frühere Fassungen</summary><ol>
          <li><time datetime="2026-10-15" class="ziffern">15.10.2026</time><span>Fassung 3: Newsletter mit Messeterminen ergänzt</span><b>aktuell</b></li>
          <li><time datetime="2026-03-02" class="ziffern">02.03.2026</time><span>Fassung 2: Karte nur noch nach Klick</span><a href="#">ansehen</a></li>
          <li><time datetime="2025-09-11" class="ziffern">11.09.2025</time><span>Fassung 1</span><a href="#">ansehen</a></li></ol></details>` }
      ]
    },
    impressum: {
      code: 'R-01 · Rechtliches', titel: 'Impressum', krume: 'Impressum',
      stand: { iso: '2026-10-15', text: '15. Oktober 2026' },
      blatt: [
        { id: 'anbieter', t: 'Anbieter', inhalt: `<dl><div><dt>Firma</dt><dd>Wiedenau Spanntechnik GmbH</dd></div><div><dt>Anschrift</dt><dd>Am Hammergraben 9<br><span class="nowrap">98574 Schmalkalden</span></dd></div></dl>` },
        { id: 'vertretung', t: 'Vertreten durch', inhalt: `<dl><div><dt>Geschäftsführung</dt><dd>${P('Vor- und Nachname')}</dd></div></dl>` },
        { id: 'kontakt', t: 'Kontakt', inhalt: `<dl><div><dt>Telefon</dt><dd class="ziffern nowrap">03683 6904-0</dd></div><div><dt>E-Mail</dt><dd><a class="nowrap" href="#">info@<wbr>wiedenau-spanntechnik.de</a></dd></div></dl>` },
        { id: 'register', t: 'Registereintrag', inhalt: `<dl><div><dt>Registergericht</dt><dd>${P('Amtsgericht')}</dd></div><div><dt>Registernummer</dt><dd class="nowrap">HRB ${P('Nummer')}</dd></div></dl>` },
        { id: 'steuer', t: 'Umsatzsteuer', inhalt: `<dl><div><dt>USt-IdNr.</dt><dd class="nowrap">DE ${P('Nummer')}</dd></div></dl>` },
        { id: 'inhalt', t: 'Verantwortlich für Inhalte', inhalt: `<p>${P('Name und Anschrift, falls diese Angabe für die Website nötig ist')}</p>` },
        { id: 'streit', t: 'Streitbeilegung', voll: true, inhalt: B('Angabe zur Verbraucherschlichtung', `<p>Ob und wie diese Angabe für einen Betrieb mit Geschäftskunden nötig ist, klärt der Kunde mit seiner Beratung.</p>`) },
        { id: 'bilder', t: 'Bildnachweise und Umsetzung', voll: true, inhalt: `<p>Fotos: ${P('Fotograf oder eigene Aufnahmen')} · Gestaltung und Umsetzung: ${P('Agentur')}</p>` }
      ]
    }
  };

  let v = new URLSearchParams(location.search).get('v');
  if (!DOKS[v]) v = 'datenschutz';
  let beobachter = null, phIndex = -1, meldTimer = null;
  const fDatum = new Intl.DateTimeFormat('de-DE', { day: 'numeric', month: 'long', year: 'numeric' });

  function melden(t) { const m = $('#meldung'); m.textContent = t; m.classList.add('an'); clearTimeout(meldTimer); meldTimer = setTimeout(() => m.classList.remove('an'), 2000); }

  function zeichne() {
    const d = DOKS[v];
    h.dataset.v = v;
    document.title = d.titel + ' · Wiedenau Spanntechnik · Fundus-Demo';
    $('#dok-code').textContent = d.code;
    $('#titel').textContent = d.titel;
    $('#krume').textContent = d.krume;
    const t = $('#text');
    if (d.abschnitte) {
      t.innerHTML = d.abschnitte.map((a, i) => `<section id="${a.id}" aria-labelledby="${a.id}-t"${a.haupt ? ' class="haupt"' : ''}><h2 id="${a.id}-t" tabindex="-1"><span class="code">D.${String(i + 1).padStart(2, '0')}</span><span>${a.t}</span><button type="button" class="anker" data-anker="${a.id}" aria-label="Link zu „${a.t}“ kopieren">${ANKER}</button></h2>${a.inhalt}</section>`).join('');
      $('#inhalt').innerHTML = d.abschnitte.map((a, i) => `<li><a href="#${a.id}"><span class="code">D.${String(i + 1).padStart(2, '0')}</span><span>${a.t}</span></a></li>`).join('');
    } else {
      t.innerHTML = `<div class="blatt">${d.blatt.map(a => `<section id="${a.id}" aria-labelledby="${a.id}-t"${a.voll ? ' class="voll"' : ''}><h2 id="${a.id}-t">${a.t}</h2>${a.inhalt}</section>`).join('')}</div>`;
      $('#inhalt').innerHTML = '';
    }
    const woerter = t.textContent.trim().split(/\s+/).length;
    $('#stand').innerHTML = `<span>Stand: <b><time datetime="${d.stand.iso}">${d.stand.text}</time></b></span>${d.stand.fassung ? `<span>Fassung ${d.stand.fassung}</span>` : ''}<span>Lesezeit etwa ${Math.max(1, Math.round(woerter / 200))} Min.</span>`;
    phIndex = -1; zaehlen();
    $$('[data-anker]').forEach(b => b.addEventListener('click', () => ankerKopieren(b.dataset.anker)));
    beobachten();
  }
  function platzhalter() { return $$('#text mark.platzhalter, #text .ph-block, #dok-kopf mark.platzhalter'); }
  function zaehlen() {
    const n = platzhalter().length;
    $('#zaehler').textContent = phIndex < 0 ? `${n} offen` : `${phIndex + 1} von ${n}`;
    $('#entwurf').hidden = n === 0;
  }
  function naechsterPlatzhalter() {
    const alle = platzhalter(); if (!alle.length) return;
    alle.forEach(x => x.classList.remove('ziel'));
    phIndex = (phIndex + 1) % alle.length;
    const z = alle[phIndex];
    z.classList.add('ziel'); z.focus({ preventScroll: true });
    z.scrollIntoView({ behavior: reduziert() ? 'auto' : 'smooth', block: 'center' });
    zaehlen();
  }
  function ankerKopieren(id) {
    const url = location.href.split('#')[0] + '#' + id;
    const fertig = () => melden('Link zum Abschnitt kopiert.');
    if (navigator.clipboard && window.isSecureContext) navigator.clipboard.writeText(url).then(fertig, fertig); else fertig();
    history.replaceState(null, '', '#' + id);
  }

  /* Abschnitt im Blick → Eintrag im Inhalt markieren */
  function markiere(id) {
    const links = $$('#inhalt a'); let ziel = null;
    links.forEach(a => { const an = a.getAttribute('href') === '#' + id; if (an) { a.setAttribute('aria-current', 'location'); ziel = a; } else a.removeAttribute('aria-current'); });
    const m = $('#marker');
    if (m && ziel) { const li = ziel.parentElement; m.style.transform = `translateY(${li.offsetTop}px)`; m.style.height = li.offsetHeight + 'px'; }
  }
  function beobachten() {
    if (beobachter) beobachter.disconnect();
    const ab = $$('#text > section'); if (!ab.length) return;
    const sichtbar = new Map();
    beobachter = new IntersectionObserver(es => {
      es.forEach(e => sichtbar.set(e.target.id, e.isIntersecting));
      const erste = ab.find(s => sichtbar.get(s.id));
      if (erste) markiere(erste.id);
    }, { rootMargin: '0px 0px -70% 0px' });
    ab.forEach(s => beobachter.observe(s));
    markiere(ab[0].id);
  }

  /* Sprung mit derselben Kurve, Fokus auf die Überschrift */
  const kurve = t => { // cubic-bezier(0.25, 1, 0.5, 1) näherungsweise per Newton
    const cx = 3 * .25, bx = 3 * (.5 - .25) - cx, ax = 1 - cx - bx, cy = 3 * 1, by = 3 * (1 - 1) - cy, ay = 1 - cy - by;
    let x = t; for (let i = 0; i < 6; i++) { const f = ((ax * x + bx) * x + cx) * x - t, d = (3 * ax * x + 2 * bx) * x + cx; if (Math.abs(d) < 1e-6) break; x -= f / d; }
    return ((ay * x + by) * x + cy) * x;
  };
  let rollen = null;
  function springe(id, fokus = true) {
    const ziel = document.getElementById(id); if (!ziel) return;
    const y0 = scrollY, y1 = Math.max(0, ziel.getBoundingClientRect().top + scrollY - 20);
    cancelAnimationFrame(rollen);
    const ende = () => { if (fokus) { const hh = ziel.querySelector('h2'); if (hh) hh.focus({ preventScroll: true }); } };
    if (reduziert()) { scrollTo(0, y1); ende(); return; }
    const t0 = performance.now(), dauer = 500;
    const schritt = n => { const p = Math.min(1, (n - t0) / dauer); scrollTo(0, y0 + (y1 - y0) * kurve(p)); if (p < 1) rollen = requestAnimationFrame(schritt); else ende(); };
    rollen = requestAnimationFrame(schritt);
  }
  document.addEventListener('click', e => {
    const a = e.target.closest('#inhalt a'); if (!a) return;
    e.preventDefault(); const id = a.getAttribute('href').slice(1);
    history.replaceState(null, '', '#' + id); springe(id);
    if (matchMedia('(max-width: 860px)').matches) $('#inhalt-details').open = false;
  });
  $$('[data-zu]').forEach(a => a.addEventListener('click', e => { e.preventDefault(); setzeV(a.dataset.zu, true); scrollTo(0, 0); }));

  // Inhaltsverzeichnis: am Desktop offen, am Telefon zugeklappt
  const schmal = matchMedia('(max-width: 860px)');
  const nav = () => { $('#inhalt-details').open = !schmal.matches; };
  nav(); schmal.addEventListener('change', nav);
  addEventListener('scroll', () => $('#nach-oben').classList.toggle('an', scrollY > 700), { passive: true });
  $('#nach-oben').addEventListener('click', e => { e.preventDefault(); if (reduziert()) scrollTo(0, 0); else scrollTo({ top: 0, behavior: 'smooth' }); $('#titel').focus({ preventScroll: true }); });
  $('#naechster').addEventListener('click', naechsterPlatzhalter);
  $('#drucken').addEventListener('click', () => window.print());

  function setzeV(neu, schreiben) {
    v = neu;
    $$('#pult-v button').forEach(b => b.setAttribute('aria-pressed', b.dataset.v === v));
    $$('.fuss [data-zu]').forEach(a => a.toggleAttribute('aria-current', a.dataset.zu === v));
    if (schreiben) { const q = new URLSearchParams(location.search); q.set('v', v); history.replaceState(null, '', location.pathname + '?' + q); }
    zeichne();
  }
  $$('#pult-v button').forEach(b => b.addEventListener('click', () => setzeV(b.dataset.v, true)));
  function schalter(id, klasse, umkehr) {
    const b = $(id);
    b.addEventListener('click', () => { const an = b.getAttribute('aria-pressed') !== 'true'; b.setAttribute('aria-pressed', an); b.lastElementChild.textContent = an ? 'an' : 'aus'; h.classList.toggle(klasse, umkehr ? !an : an); if (klasse === 'druckansicht') beobachten(); });
  }
  schalter('#pult-trennung', 'ohne-trennung', true);
  schalter('#pult-druck', 'druckansicht', false);

  setzeV(v, false);
  if (location.hash && document.getElementById(location.hash.slice(1))) setTimeout(() => springe(location.hash.slice(1)), 50);

  /* Vorführung: durch die Abschnitte fahren, Platzhalter anspringen, Anker kopieren */
  let uhren = [];
  const spaeter = (f, ms) => uhren.push(setTimeout(f, ms));
  function stopp() { uhren.forEach(clearTimeout); uhren = []; cancelAnimationFrame(rollen); }
  function neustart() { stopp(); $$('.ziel').forEach(x => x.classList.remove('ziel')); phIndex = -1; zaehlen(); scrollTo(0, 0); markiere(($('#text > section') || {}).id); }
  function vorfuehren() {
    neustart();
    h.classList.add('vorfuehrung');
    if (v === 'datenschutz') {
      const ids = ['aufruf', 'anfrage', 'dienste', 'aenderungen'];
      ids.forEach((id, i) => spaeter(() => springe(id, false), 1400 + i * 1900));
      spaeter(() => { const b = $('#aenderungen .anker'); if (b) { b.style.opacity = 1; b.style.borderColor = 'var(--text)'; melden('Link zum Abschnitt kopiert.'); spaeter(() => { b.style.opacity = ''; b.style.borderColor = ''; }, 900); } }, 1400 + 4 * 1900);
      spaeter(() => springe('verantwortlich', false), 11000);
      spaeter(vorfuehren, 13400);
    } else {
      [0, 1, 2, 3].forEach(i => spaeter(naechsterPlatzhalter, 1200 + i * 1500));
      spaeter(() => { $$('.ziel').forEach(x => x.classList.remove('ziel')); scrollTo({ top: 0, behavior: reduziert() ? 'auto' : 'smooth' }); }, 7600);
      spaeter(vorfuehren, 9200);
    }
  }
  function pause() { stopp(); h.classList.remove('vorfuehrung'); }
  function weiter() { vorfuehren(); }

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