diff --git a/CLAUDE.md b/CLAUDE.md
index bbd4c56..b5078ae 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -11,7 +11,7 @@ Dieses Dokument beschreibt Architektur, Konventionen und wichtige Implementierun
- **Einstiegspunkt:** `index.html`
- **Styles:** `css/styles.css` (Layout & Komponenten) + `css/tokens.css` (Design-Tokens)
- **Logik:** `js/app.js` (eine einzige Datei)
-- **Aktuelle Version:** `v69` (Script-Tag: `
+
```
### Externe Aufrufe
@@ -37,7 +37,7 @@ Dass daraus **keine Inhalte** abfließen können, ist kein Zufall, sondern eine
> ⚠️ **Die Zusagen im Markup müssen dazu passen.** Hero-Badge, Feature-Karte „Local-First" und die FAQ-Antwort „Verlassen meine Daten den Browser?" sprechen deshalb von *Inhalten*, die im Browser bleiben, und benennen die Zählung ausdrücklich. Die FAQ-Antwort steht **zweimal** in `index.html` – sichtbar und im `FAQPage`-Markup – und muss wörtlich übereinstimmen (ein Test prüft das).
-> ⚠️ **Das Ladegewicht-Budget zählt den Zähl-Aufruf NICHT mit.** Bis v68 tat es das – und maß damit das Netz statt das Repo: in der CI ging der Aufruf durch und brachte rund 9 KB mit, im Entwicklungscontainer sperrt die Netzwerkrichtlinie ihn. Derselbe Commit lieferte zwei verschiedene Zahlen, und dieselbe Grenze war einmal eingehalten und einmal gerissen. Gefiltert wird **beim Zählen**, ausdrücklich nicht über `page.route()`: ein Interceptor umgeht den Speicher-Cache, danach lädt `logo.svg` (106 KB) zweimal – einmal für die Topbar, einmal für den Hero – und die Messung ist um genau diesen Betrag falsch. Die Grenze selbst (700 KB) steht seit v45 unverändert.
+> ⚠️ **Das Ladegewicht-Budget zählt den Zähl-Aufruf NICHT mit.** Bis v68 tat es das – und maß damit das Netz statt das Repo: in der CI ging der Aufruf durch und brachte rund 9 KB mit, im Entwicklungscontainer sperrt die Netzwerkrichtlinie ihn. Derselbe Commit lieferte zwei verschiedene Zahlen, und dieselbe Grenze war einmal eingehalten und einmal gerissen. Gefiltert wird **beim Zählen**, ausdrücklich nicht über `page.route()`: ein Interceptor umgeht den Speicher-Cache, danach lädt `logo.svg` (106 KB) zweimal – einmal für die Topbar, einmal für den Hero – und die Messung ist um genau diesen Betrag falsch. Die Grenze selbst (700 KB) steht seit v45 unverändert. **Stand v70: rund 5,5 KB Luft.** Der Rundgang brachte 17 KB Code und Text mit und riss die Grenze; zurückgeholt wurde der Platz nicht durch eine höhere Grenze, sondern indem das DatenGraf-Logo unter dem Falz tatsächlich erst bei Bedarf lädt. Die nächsten echten Hebel sind `logo.svg` (108 KB, reine Pfadgeometrie) und `favicon.svg` (126 KB, fällt meist erst nach `networkidle` an und deshalb nicht ins Budget, wird aber von jedem Besucher geladen).
**Im Test abgeklemmt:** `openApp()` beantwortet die Zähl-Hosts mit einem leeren Skript (`route.fulfill`, nicht `abort` – ein abgebrochener Aufruf schriebe „Failed to load resource" in die Konsole). Sonst schriebe jeder Lauf hunderte Aufrufe in die echte Statistik.
@@ -68,7 +68,7 @@ Die App hat keinen Build-Schritt – getestet wird **die ausgelieferte App**, al
```bash
npm install # nur Dev: @playwright/test (exakt gepinnt)
npx playwright install chromium # einmalig
-npm test # 380 Tests, ~150 s
+npm test # 386 Tests, ~180 s
npm run test:ui # interaktiver Modus
```
@@ -88,7 +88,7 @@ npm run test:ui # interaktiver Modus
| `tests/a11y.spec.js` | Skip-Link, Fokus-Falle, Tab-Order der Seitenleiste, ARIA-Tabs, Kontrast (Ampel-Text-Tokens, gemessen statt behauptet), `[hidden]` gegen **jede** Klasse mit eigenem `display`, Überlauf bei 360/375/390 px |
| `tests/hvd.spec.js` | amtliches Vokabular (96 Konzepte, sechs Codes wörtlich), Dropdown-Gruppierung, v46-Migration, Einstufung bleibt manuell, alle Pflichten der DVO (EU) 2023/138, Export nur gemeinsam, CSV-/Katalog-Round-Trip |
| `tests/risiko.spec.js` | k-Anonymität/l-Diversität gegen Handrechnung, Trenner-Kollision, Normalisierung, Ampelschwellen, Modellfehler (sensibles Merkmal = QI), Tab/ARIA, Übergabe aus der Bereinigung |
-| `tests/tour.spec.js` | Rundgang: alle Schritte, Zielelemente existieren wirklich, Escape und Pfeiltasten, Schritte ohne Daten bieten den Import an |
+| `tests/tour.spec.js` | Rundgang: Kapitelstruktur und -sprung, jeder Bereich und Tab wird gezeigt und ist sichtbar, **Karte verdeckt das Ziel nicht** (Desktop, gemessen), Telefon: Anfang des Ziels bleibt frei, **Ziel liegt über dem Abdunkeln** (per `elementFromPoint`, auch in Topbar/Seitenleiste), Schritte ohne Daten, Escape und Pfeiltasten |
| `tests/seo.spec.js` | statische Seiten aktuell (`--check`), Metadaten je Seite, `.static-hero`, Sitemap vollständig, Google-Bestätigungsdatei, Datenschutzerklärung ohne JavaScript |
| `tests/assets.spec.js` | Icon-Zuschnitt (CSS-Abgleich, echtes Rendern auf Canvas, `font-display: swap`, keine Brands-Schrift), Ladegewicht-Budget der Startseite (**ohne** den fremden Zähl-Aufruf, siehe unten) |
@@ -120,7 +120,7 @@ Spätere Module hängen sich an `inventory` an: Modul 3a (Clearing) bewertet die
**Startseiten-Abschnitte tragen `.home-only`.** `showView()` blendet sie über genau eine Abfrage aus (`document.querySelectorAll('.home-only')`) statt über eine Liste von IDs plus einen Sonderfall für `.consult-cta` – bis v65 wäre ein neuer Startseiten-Abschnitt auf allen Unterseiten stehen geblieben, ohne dass etwas rot geworden wäre. Aktuell: `#hero`, `#hero-steps`, `#about-accordion`, `#module-grid`, `.consult-cta`. Ein Test geht alle sechs Unterseiten durch und verlangt, dass keines davon sichtbar bleibt.
-Sieben Views: `home` (Hero + Schritte + Akkordeon + Modul-Grid), `kompass` (Daten-Kompass), `inventory` (Inventar/Clearing/Qualität-Tabs), `governance` (RACI + Reifegrad), `pseudo` (Textbereinigung, drei Tabs), `wissen` (Wissens- & Methodik-Center) und `vorlagen` (Vorlagen & Musterdokumente). Zentral über `showView(name)` umgeschaltet (blendet die Home-Elemente per `style.display` aus, toggelt `.hidden` an `#kompass-view`/`#inventory-view`/`#governance-view`/`#pseudo-view`/`#wissen-view`/`#vorlagen-view`, blendet den Phase-4&5-Beratungsblock `.consult-cta` außerhalb von `home` aus, scrollt nach oben). `navTo(target)` kapselt die Navigations-Einstiege (Topbar-Brand → home, Hero-CTA + Topbar-„Loslegen" → kompass, Sidebar-Links `data-view`, Modul-Buttons; „Dateninventar" öffnet ohne Daten das Erklär-Modal, `kompass`/`governance`/`pseudo`/`wissen`/`vorlagen` jederzeit).
+Sieben Views: `home` (Hero + Schritte + Akkordeon + Modul-Grid), `kompass` (Daten-Kompass), `inventory` (Inventar/Clearing/Qualität-Tabs), `governance` (RACI + Reifegrad), `pseudo` (Textbereinigung, drei Tabs), `wissen` (Wissens- & Methodik-Center) und `vorlagen` (Vorlagen & Musterdokumente). Zentral über `showView(name)` umgeschaltet (blendet die Home-Elemente per `style.display` aus, toggelt `.hidden` an `#kompass-view`/`#inventory-view`/`#governance-view`/`#pseudo-view`/`#wissen-view`/`#vorlagen-view`, blendet den Phase-4&5-Beratungsblock `.consult-cta` außerhalb von `home` aus, scrollt nach oben). `navTo(target)` kapselt die Navigations-Einstiege (Topbar-Brand → home, Hero-„Sofort loslegen" + Topbar-„Daten-Kompass" → kompass, Sidebar-Links `data-view`, Modul-Buttons; „Dateninventar" öffnet ohne Daten das Erklär-Modal, `kompass`/`governance`/`pseudo`/`wissen`/`vorlagen` jederzeit).
**Status-Dashboard (Startseite):** `#dashboard` erscheint auf `home`, sobald Daten vorliegen (`hasAnyData()`), sonst bleibt es per `.hidden` ausgeblendet (Erstnutzer sehen Hero + Module). `refreshDashboard()` (in `showView('home')` und beim Laden nach `loadState()`) toggelt Sichtbarkeit und ruft `renderDashboard()`, das vier Live-Kennzahl-Karten füllt: Daten-Kompass (`kompassOverall()` % + `kompassAmpel`), Governance (`reifegrad().score` % + `reifeAmpel`, „offen" ohne Antworten), Inventar (Anzahl + Ø `completeness`), Risiko-Clearing (Ampelverteilung via `ensureAllClearing()`). Jede Karte ist ein `[data-go]`-Schnellsprung. **Wichtig:** `[data-go]` ist **delegiert** an `document` gebunden (nicht pro Element), damit dynamisch gerenderte Dashboard-Karten ebenfalls greifen.
@@ -447,7 +447,13 @@ Der Verlauf steckt **additiv** in `buildProjectJSON()` (kein Schema-Bump – äl
### Onboarding-Rundgang
-Geführter Durchlauf durch die Bausteine (`TOUR_STEPS`, `tour = { i, active }`). `startTour()` / `tourGo(±1)` / `endTour()`; `renderTour()` navigiert je Schritt via `navTo()`, hebt ein Ziel per `.tour-highlight` hervor (z-index über dem abdunkelnden `#tour-layer`) und baut die Karte `#tour-card` (`role="dialog"`, `aria-modal`). Escape und Pfeiltasten sind gebunden. **`trapFocus()` greift auch hier** – die Funktion sucht in `.modal-backdrop` *und* `.tour-layer`: `aria-modal` blendet den Rest für Screenreader aus, per Tab konnte man ihn vorher trotzdem verlassen und landete in einer Seite, die für sie gar nicht existiert.
+Geführter Durchlauf durch **alle** Bereiche, seit v70 in **sieben Kapiteln** (`TOUR_KAPITEL`: Orientierung, Daten-Kompass, Phase 1–3, Wissen & Vorlagen, Sichern & loslegen) mit 29 Schritten (`TOUR_STEPS`, je `{ id, kap, view, target, title, text }`, optional `invTab`, `pseudoTab`, `openSidebar`, `needsData`, `angebot`). `startTour(kapitel?)` / `tourGo(±1)` / `tourKapitel(id)` / `endTour()`; `renderTour()` navigiert je Schritt via `navTo()`, schaltet bei Bedarf in den passenden Tab (`showInventoryTab`, `showPseudoTab`), hebt das Ziel per `.tour-highlight` hervor und baut die Karte `#tour-card` (`role="dialog"`, `aria-modal`). Der erste Schritt listet alle Kapitel zum Direktanspringen, jede Karte trägt Kapitelpunkte (`.tour-dot`, `aria-current="step"`) und einen Fortschrittsbalken.
+
+- **Die Karte steht neben dem Ziel** (`placeTourCard()`): bevorzugt darunter, sonst darüber, links oder rechts – je nachdem, wo sie ganz in den Sichtbereich passt (`data-place`). Ohne Ziel steht sie mittig (`mitte`), unter 720 px Breite dockt sie an (`dock` unten, `dock-oben`, wenn das Ziel in der unteren Hälfte beginnt). Bis v69 stand sie immer unten mittig und verdeckte bei großen Zielen genau das, was sie erklären sollte.
+- **Erst messen, dann scrollen, dann platzieren.** `scrollTourZiel(ziel, kartenHoehe)` scrollt so, dass Ziel **und** Karte gemeinsam Platz haben; stures Zentrieren ließ bei einem 300 px hohen Ziel keinen Raum für die Karte. Gescrollt wird ohne Animation – sonst wäre die Platzierung während des Scrollens falsch. Scroll und Größenänderung führen die Karte nach (`tourNachfuehren`, ein Frame).
+- **Ohne Inventar** liefert `tourSteps()` von den `needsData`-Schritten nur den mit `angebot`: er zeigt die Inventar-Karte der Startseite und bietet das Beispiel an. `navTo('inventory')` würde ohne Daten das Erklär-Modal öffnen – hinter der Karte; deshalb navigiert dieser Schritt nach `home`. Nach dem Laden (`loadSampleData()` gibt seit v70 das Promise zurück) wächst die Liste, und der Rundgang bleibt auf derselben `id`. Escape und Pfeiltasten sind gebunden. **`trapFocus()` greift auch hier** – die Funktion sucht in `.modal-backdrop` *und* `.tour-layer`: `aria-modal` blendet den Rest für Screenreader aus, per Tab konnte man ihn vorher trotzdem verlassen und landete in einer Seite, die für sie gar nicht existiert.
+
+> ⚠️ **Ziele in Topbar und Seitenleiste blieben bis v69 abgedunkelt.** Die sticky Topbar (`z-index: 10`) und die fixierte Seitenleiste (`300`) bilden eigene Stapelkontexte – ein Element darin kommt nie über deren Wert hinaus, egal welchen `z-index` es selbst trägt. Beim Schritt „Arbeitsstand sichern" lag die hervorgehobene Schaltfläche deshalb **unter** dem Abdunkeln. `tourLift()` hebt den **äußersten** Vorfahren mit eigenem Stapelkontext (`bildetStapelkontext()`: fixed/sticky, positioniert mit z-index, transform, filter, backdrop-filter, opacity, isolation) per `.tour-lift` auf 1201. `.tour-highlight` setzt `position: relative` nur noch, wenn das Ziel statisch ist (`.tour-pos`) – sonst verlöre die sticky Topbar ihre Positionierung. Der Test macht das Abdunkeln klickbar und prüft mit `elementFromPoint`, was **oben** liegt; eine Prüfung auf Klassen hätte den Fehler nie gesehen.
> ⚠️ **Die Stapelreihenfolge ist dreiteilig und hängt an einer Eigenheit von `position: fixed`.** Ein fixiertes Element bildet einen **eigenen Stapelkontext** – die Karte in `#tour-layer` kann dessen `z-index` also nie überbieten, egal welchen Wert sie selbst trägt. Bis v65 stand das Abdunkeln am Layer (1200) und `.tour-highlight` darüber (1201); das hervorgehobene Zielelement zeichnete damit **in die Karte hinein** (bei Schritt 3 stand der Fragebogentext über Titel und Knöpfen) und fing dort auch die Klicks ab. Seit v66 gilt: **Abdunkeln `body.tour-on::before` (1200) < Hervorhebung (1201) < Layer mit Karte (1202)**. Das Abdunkeln muss dafür *außerhalb* des Layers liegen – daher die Body-Klasse, die `startTour()` setzt und `endTour()` entfernt (sonst bliebe die Seite dauerhaft dunkel).
@@ -484,7 +490,7 @@ Dazu drei Einträge in `PRUEF_WERKZEUGE` und einer in `METHOD_MODELS`:
### Daten-Kompass
-Eigene View `#kompass-view` und **Haupt-CTA** (Hero-Button + Topbar-„Loslegen"). Eine ausführliche Open-Data-Reifegrad-Checkliste nach anerkannten Modellen: **World-Bank ODRA**, **EU Open Data Maturity**, **5-Sterne-Open-Data** (Berners-Lee), **DCAT-AP.de** und **DSGVO/FAIR** sowie **Data Orchard Data Maturity** (Quellen im UI unter „Methodik & Quellen").
+Eigene View `#kompass-view` und **Haupt-CTA** (Hero-„Sofort loslegen" + Topbar-„Daten-Kompass"). Eine ausführliche Open-Data-Reifegrad-Checkliste nach anerkannten Modellen: **World-Bank ODRA**, **EU Open Data Maturity**, **5-Sterne-Open-Data** (Berners-Lee), **DCAT-AP.de** und **DSGVO/FAIR** sowie **Data Orchard Data Maturity** (Quellen im UI unter „Methodik & Quellen").
- **Struktur:** `KOMPASS_DIMENSIONS` (8 Dimensionen × je 3–5 Items, 33 Prüfpunkte). Status je Item: `offen` / `teilweise` / `erfuellt` / `na`.
- **Score:** `kompassDimScore()` und `kompassOverall()` = Ø der Faktoren (erfüllt 1, teilweise 0,5, offen 0; `na` ausgenommen), 0–100. Ampel `kompassAmpel()`: ≥ 80 „Fortgeschritten", ≥ 50 „Im Aufbau", sonst „Am Anfang".
@@ -518,7 +524,7 @@ Eigener Startseiten-Abschnitt **unterhalb der Modul-Karten** (`.graf-bridge`/`.g
Der Abschnitt erklärt jetzt auch, **was** die Brücke leistet (`GRAF_COLUMNS` 1:1, Vorbelegung von `accessRights` und `accrualPeriodicity` aus der Kartierung, nachzuerfassen bleiben Lizenz, Schlagwörter und Adresse) und bietet zwei Wege: `#graf-bridge-import` → **direkt** `pickAndImport()` (nicht über `openInventoryModal()` – wer kartiert hat, braucht das Erklär-Modal nicht mehr) und einen Verweis auf DatenGraf für alle, die noch nicht kartiert haben.
-**Das Zeichen ist seit v69 das echte DatenGraf-Logo** (`datengraf-logo.svg`, lokal im Repo – die beiden Werkzeuge teilen ihre Bildsprache, und das Logo sagt sofort, wovon die Rede ist). Runde Fassung wie `.hero-logo`, damit die beiden als Geschwister lesbar bleiben. Die Datei stammt aus dem DatenGraf-Repo und wird **lokal ausgeliefert** – ein Hotlink auf `datengraf.nozilla.net` wäre ein zweiter externer Aufruf und würde den Test „null externe Requests" rot machen. Ein Test prüft Quelle, Alt-Text und dass das Bild wirklich lädt (`naturalWidth > 0`); ein ``, das 404 liefert, sähe im Markup korrekt aus.
+**Das Zeichen ist seit v69 das echte DatenGraf-Logo** (`datengraf-logo.svg`, lokal im Repo – die beiden Werkzeuge teilen ihre Bildsprache, und das Logo sagt sofort, wovon die Rede ist). Runde Fassung wie `.hero-logo`, damit die beiden als Geschwister lesbar bleiben. Die Datei stammt aus dem DatenGraf-Repo und wird **lokal ausgeliefert** – ein Hotlink auf `datengraf.nozilla.net` wäre ein zweiter externer Aufruf und würde den Test „null externe Requests" rot machen. Ein Test prüft Quelle, Alt-Text und dass das Bild wirklich lädt (`naturalWidth > 0`); ein `
`, das 404 liefert, sähe im Markup korrekt aus. **Seit v70 lädt es erst in der Nähe des Sichtbereichs** (`data-src` + `IntersectionObserver`, 400 px Vorlauf): `loading="lazy"` allein half nicht, weil Chrome Bilder schon in 1.250–2.500 px Abstand vorlädt – das Logo kam bei jedem Aufruf mit (21 KB). Der Test wartet deshalb auf das Laden, statt sofort zu messen; ohne das war er ein Wettlauf und in der vollen Suite gelegentlich rot.
### Hero je Ansicht (`.view-hero`, `.hero-panel`)
@@ -639,7 +645,7 @@ Nach Änderungen an `app.js` `?v=N` im Script-Tag **und** die `v{N}` im Footer e
| Hochwertige Datensätze (HVD) | `hvdIssues()`, `guessHvd()`, `hvdVorschlaege()`, `hvdCategoryUri()`, `hvdFromURI()`, `hvdSelectHTML()`, `migrateHvd()`, `renderHvdHinweise()`, `HVD_CATEGORIES`, `HVD_META`, `HVD_LICENSES`, `HVD_ELI`, `HVD_BNA` | `[data-field="hvd"]`, `.inv-hvd`, `.inv-hvd-uri`, `#quality-hvd`, `.qual-hvd` |
| DCAT-AP.de-Qualitätsprüfung | `validateDataset(d)`, `qualityStatus()`, `renderQuality()`, `jumpToInventoryCard(idx)` | `#tab-quality`, `#quality-panel`, `#quality-summary`, `.qual-card`, `.qual-fix` |
| Wissens- & Methodik-Center | `renderWissen()`, `GLOSSARY`, `LEGAL_BASIS`, `LEGAL_BASIS_LAENDER`, `LAENDER_KIND`, `KOMMUNAL_SATZUNGEN`, `METHOD_MODELS`, `wissenFilter` | `#wissen-view`, `#wissen-search`, `#wissen-land`, `#wissen-glossary`, `#wissen-laws`, `#wissen-laender`, `#wissen-kommunal`, `#wissen-models` |
-| Onboarding-Rundgang | `startTour()`, `endTour()`, `tourGo()`, `renderTour()`, `TOUR_STEPS`, `tour` (State) | `#tour-layer`, `#tour-card`, `#hero-tour-btn`, `#sidebar-tour`, `.tour-highlight` |
+| Onboarding-Rundgang | `startTour()`, `endTour()`, `tourGo()`, `tourKapitel()`, `renderTour()`, `tourSteps()`, `placeTourCard()`, `scrollTourZiel()`, `tourLift()`, `TOUR_KAPITEL`, `TOUR_STEPS`, `tour` (State) | `#tour-layer`, `#tour-card[data-place]`, `.tour-chapter`, `.tour-dot`, `.tour-progress`, `#hero-tour-btn`, `#sidebar-tour`, `.tour-highlight`, `.tour-lift` |
| Vorlagen & Musterdokumente | `generateDoc(doc, fmt)`, `printDoc()`, `docShell()`, `policyBodyHTML/Markdown`, `dsfaBodyHTML/Markdown`, `freigabeBodyHTML`, `vvtBodyHTML/CSV`, `orgName()` | `#vorlagen-view`, `.vorlage-card`, `[data-doc][data-fmt]` |
| Status-Einseiter | `statusKennzahlen()`, `statusNaechsteSchritte()`, `statusBodyHTML()` | `[data-doc="status"]` |
| PDF-Bericht Inventar/Clearing | `buildInventoryReportHTML()`, `printInventoryReport()` | `#btn-print-inventory` |
@@ -701,6 +707,7 @@ Nach Änderungen an `app.js` `?v=N` im Script-Tag **und** die `v{N}` im Footer e
| v16 | Daten-Kompass (Herzstück) – eigene View + Hero-Haupt-CTA (Topbar-„Loslegen" zeigt ebenfalls darauf): ausführliche Open-Data-Reifegrad-Checkliste nach ODRA / EU Open Data Maturity / 5-Sterne / DCAT-AP.de / DSGVO·FAIR (7 Dimensionen, Quellenangaben), Status je Item mit Score & Ampel, Vorbelegung aus dem App-Stand, adaptive Sprünge in die passenden Bausteine, Persistenz (`datenlotse_kompass`) und PDF-Export; leeres „Loslegen"-Platzhalter-Modal entfernt |
| v17 | Weiterer Ausbau (1/4) – Inventar Suche, Filter & Sortierung: `renderInventory()` in `renderInventory()` + `renderInventoryBody()` aufgeteilt; `.inv-controls` (Volltextsuche + Schutzbedarf-/Clearing-Ampel-Filter + Sortierung Titel/Vollständigkeit) über `invFilter`-State und `filteredInventory()`; der echte `idx` wird durch den Filter mitgeführt, sodass Editieren über gefilterten Teilmengen weiterhin den richtigen Datensatz trifft; Live-Meta „X von Y" + Empty-State |
| v18 | Weiterer Ausbau (2/4) – Pseudonymisierung erweitert: drei neue Muster (Sozialversicherungsnummer, Steuer-ID *kontextgetriggert*, Kfz-Kennzeichen), Aktenzeichen um Geschäftszeichen/„Gz." und buchstabenhaltige Kerne erweitert, zusätzliche Geburtsdatum-Trigger („Geburtsdatum"/„Geburtstag"); Mapping-Export als CSV (`buildPseudoMappingCSV` + Button im Mapping-Kopf); Demo-Text und Grenzen-Liste aktualisiert; verifiziert auf Determinismus, Platzhalter-Konsistenz und Null-Falschtreffer auf neutralem Verwaltungstext |
+| v70 | **Ein Rundgang durch alles – mit der Karte am Ziel.** Der Rundgang bestand aus elf Stichproben und hatte drei Mängel, die sich erst beim Durchklicken zeigten. **(1)** Die Karte stand immer unten mittig; bei großen Zielen verdeckte sie, was sie erklären sollte. Jetzt steht sie daneben – darunter, darüber, links oder rechts, je nachdem, wo sie ganz hinpasst –, und gescrollt wird so, dass Ziel und Karte gemeinsam Platz haben: stures Zentrieren ließ bei einem 300 px hohen Ziel keinen Raum. Auf drei Desktop-Größen verdeckt die Karte in keinem der 29 Schritte ihr Ziel, gemessen. **(2)** Ziele in Topbar und Seitenleiste blieben **unter dem Abdunkeln** – beide bilden eigene Stapelkontexte, ein Element darin kommt nie über deren `z-index` hinaus. Gehoben wird jetzt der äußerste solche Vorfahr; der Test macht das Abdunkeln klickbar und fragt `elementFromPoint`, was oben liegt. **(3)** Ohne Daten öffnete ein Inventar-Schritt über `navTo('inventory')` das Erklär-Modal **hinter** der Karte. Inhaltlich: **sieben Kapitel, 29 Schritte**, mit Kapitelauswahl am Anfang, Kapitelpunkten und Fortschrittsbalken; die Schritte wechseln selbst in den passenden Tab und decken jetzt auch Rechtspflicht, Kompass-Verlauf, RACI, Verteilungen, Filter und Massenbearbeitung, Lizenz-Kompatibilität, Metadaten-Güte, Exporte, k-Anonymität, die zwei Leserichtungen der Landesgesetze und die DatenGraf-Brücke ab. Ohne Inventar bleibt von den datenabhängigen Schritten nur das eine Angebot, statt siebenmal denselben Hinweis zu zeigen. Drei Texte waren veraltet: der Willkommensschritt versprach „keine Übertragung" (seit v48 falsch), der Inventarschritt nannte die Prozentzahl „Vollständigkeit" (seit v63 Metadaten-Güte), der letzte verwies nur auf die Seitenleiste. **Das Ladegewicht-Budget riss** – wie in v69 angekündigt, die 17 KB des Rundgangs passten nicht in 5 KB Luft. Die Grenze blieb; stattdessen lädt das DatenGraf-Logo unter dem Falz jetzt wirklich erst bei Bedarf (`loading="lazy"` griff wegen Chromes Vorlade-Abstand nie). Nebenbei war der Logo-Test seit v69 ein Wettlauf gegen das Netz. **Mutationen:** acht einzeln geprüft, sieben wurden rot. Die achte – ein Nachführen der Karte nach dem Hereingleiten der Seitenleiste – blieb grün; nachgemessen auf drei Breiten war das Ergebnis mit und ohne identisch, der Fehler lag im Test (er maß während des Übergangs). Die wirkungslose Zeile ist entfernt statt als scheinbare Absicherung stehen geblieben. 6 neue Tests, acht bestehende auf die Kapitelstruktur umgeschrieben. |
| v69 | **Das echte DatenGraf-Logo.** v68 musste sich mit `fa-circle-nodes` behelfen, weil die Netzwerkrichtlinie `datengraf.nozilla.net` sperrt und der Repo-Zugriff dieser Sitzung nicht über `daimpad/datenlotse` hinausreicht. Der Nutzer hat die Rohdatei-Adresse nachgereicht; das Logo liegt jetzt als `datengraf-logo.svg` **im Repo** und wird lokal ausgeliefert – ein Hotlink wäre ein zweiter externer Aufruf und machte den Test „null externe Requests" rot. Vor dem Übernehmen geprüft: kein `
-
+
diff --git a/index.html b/index.html
index f36a1e0..ce4dc6d 100644
--- a/index.html
+++ b/index.html
@@ -125,10 +125,10 @@
-
+
-
-
+
+
Dann brauchen Sie hier nicht von vorn anzufangen. DatenLotse liest genau das CSV-Schema, das DatenGraf exportiert: Aus jeder Kombination aus Quelle und Datentyp wird ein Datensatz-Kandidat nach DCAT-AP.de – samt Vorbelegung von Zugriffsrechten und Aktualisierungszyklus aus Ihrer Kartierung. Sie ergänzen nur noch, was DatenGraf nicht kennt: Lizenz, Schlagwörter und die Adresse, unter der die Daten liegen.
@@ -915,7 +915,7 @@