# Übergabe – Website Anelia Wolf Stand: 03.09.2026 · Übergabe an die betreuende Agentur Dieses Dokument beschreibt, **was gebaut wurde**, **wie es betrieben wird** und **was vor dem Livegang noch fehlt**. Die technische Kurzfassung für Entwickler steht in `README.md`, die vollständige Begründung jeder Designentscheidung in `docs/superpowers/specs/2026-09-02-anelia-wolf-website-design.md` (Spec) und `docs/superpowers/plans/2026-09-02-anelia-wolf-build-plan.md` (Bauplan). --- ## 1. Was gebaut wurde ### 1.1 Umfang Eine statische Website in **zwei Sprachen**, ohne Backend, ohne Datenbank, ohne Cookie-Banner. Deutsch ist die Originalfassung und liegt auf den bisherigen Adressen, Englisch liegt vollstaendig unter `/en/`: | Route | Inhalt | |---|---| | `/` | Startseite, sechs nummerierte Sektionen: 01 Positionierung · 02 Leistungen · 03 WOLF-Prinzip · 04 Über Anelia · 05 Für wen (mit Termine-Ledger) · 06 Kontakt | | `/leistungen/coaching/` | Coaching & Analysen | | `/leistungen/trainings/` | Trainings & Workshops | | `/leistungen/keynotes/` | Keynotes & Speaking | | `/impressum/` | Impressum | | `/datenschutz/` | Datenschutzerklärung | | 404 | „Diese Fährte endet hier.“ – deutsch, mit englischem Zweizeiler darunter | | `/en/` | English start page | | `/en/services/coaching/` | Coaching & Assessments | | `/en/services/trainings/` | Training & Workshops | | `/en/services/keynotes/` | Keynotes & Speaking | | `/en/imprint/` | Imprint (Übersetzung, verbindlich bleibt `/impressum/`) | | `/en/privacy/` | Privacy (Übersetzung, verbindlich bleibt `/datenschutz/`) | Dazu erzeugt der Build `sitemap.xml`, `robots.txt`, `icon.svg` und `apple-icon.png`. ### 1.2 Technik Next.js 16 (App Router) im **Static Export**, React 19, Tailwind v4, GSAP 3.15 + ScrollTrigger, Lenis (Smooth Scroll), TypeScript. Paketmanager npm. **Bewusste Selbstbeschränkungen** – sie sind keine Kosmetik, die Datenschutzerklärung sagt sie ausdrücklich zu: - **keine externen Requests**: keine Google Fonts, keine CDNs, keine Karten, keine Videos, keine Social-Plugins, kein Analytics, keine iframes. Schriften werden über `next/font` **zur Build-Zeit selbst gehostet** (`out/_next/static/media/*.woff2`). - **kein Storage**: kein localStorage, kein sessionStorage, keine Cookies. Deshalb ist auch kein Cookie-Banner nötig und keiner eingebaut. - **kein Server hinter dem Kontaktformular**, kein Newsletter. Das Formular in Abschnitt 06 setzt aus den Eingaben eine `mailto:`-Nachricht zusammen und übergibt sie dem E-Mail-Programm der Besucherin – es sendet selbst nichts. > Wer eine dieser Zusagen ändert (z. B. ein Analytics-Tool einbaut), **muss** > `src/content/legal.ts` (Ziffer 2, 3 und 6 der Datenschutzerklärung) mit ändern > und braucht in der Regel ein Consent-Banner. ### 1.3 Design-System Alle Tokens stehen an genau einer Stelle: `src/app/globals.css`. **Farben** (aus dem Logo abgeleitet): | Token | Wert | Verwendung | |---|---|---| | `--ink` | `#0f0e0c` | dunkler Grund | | `--ivory` | `#f6f1e8` | heller Grund | | `--bone` | `#eee6d8` | zweiter heller Grund (Termine) | | `--gold` | `#c9a24d` | Gold **nur auf dunklem Grund** (8,05:1 auf Ink) | | `--gold-deep` | `#7d5f1b` | Gold **nur auf hellem Grund** (5,3:1 auf Ivory) | | `--grey-warm` / `--grey-deep` | `#a8a196` / `#5e5a52` | gedämpfter Text dunkel / hell | Gold ist rationiert: Haarlinien, Ziffern, Labels, Striche – nie Fließtext. Die großen Display-Ziffern auf hellem Grund nutzen `--gold-700` (`#a37a2c`, 3,5:1 – zulässig, weil sie mit 147 px als Large Text gelten und dekorativ sind). **Typografie**: Playfair Display (Display, Headlines/Ziffern/Formel/Zitate), Source Sans 3 (Fließtext), DM Mono (Labels, Meta-Zeilen). Gewählt am 06.09.2026 aus dem Vergleich unter `/schrift-test/` (dort Paarung 01). Feste Regel: **die Display-Schrift wird nirgends unter 28 px gesetzt** – kleinere Titel laufen in Source Sans 3. Geprüft, siehe QA-Log. Das Betonungswort einer Headline ist kursiv und auf dunklem Grund zusätzlich golden; auf hellem Grund bleibt es rein typografisch, weil der Gold-Verlauf auf Elfenbein nur auf 2,4:1 käme. Die Regel steht in `globals.css`, nicht in den Komponenten. **Form**: Radius 0, keine Schatten, kein Bold. Die Seite ist aus Haarlinien gebaut. Die Grenze zwischen zwei Farbblöcken ist eine 1 px Gold-Haarlinie. **Grund/Theme (wichtig für spätere Eingriffe)**: Jedes Themenblock-Element (`[data-theme="dark"|"light"]`) malt **seinen eigenen, deckenden Grund**. Es gibt **kein JavaScript, das Farben umschaltet** – ein früherer Ansatz („ThemeTween“) wurde entfernt, weil Text kurzzeitig auf der falschen Palette landen konnte. Die Regeln dafür stehen in `globals.css` im Block „Ground & boundary (no JS)“. Neue Sektionen brauchen nur ein `data-theme="dark"` oder `"light"` – Grund und Gold-Naht kommen automatisch. ### 1.4 Motion Alle Bewegungen laufen über GSAP + ScrollTrigger, Smooth Scroll über Lenis. Die Primitiven liegen in `src/components/motion/`: | Komponente | Aufgabe | |---|---| | `Reveal`, `Lines` | Einblenden von Blöcken und Zeilen beim Scrollen (nur `opacity`/`y`) | | `Rule` | die Gold-Haarlinie, die sich beim Erscheinen aufzieht | | `Draw` | Strichanimation des Wolf-Monogramms | | `Door`, `Curtain` | Seitenübergänge | | `Magnet` | leichter Cursor-Magnetismus auf Buttons | | `ScrollProgress` | 1 px Fortschrittslinie unter dem Header | | `TransitionLink` | Links mit Übergang + Anker-Offset | **Barrierefreiheit der Motion**: Reveals animieren ausschließlich `opacity` (und `y`) – nie `visibility`/`autoAlpha`, damit noch nicht sichtbare Elemente in der Tab-Reihenfolge bleiben. `prefers-reduced-motion` ist überall über `gsap.matchMedia` behandelt; die Formel-Sektion (300 svh Sticky-Bühne) fällt dabei auf ihre natürliche Höhe zusammen. Fokusring: 2 px, sichtbar auf beiden Gründen. Ein „Zum Inhalt springen“-Link liegt vor dem Header. ### 1.5 Inhalte **Sämtliche Texte liegen in `src/content/*.ts`** (`home`, `coaching`, `trainings`, `keynotes`, `legal`, `chrome`, `not-found`). Wer Copy ändert, ändert dort – nie im JSX. Stammdaten (Name, E-Mail, Telefon, LinkedIn, Navigation, Routen) liegen in `src/lib/site.ts`. Die englischen Texte liegen daneben in `src/content/en/` – Datei für Datei dieselbe Struktur. Erzwungen wird das über den Typ: jede deutsche Inhaltsdatei exportiert ihre Form (z. B. `export type CoachingContent = Widen`), die englische Datei erfüllt genau diesen Typ. Fehlt drüben ein Feld oder heisst es anders, schlägt `npx tsc --noEmit` fehl – die Fassungen können also nicht auseinanderlaufen. `Widen` (`src/content/widen.ts`) macht dabei aus den `as const`-Literaltypen der deutschen Datei wieder `string`; ohne das wäre „Coaching & Analysen“ der Typ und nicht der Wert. --- ### 1.6 Zwei Sprachen Deutsch ist die Originalfassung, Englisch die Uebersetzung. Beide sind vollstaendig – es gibt keine Seite, die nur in einer Sprache existiert. **Adressen.** Deutsch bleibt auf `/`, `/leistungen/…`, `/impressum/`. Englisch bekommt englische Segmente: `/en/`, `/en/services/…`, `/en/imprint/`. Beides steht an genau einer Stelle: `routesByLang` in `src/lib/i18n.ts`. Wer eine Adresse aendert, aendert sie dort – Navigation, Fuss, Sitemap, hreflang und der Sprachumschalter lesen alle aus dieser Tabelle. **Umschalter.** Die beiden Flaggen im Kopf (`LangSwitch.tsx`) fuehren nicht pauschal auf die Startseite, sondern auf das Gegenstueck derselben Seite (`counterpart()`). Unter 1024 px ist im Kopf kein Platz; dort steht der Umschalter im Overlay-Menue. Eine Flagge steht streng genommen fuer ein Land und nicht fuer eine Sprache – deshalb steht das Kuerzel DE/EN daneben und der zugaengliche Name nennt die Sprache ausgeschrieben. **Zwei Wurzel-Layouts.** `app/(de)/layout.tsx` schreibt ``, `app/en/layout.tsx` schreibt ``. Im App Router schreibt nur das Wurzel-Layout das ``-Element, und die Sprache des Dokuments gehoert dort hin (WCAG 3.1.1) – ein `
` weiter unten waere nicht dasselbe. Die Gruppe `(de)` taucht in keiner URL auf. Beide Layouts bestehen nur aus einem Aufruf von `` (`src/components/layout/Shell.tsx`), das Dokument steht also trotzdem nur einmal im Projekt. Zwei Folgen davon: - Ein Sprachwechsel ist ein vollstaendiger Seitenaufbau statt einer Client-Navigation. Bei einem Sprachwechsel ist das richtig – Metadaten, Huelle und Inhalt wechseln ohnehin komplett. - Next kann keine gemeinsame 404 mehr zusammensetzen und faellt ohne Gegenmassnahme auf seine eigene, weisse Fehlerseite zurueck. Deshalb `experimental.globalNotFound` in `next.config.ts` und `src/app/global-not-found.tsx`; diese Datei rendert das ganze Dokument selbst. Sie erzeugt `out/404.html`. **Seitenaufbau nur einmal.** Die Routendateien enthalten nur Metadaten und reichen ihre Inhaltsdatei weiter; der Aufbau steht in `src/components/pages/` (`HomeBody`, `CoachingBody`, `TrainingsBody`, `KeynotesBody`, `NotFoundBody`). Eine Layout-Aenderung wirkt damit in beiden Sprachen, ohne dass jemand daran denken muss. **Rechtstexte.** Verbindlich ist die deutsche Fassung. `/en/imprint/` und `/en/privacy/` sagen das im ersten Abschnitt und verlinken die deutsche Seite. Die Platzhalter sind in beiden Fassungen dieselben Angaben, und der Build-Guard prueft beide Dateien – wer nur die deutsche fuellt, kommt nicht am Launch-Flip vorbei. **Suchmaschinen.** Jede Seite traegt `canonical` auf sich selbst und `hreflang` auf beide Fassungen plus `x-default` auf Deutsch (`alternatesFor()` in `src/lib/i18n.ts`). Die `sitemap.xml` fuehrt alle zwoelf Seiten mit denselben Alternates. --- ## 2. Betrieb: entwickeln, bauen, deployen ```bash npm install npm run dev # Entwicklungsserver http://localhost:3000 npm run lint # ESLint npx tsc --noEmit # Typprüfung npm run build # erzeugt out/ ``` ### Deployment `next.config.ts` setzt `output: "export"` und `trailingSlash: true`. `npm run build` schreibt den Ordner **`out/`** – das ist das komplette Deployment. Vorgehen: 1. `npm run build` 2. **Inhalt von `out/`** (nicht den Ordner selbst) in das Web-Root des Hosters hochladen – FTP, rsync, Git-Deploy, Netlify-Drop, was auch immer. 3. Fertig. **Kein Node-Prozess auf dem Server, kein `next start`, keine Datenbank, keine Umgebungsvariablen.** Es funktioniert damit auf jedem Standard-Hoster (Apache, nginx, Uberspace, Hetzner Webhosting, Netlify, Vercel, IONOS …). **`trailingSlash: true`** bedeutet: jede Route ist ein Ordner mit `index.html` (`out/leistungen/coaching/index.html`). Das ist genau deshalb so gewählt, damit auch „dumme“ Hoster ohne Rewrite-Regeln die Seiten ausliefern. Bitte den Hoster **nicht** so konfigurieren, dass er Trailing Slashes entfernt. **404**: `out/404.html` ist die Fehlerseite. Bei Apache genügt `ErrorDocument 404 /404.html`, Netlify/Vercel finden sie automatisch. Nginx: `error_page 404 /404.html;`. **HTTPS**: Pflicht (die Datenschutzerklärung nennt TLS). Zusätzlich empfohlen: `Strict-Transport-Security`, `X-Content-Type-Options: nosniff`, `Referrer-Policy: strict-origin-when-cross-origin`. Da die Seite keine externen Ressourcen lädt, ist eine sehr strenge Content-Security-Policy möglich. **Domain**: In `src/lib/site.ts` steht `https://anelia-wolf.com`. Dieser Wert speist Canonical-URLs, OpenGraph und `sitemap.xml`. Bei anderer Domain hier ändern und neu bauen. --- ## 3. Bilder und Logo einspielen (Drop-in) ### Logo: erledigt Das Original-Logo der Kundin ist eingebaut. `public/brand/logo-mark.svg` enthält das Monogramm, abgeleitet aus `v3-anelia-wolf-gold.svg`: ohne C2PA-Metadaten (rund 16 KB, die sonst auf jeder Seite mitgeliefert würden), ohne weißes Hintergrundrechteck, ohne Wortmarke, auf die Marke beschnitten, schwarze Flächen auf `currentColor`. Die Original-Koordinaten sind unverändert, deshalb sitzt der Goldverlauf exakt wie im Original. Details stehen in `public/brand/README.md`. Zwei Dinge sind dadurch anders als in der ursprünglichen Spec: - **Die Marke wird als Ganzes aufgewischt, nicht Strich für Strich gezeichnet.** Das Logo besteht aus Flächen, nicht aus Linien; eine Strichanimation wäre darauf unsichtbar. Vor allem aber sind die Teile verzahnt: Die Brust des Wolfs ist der mittlere Strich des W, und das rechte V existiert nur als zwei Fragmente um den Kopf herum. Nacheinander gezeichnet zerfällt die Marke sichtbar in Bruchstücke. Sie wird deshalb in einer Bewegung von oben nach unten aufgedeckt, sodass jedes Zwischenbild ein sauberer Querschnitt der fertigen Marke ist. Das gezeichnete Ersatz-Monogramm (`WolfMark.tsx`) animiert weiterhin als Strich; `src/components/motion/Draw.tsx` entscheidet das automatisch anhand der Datei. - **Die 404-Seite zeigt das vollständige Monogramm.** Die Spec sah dort das W ohne Wolf vor („Hier ist der Wolf nicht."). Aus demselben Grund geht das nicht. Die Zeile heißt jetzt „Diese Fährte endet hier." `public/brand/logo-full.png` (2400 × 1260 px) ist das Social-Preview-Bild und wurde aus demselben Original erzeugt: Monogramm und Wortmarke auf Tinte. Es wird als OpenGraph-Bild ausgeliefert, also beim Teilen auf LinkedIn. Die Wortmarke „ANELIA WOLF" bleibt im Kopf und im Fuß **echter Text** (Source Sans 3, gesperrt) und kein Bild: So bleibt sie bei jeder Fenstergröße scharf, ist vorlesbar und markierbar. ### Alles Weitere Die Seite ist so gebaut, dass **fehlende Assets nichts kaputt machen**: Sie rendert dann eine dokumentierte typografische Alternative. Sobald die Datei im richtigen Ordner mit dem richtigen Namen liegt, wird sie **ohne Codeänderung** verwendet – nur neu bauen. ### `public/brand/` – siehe `public/brand/README.md` | Datei | Anforderung | Fehlt sie, dann … | |---|---|---| | `logo-mark.svg` | nur das W-Monogramm mit Wolfskopf, transparent, **echtes SVG mit Pfaden** | typografisches ``-Monogramm als Platzhalter | | `logo-full.png` | komplettes Logo mit Wordmark, 1200 × 630 px (oder das Doppelte) | kein Social-Preview-Bild in den OpenGraph-Daten | **Nur SVG** für das Monogramm – die Strichanimation braucht echte Pfade, ein PNG wird ignoriert. Keine Gold-Variante nötig (die Seite färbt über `currentColor`). **Kein `