presseportale/dev/frontend/ENTWICKLUNGSKONZEPT-BusinessPortal24-Frontend.md
Kevin Adametz 092ee0e918
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
13-05-2026 Frontend DEV + HUB
2026-05-13 18:11:03 +02:00

691 lines
41 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Entwicklungskonzept BusinessPortal24, Presseecho & presseportale-Hub Frontend
> **Stand:** 13. Mai 2026
> **Domains:** `businessportal24.test` / `.com` · `presseecho.test` / `.de` · `presseportale.test` / `.com` (Hub)
> **Theme-Slugs:** `businessportal24` (warm-rotes Editorial) · `presseecho` (grünes Editorial) · `presseportale` (Hub-Blau · Publisher-Landing)
> **Assets-Dir (geteilt):** `public/build/web/`
> **Ziel:** Editoriales DACH-Pressemitteilungs-Ökosystem mit 1:1-Mockup-Umsetzung. Presseecho nutzt die **gleiche Komponenten-Architektur** wie BP24, der Hub `presseportale.com` ist eine **eigenständige Publisher-Landing** mit klar abgegrenztem Charakter (Hub-Blau + Bernstein, kein Editorial-Feed).
Dieses Dokument beschreibt den aktuellen Stand und die wichtigsten Architektur­entscheidungen der BusinessPortal24-, Presseecho- und presseportale-Hub-Frontend-Entwicklung. Es ist die zentrale Anlaufstelle für alle, die im Frontend weiterarbeiten oder neue Seiten ergänzen.
---
## 1. Zielbild & Designreferenzen
Das Portal folgt einer **editorial-zeitungs-orientierten Ästhetik** mit ruhiger Beige-Surface, klarer Hierarchie über Typografie statt Cards und einer einzigen warm-roten Akzentfarbe.
Presseecho übernimmt **dieselbe Architektur**, tauscht aber das Surface auf grünlich-getintetes Editorial-Off-White und ersetzt die warm-rote Akzentfarbe durch ein dunkles **Forest-Green** (Brand `#345636`). Die Editorial-Akzentfarbe für Eyebrows auf dunklem Grund bleibt warm-amber (`accent-warm: #e8a95f`) das hat sich in der Iteration als beste Lesbarkeit auf den dunklen Forest-Panels bewährt.
| Datei | Zweck |
| --- | --- |
| `dev/frontend/Pass B _ _ Deutschland _aktiv.png` | Visuelle Referenz Desktop |
| `dev/frontend/Pass B _ _ Deutschland _aktiv.html` | Roh-HTML-Export aus Figma (für strukturelle Analyse) |
| `dev/frontend/Mobile _ Startseite.png` | Visuelle Referenz Mobile |
| `dev/frontend/tailwind_v3/Startseite Tailwind.html` | **Master-Vorlage** der Implementierung (Tailwind v3 Export sauberer, ohne Embedded-Bilder) |
| `dev/frontend/tailwind_v3/Branchenseite Tailwind.html` | Vorlage Branchenseite (offen) |
| `dev/frontend/tailwind_v3/Detailseite Tailwind.html` | Vorlage Detailseite Pressemitteilung (offen) |
| `dev/frontend/tailwind_v3/Veröffentlichen Tailwind.html` | Vorlage Veröffentlichen-Landing (offen) |
| `dev/frontend/Branchenseite _ Energie _ Klima _aktiv.png` / `.html` | Hochauflösende Branchen-Vorlage |
| `dev/frontend/Detailseite _ Pressemitteilung _aktiv.png` / `.html` | Hochauflösende Detailseite-Vorlage |
| `dev/frontend/Ver_ffentlichen _ Variante A _aktiv_.png` / `.html` | Veröffentlichen-Vorlage |
| `dev/frontend/Umsetzungskonzept - Frontend BusinessPortal24 Startseite.md` | Historisches Detailkonzept zur Startseite |
**Verbindlich:** Die `tailwind_v3`-Exports sind die normative Referenz sie enthalten alle Spacings, Schriftgrößen, Tracking-Werte und Farbtöne in Klartext. Das `.png` dient als visuelle Bestätigung.
---
## 2. Tech-Stack
- **Framework:** Laravel 12 (PHP 8.4)
- **UI:** Livewire 4 + Volt 1 (single-file components)
- **CSS:** Tailwind CSS v4 mit `@theme`-Tokens und scoped Layer-Komponenten
- **Build:** Vite 6 (dualer Setup: `vite.web.config.js` Port 5178 / `vite.portal.config.js` Port 5177)
- **Interaktivität:** Alpine.js v3 (initialisiert in `resources/js/app.js`)
- **Icons:** Inline-SVG (Bunny-Fonts-Icons werden bewusst NICHT genutzt, um Render-konsistent zu bleiben)
- **Fonts (Bunny.net):** `Inter Tight` (Sans), `Source Serif 4` (Serif), `JetBrains Mono` (Mono)
- **Tests:** Pest 3 + PHPUnit 11
- **Lint/Format:** Laravel Pint (`vendor/bin/pint --dirty --format agent`)
---
## 3. Domain-Routing
Das Portal nutzt das bestehende `ThemeServiceProvider`-System aus `CLAUDE.md`. Beide Domains teilen sich `build/web/`-Assets und unterscheiden sich nur in der geladenen Theme-CSS-Datei:
```
Request (Host: businessportal24.test)
→ ThemeServiceProvider erkennt Domain
→ /config/domains.php liefert assets_dir = "build/web", theme = "businessportal24"
→ routes/web.php · "/" gibt businessportal24.blade.php zurück, vor­geladen mit Daten aus $webHomeData(Portal::Businessportal24)
→ resources/views/web/layouts/web-master.blade.php lädt theme-businessportal24.css + app.js
Request (Host: presseecho.test)
→ /config/domains.php liefert theme = "presseecho"
→ routes/web.php · "/" gibt presseecho.blade.php zurück, vor­geladen mit Daten aus $webHomeData(Portal::Presseecho)
→ web-master.blade.php lädt theme-presseecho.css + app.js
```
Lokale Domain-Simulation:
- `.env`: `DEV_SIMULATE_DOMAIN=true`, `DEV_SIMULATED_DOMAIN=businessportal24.test|presseecho.test`
- Alternativ: `?theme=businessportal24|presseecho|presseportale` als Query-Parameter
> **Hub-Sonderfall (`presseportale.test`):** Diese Domain ist gleichzeitig **Admin-Backend** (Auth/Admin/Customer-Routen, theme = `main`, Build-Dir `build/portal/`) **und** öffentliche **Hub-Landing** (theme = `presseportale`, Build-Dir `build/web/`). In `config/domains.php` existieren beide Einträge (`portal` und `presseportale`) für dieselbe `domain_name`. Der `ThemeServiceProvider` matcht zuerst `portal` (Backend-Standard); für die öffentliche Landing schaltet **`routes/web.php` per `$applyWebDomainConfig('presseportale')` explizit auf das Hub-Theme** um. Auth- und Admin-Routen bleiben unbeeinflusst.
### 3.1 Generischer Daten-Provider
Der Daten-Provider `$webHomeData(Portal $primaryPortal)` in `routes/web.php` ist **portal-agnostisch** und liefert für beide Domains die gleichen Variablen (`leadRelease`, `sideReleases`, `mostReadReleases`, `activeNewsrooms`, `industryIndex`, `homeStats`). Aufruf:
```php
view('web.presseecho', $webHomeData(Portal::Presseecho));
view('web.businessportal24', $webHomeData(Portal::Businessportal24));
```
Die Trennung der Portale geschieht über `whereIn('portal', [$primaryPortal->value, Portal::Both->value])`.
### 3.1.1 Presseecho-Farbpalette (Stand 13.05.2026, finalisiert)
Damit das Theme für Presseecho dokumentiert ist, hier der **verbindliche Token-Snapshot** aus `theme-presseecho.css`:
```css
@theme {
/* Surfaces (grünlich-getintete Editorial-Vorlage) */
--color-bg: #f2f4ed;
--color-bg-elev: #fafbf7;
--color-bg-rule: #dde2d3;
--color-bg-rule-strong: #1b2417;
--color-bg-card-warm: #ecefe3;
--color-bg-card-warm-border: #c7cfb6;
/* Dunkle Editorial-Panels (Topbar, CTA, Newsletter, Footer) */
--color-topbar: #1a3d2e; /* linear-gradient(135deg, #1a3d2e 0%, #122d22 100%) */
--color-topbar2: #122d22;
/* Ink (warm-grün, gedämpft) */
--color-ink: #1b2417;
--color-ink-2: #324132;
--color-ink-3: #6a7766;
--color-ink-4: #98a294;
--color-ink-on-dark: #f0f4eb;
--color-ink-on-dark-2: #b1b9ab;
/* Brand: dunkles Forest-Green */
--color-brand: #345636;
--color-brand-deep: #243c25;
--color-brand-soft: #dbe7d3;
/* Editorial-Akzente */
--color-accent-warm: #e8a95f; /* warmer Bernstein für Eyebrows auf Dunkel */
--color-ink-on-dark-muted: #859485;
--color-ink-on-dark-rule: #28332b;
--color-bg-card-warm-hover: #dde3cc;
--color-bg-card-warm-rule: #b7c0a2;
--color-card-warm-cat: #5f6a52;
--color-card-warm-title: #2e3826;
--color-feature-line: #a8c8a8;
--color-feature-dot: #c4dcc4;
}
/* Gradient-Komponenten-Klassen */
.bg-feature-grad { background-image: linear-gradient(135deg, #2c4733, #15281c); }
.bg-hero-grad { background-image: linear-gradient(135deg, #2c4733, #1a2a1f); }
```
**Iteration des Topbar-Gradients:**
| Versuch | Werte | Bewertung |
| --- | --- | --- |
| Startwert | `#1b2a1f → #25342a` | zu dunkel/zu neutral |
| Erste Variante | `#1f4d3a → #163a2c` | **zu hell** |
| **Final** | **`#1a3d2e → #122d22`** | **abgenommen** ✅ |
### 3.1.2 presseportale-Hub-Palette (Stand 13.05.2026)
Der **Hub** ist bewusst eigenständig positioniert: er ist **kein Editorial-Feed**, sondern eine reine Publisher-Landing („Ein Konto zwei Reichweiten"). Er bekommt daher einen ganz eigenen Charakter:
* **Surface:** warmes Buchpapier wie bei BP24/Presseecho (`--color-bg: #f6f4ef`) signalisiert Familien-Zugehörigkeit.
* **Primary:** Hub-Blau `#1A2540` mit Gradient nach `#243152` (Topbar, CTAs, alle „Hub"-Akzente).
* **Akzent:** gedecktes Bernstein `#B07A3A` **bewusst gewählt**, weil weder Orange (BP24) noch Grün (Presseecho). Der Hub steht visuell „zwischen" den beiden Brands.
* **Schrift:** Inter Tight (Standardtext) + JetBrains Mono (Mono) + Source Serif 4 (**nur für Marken-Mentions** der Tochter-Portale, damit typografische Konsistenz zur jeweiligen Brand-Landing erhalten bleibt; im Hub-Fließtext nicht verwendet).
Token-Snapshot aus `resources/css/web/theme-presseportale.css`:
```css
@theme {
/* Surfaces gleiche Familie wie BP24/Presseecho */
--color-bg: #f6f4ef;
--color-bg-elev: #fbfaf6;
--color-bg-rule: #e2ddd0;
--color-bg-card: #ffffff;
--color-bg-card-warm: #efeadc;
/* Hub-Blau Primary */
--color-hub: #1a2540;
--color-hub-2: #243152;
--color-hub-3: #2e3d66;
--color-hub-soft: #e5e9f1;
--color-hub-soft-2: #cfd6e4;
--color-hub-line: #7b8fbf;
--color-topbar: #1a2540;
--color-topbar2: #243152;
/* Bernstein-Akzent bewusst NICHT BP24-Orange, NICHT Presseecho-Grün */
--color-accent: #b07a3a;
--color-accent-deep: #8a5e27;
--color-accent-soft: #f1e6d3;
/* Ink, Brand-Aliase (für Komponenten, die brand-Tokens nutzen) */
--color-brand: #1a2540;
--color-brand-deep: #0f1729;
--color-brand-soft: #e5e9f1;
/* Schrift: Inter Tight + JetBrains Mono für Hub-Inhalte,
Source Serif 4 wird mitgeladen, aber nur für Marken-Mentions per
<x-web.brand-mark> aktiviert. */
--font-sans: "Inter Tight", Inter, system-ui, sans-serif;
--font-serif: "Source Serif 4", "Source Serif Pro", Charter, Georgia, serif;
--font-mono: "JetBrains Mono", "SF Mono", ui-monospace, monospace;
}
```
Hub-spezifische **Komponenten-Klassen** (alle in `@layer components`):
* `.bg-hub-grad` → 135° `#1a2540 → #243152` (Topbar, CTA, Architektur-Knoten)
* `.bg-hub-grad-2` → 180° `#1a2540 → #0f1729` (Footer)
* `.bg-accent-grad` → 135° `#b07a3a → #8a5e27`
* `.hero-grid` → subtile 48×48 px Gitterlinien als Hero-Hintergrund
* `.section-eyebrow` → Hub-Blau-Eyebrow mit Linien-Schwanz
* `.ribbon-recommend` → „Empfohlen für Unternehmen"-Banner auf der Pro-Tarif-Karte
* `.faq-chev` + `details > summary` → CSS-only Accordion (kein JS nötig)
### 3.2 Brand-Konfiguration
In `config/domains.php` liegt pro Domain ein **`brand`-Block**, der Komponenten dynamisch befüllt (Logo-Text, Tagline, Newsletter-Topics, Footer-Legal, Meta-Texte). `name` + `accent` ergeben **zusammen** den vollständigen Markennamen der `accent`-Teil wird im Header/Footer farbig hervorgehoben:
```php
'presseecho' => [
'theme' => 'presseecho',
'brand' => [
'name' => 'presse', // schwarz
'accent' => 'echo', // grün (text-brand → #345636)
'tagline_short' => 'Pressemitteilungen · DACH',
'tagline_long' => 'Fachmeldungen aus Wirtschaft und Industrie ...',
'footer_legal' => '© :year presseecho · Alle Rechte vorbehalten',
'about_label' => 'Über presseecho',
'meta_title' => '... presseecho',
'meta_description' => '...',
'newsletter_topics' => [ ... ],
],
],
'businessportal24' => [
'theme' => 'businessportal24',
'brand' => [
'name' => 'businessportal', // schwarz
'accent' => '24', // orange (text-brand → #C84A1E)
'footer_legal' => '© :year businessportal24 · Alle Rechte vorbehalten',
...
],
],
'presseportale' => [ // Hub-Variante (web)
'theme' => 'presseportale',
'brand' => [
'name' => 'presse', // hub-blau
'accent' => 'portale', // bernstein
'footer_legal' => '© :year presseportale · Alle Rechte vorbehalten',
...
],
],
```
Komponenten (`site-header`, `site-footer`, `newsletter-strip`) lesen ihre Defaults aus `config('domains.domains.'.config('app.theme').'.brand', [...])`. Übergaben via `:brand="..."` überschreiben sie jederzeit.
### 3.3 Brand-Mark-Konvention (verbindlich, Stand 13.05.2026)
Die Schreibweise der drei Marken folgt einer einheitlichen Regel: **keine TLD-Endung am Markennamen, Akzentteil farblich hervorgehoben.** Domains (`.de`, `.com`) gehören ausschließlich in technische Felder (URLs, mailto-Adressen, Impressum) niemals in den Marken-Schriftzug.
| Marke | Wortmarke | Akzentfarbe (auto) | Akzentfarbe (on-dark) |
| ------------------ | ------------------------------------------ | ---------------------- | --------------------- |
| `presseecho` | **presse**·*echo* | `#345636` (Forest) | `#9BD5B2` |
| `businessportal24` | **businessportal**·*24* | `#C84A1E` (Orange) | `#F4B098` |
| `presseportale` | **presse**·*portale* | `#B07A3A` (Bernstein) | `#B07A3A` |
**Single Source of Truth:** Die Komponente `<x-web.brand-mark brand="…" />` rendert die Markenschreibung zentral inkl. Span-Splitting, Schriftart und Akzent­farbe. Sie wird überall verwendet, wo eine Marke als Fließtext-Mention erscheint:
* Hub-Komponenten (`hub/top-utility-bar`, `hub/site-header`, `hub/site-footer`, `hub/brand-context-banner`)
* Hub-View `presseportale.blade.php` (Hero-Headline, Architektur-Diagramm, Tarif-Subline, Plattform-Familie, FAQ)
* Cross-Brand-Mentions auf BP24-/Presseecho-Landings, falls ergänzt
```blade
{{-- Standard: font-serif (Source Serif 4), Auto-Akzent --}}
<x-web.brand-mark brand="presseecho" />
{{-- In Fließtext / kleinen Schrift­größen: font-sans (Inter Tight) --}}
<x-web.brand-mark brand="businessportal24" :serif="false" />
{{-- Auf dunklem Hintergrund (Topbar, Hub-Footer): hellere Akzentfarbe --}}
<x-web.brand-mark brand="presseecho" variant="on-dark" />
```
Die BP24-/Presseecho-Header und -Footer rendern ihren eigenen Markennamen weiterhin über das `$brandName`+`$brandAccent`-Pattern aus der `brand`-Config (die Config liefert dasselbe Splitting `presse`+`echo`), erscheinen also typografisch identisch.
---
## 4. Theme-System (Tailwind v4)
### Datei: `resources/css/web/theme-businessportal24.css`
Alle Designtokens liegen in einem `@theme`-Block:
```css
@theme {
/* Surfaces */
--color-bg: #f6f4ef;
--color-bg-elev: #fbfaf6;
--color-bg-rule: #e5e0d5;
--color-bg-rule-strong: #1c1a17;
--color-bg-card-warm: #f1ece2; /* Warm-beige Anzeigen-Karten */
--color-bg-card-warm-border: #d9cdb6;
--color-topbar: #1a1f26;
--color-topbar2: #232a33;
/* Ink (Text-Hierarchie) */
--color-ink: #1c1a17;
--color-ink-2: #3d3935;
--color-ink-3: #6e6862;
--color-ink-4: #9a958d;
--color-ink-on-dark: #f6f4ef;
--color-ink-on-dark-2: #b8b3aa;
/* Brand */
--color-brand: #c84a1e;
--color-brand-deep: #a23814;
--color-brand-soft: #f4e5dd;
--color-live: #e03a1a;
--color-gain: #2e8540;
--color-loss: #c8341e;
--color-ok: #2e8540;
/* Editorial-Akzente (auf dunklem Grund / in Card-Warm) */
--color-accent-warm: #ff8b6f; /* Eyebrows auf TopBar/Hero/Newsletter */
--color-ink-on-dark-muted: #8a847b; /* gedämpfter Text auf Dunkel */
--color-ink-on-dark-rule: #2a2723; /* feiner Trenner auf Dunkel */
--color-bg-card-warm-hover: #ece5d5;
--color-bg-card-warm-rule: #c8bda8; /* Hairline „Anzeige" innerhalb Card-Warm */
--color-card-warm-cat: #6e6862;
--color-card-warm-title: #3a332b;
--color-feature-line: #a8c8a8; /* Decor-Linien im Feature-Bild-Fallback */
--color-feature-dot: #c4dcc4;
/* Typo & Layout */
--font-sans: "Inter Tight", "Söhne", Inter, system-ui, sans-serif;
--font-serif: "Source Serif 4", "Source Serif Pro", Charter, Georgia, serif;
--font-mono: "JetBrains Mono", "SF Mono", ui-monospace, monospace;
--container-layout: 1280px;
}
```
Daraus stehen Klassen wie `bg-bg`, `text-ink-3`, `border-bg-rule`, `text-brand`, `text-accent-warm`, `bg-card-warm-hover`, `max-w-layout`, `font-serif` automatisch zur Verfügung.
> **Wichtig:** Komponenten dürfen **keine Hex-Werte** mehr enthalten. Stattdessen die Tokens nutzen (`text-accent-warm`, `border-ink-on-dark-rule`, `text-card-warm-cat`, …). So bleibt der Theme-Wechsel zwischen BP24 und Presseecho ein reiner CSS-Switch.
### Wiederkehrende Komponenten-Klassen (in `@layer components`)
| Klasse | Verwendung |
| --- | --- |
| `.eyebrow` / `.eyebrow.muted` / `.eyebrow.on-dark` | 11px-Vor-Label uppercase (Brand-Farbe / Grau / `accent-warm` für Dunkel-Sektionen) |
| `.bp-cat` | Kategoriekürzel 11px uppercase brand |
| `.bp-tag` | Solid-Brand-Tag (z. B. „TOP-MELDUNG", „Top-Meldung") |
| `.rule-strong` | 1 px-Hairline auf `--color-bg-rule-strong` |
| `.rule` | 1 px-Hairline auf `--color-bg-rule` |
| `.bg-topbar-grad` | 135°-Gradient TopBar → Topbar2 (TopBar, CTA, Footer, Newsletter) |
| `.bg-feature-grad` | 135°-Gradient (Featured-Top-Bild-Fallback) |
| `.bg-hero-grad` | 135°-Gradient (Hero-Bild-Fallback) |
| `.ticker-marquee-track` | Endlos-Laufband (CSS-Keyframe `bp-ticker-marquee`, Dauer per `--bp-ticker-duration`, default 42 s; respektiert `prefers-reduced-motion`) |
### Utility-Klassen (in `@layer utilities`)
- `.pulse-dot` 1.6 s ease-in-out Animation (Live-Ticker, „heute aktiv"-Badge)
- `.tabular-nums` `font-variant-numeric: tabular-nums`
Plus eine globale Regel:
```css
[x-cloak] { display: none !important; } /* Alpine.js Init-Schutz */
```
---
## 5. Komponenten-Architektur
### 5.1 Layout
```
resources/views/web/layouts/web-master.blade.php
└── @yield('content')
```
Das Layout lädt das theme-spezifische CSS via `@vite`. Domain-spezifische Fonts werden nur für `businessportal24` von bunny.net gezogen.
### 5.2 Startseite
```
resources/views/web/businessportal24.blade.php
├── <x-web.site-header /> ← TopBar + Header + Nav + Live-Ticker
├── <main>
│ ├── <x-web.focus-hero /> ← „Im Fokus" Hero + Sidebar „Was sonst zählt"
│ ├── <section> 1.7fr/1fr Grid
│ │ ├── <livewire:web.press-release-feed />
│ │ └── <aside>
│ │ ├── <x-web.most-read />
│ │ ├── <x-web.publisher-cta />
│ │ └── <x-web.active-newsrooms />
│ ├── <x-web.industry-spotlight />
│ ├── <x-web.events-week />
│ ├── <x-web.industry-index />
│ ├── <x-web.newsletter-strip />
│ └── <x-web.quality-summary />
└── <x-web.site-footer />
```
### 5.3 Komponenten-Übersicht
| Datei | Rolle | Datenquelle |
| --- | --- | --- |
| `site-header.blade.php` | Top-Utility-Bar (Datum + Ausgabe-Tabs + Sprache/Links), Brand-Header (Logo + Suche + Anmelden + Veröffentlichen), Unter-Nav. Inkl. **Such-Overlay** + **Burger-Mobile-Nav** via Alpine. | Statisch (Props) |
| `live-ticker.blade.php` | Dunkler AD-HOC-Streifen mit Ticker-Items + DAX-Sparkline. | Mock (Props `ticker`, `marketIndex`) |
| `focus-hero.blade.php` | Hauptmeldung (500 px Hero) + 4 Sidebar-Items „Was sonst zählt" + Anzeige. | echtes `leadRelease`, `sideReleases` → fallback Mockup |
| `focus-side-item.blade.php` | Einzelnes Sidebar-Item (Nummerierung 01-04, 64×64-Bild, Verifiziert-Icon). | `release` ODER `mock` |
| `focus-ad.blade.php` | Warm-beige Anzeigen-Karte mit Anzeige- + Ende-Anzeige-Hairlines. | Statisch / Props |
| `press-release-feed.blade.php` (Volt) | Featured-Top + Liste + In-Feed-Anzeige + „Weitere Meldungen"-Button. Tabs: Alle / Heute / Diese Woche. **Pagination** via `WithPagination`. Empty-State liefert Mock-Top + Mock-Liste + Anzeige. | `PressRelease` mit `withCount`-Eager-Loading |
| `feed-top-item.blade.php` | Featured-Eintrag mit 240×160-Bild. | `release` ODER `mock` |
| `feed-item.blade.php` | Zeilen-Eintrag 60 px Zeit / 100 px Kat. / 1fr Titel. Optional „Empfehlung"-Badge. | `release` ODER `mock` |
| `feed-ad.blade.php` | Inline-Anzeige mit Anzeige- + Ende-Anzeige-Hairlines. | Statisch / Props |
| `most-read.blade.php` | Top 4 nach Hits mit horizontalem Brand-Balkenindikator. | `releases` → fallback Mockup |
| `publisher-cta.blade.php` | Dunkle Call-to-Action mit Brand-Button + Sekundärlink. | Statisch (Props `submitHref`, `pricingHref`) |
| `active-newsrooms.blade.php` | Newsroom-Liste mit Marken-Initial-Quadrat + Pulse-Badge „heute aktiv". | `companies` → fallback Mockup |
| `industry-spotlight.blade.php` | „Heute im Fokus · Energie & Klima" 3-Spalten-Stat-Grid + 3 Meldungen + warme Studien-Karte mit Brand-Topborder. | Aktuell Mockup |
| `events-week.blade.php` | 7-Spalten-Grid „Termine & Events" mit „Heute"-Highlight und Pulse-Dot. | Aktuell Mockup |
| `industry-index.blade.php` | „Branchen-Index" 4×2 Grid mit Gain/Loss-Delta + Balkenindikator. | `industries` (Category-Counts) → fallback Mockup |
| `newsletter-strip.blade.php` | Dunkles Newsletter-Panel mit Email-Form + Topic-Checkboxen (links Topic-Auswahl). | Aktuell Mockup |
| `quality-summary.blade.php` | Warm-beige Card mit Schild-Icon zum Content-Score. | Statisch |
| `site-footer.blade.php` | 4-Spalten-Footer + Bottom-Bar (AGB / Cookie / DSGVO). | Statisch |
Alle Komponenten haben **konsistente Konventionen**:
- `cursor-pointer` + `hover:`-Variante + `transition-colors` auf jedem klickbaren Element
- Bei Bild-Containern: `group` + `group-hover:scale-105` (subtiler Zoom)
- Bei Listenelementen: `group` + `group-hover:text-brand` für den Titel
- Alle Mockup-Inhalte sind als spätere Datenquellen markiert (Inline-Kommentare oder via Issue-Tracker)
### 5.4 Hub-Komponenten (`components/web/hub/`)
Der Hub `presseportale.com` hat einen **eigenen, deutlich anderen Charakter** als die beiden Brand-Portale (kein Editorial-Feed, sondern Publisher-Landing) und bekommt daher einen eigenen Komponenten-Namespace. Die Sektionen selbst (Hero, Features, How-it-works, Tarife, Plattform-Familie, Social-Proof, FAQ, CTA) sind als **inline-Markup** in `resources/views/web/presseportale.blade.php` umgesetzt, weil sie page-spezifisch sind.
| Datei | Rolle |
| --- | --- |
| `hub/top-utility-bar.blade.php` | Schmale Hub-Blau-Topbar mit Datum, „Publisher-Hub für …"-Brand-Family-Links (rendert `<x-web.brand-mark variant="on-dark" :serif="false">`), Status/Doku/Kontakt. Props: `date`, `siblingPortals` (jetzt Liste mit `brand`-Key statt fixer Strings). |
| `hub/site-header.blade.php` | Wortmark `presse`·`portale` (über `<x-web.brand-mark brand="presseportale" :serif="false">`) + Untertitel „Publisher · Hub", zentrale Primary-Nav (Tarife, So funktioniert es, …), Anmelden + Konto erstellen CTAs. Routes: `login`, `register`. |
| `hub/brand-context-banner.blade.php` | **Conditional Banner** unter dem Header greift nur bei `?from=presseecho` oder `?from=businessportal24` und zeigt: „Sie kommen von … Ihr Konto hier funktioniert für beide Portale". Markenname über Brand-Mark (font-serif), „Zurück zu …"-Link nutzt sans-Variante. |
| `hub/site-footer.blade.php` | 4-Spaltiger Hub-Footer (Konto / Plattform / Rechtliches + Brand-Spalte mit Plattform-Familie-Links über Brand-Mark `variant="on-dark"`), Hub-Gradient `linear-gradient(180deg,#1A2540,#0F1729)`. Brand-Block aus `config/domains.php`. |
**Hub-Sektionen als inline-Blade** (in `presseportale.blade.php`):
1. **Hero** mit Architektur-Diagramm rechts (zentraler Hub-Knoten + Brand-Portal-Karten + Output-Boxen, alles SVG-only).
2. **Was Sie hier können** 3-Karten-Grid (Veröffentlichen / Newsrooms / Reichweite).
3. **So funktioniert es** 4-Step-Ol mit Differenzierungs-Highlight in Schritt 3 (Bernstein-Akzent für „Unsere Qualitätssicherung").
4. **Tarife** 3 Karten (Starter / Standard / Pro mit `.ribbon-recommend`) + breiter Enterprise-Streifen in Hub-Blau.
5. **Hinter presseportale.com** 2-Spalten-Plattform-Familie mit den **Original-Brand-Gradients** der Tochter-Portale (`#1F4D3A→#163A2C` für Presseecho, `#1A1F26→#232A33` für BP24).
6. **Aktive Newsrooms** Prose-Auflistung statt Logo-Wall + kompakte Stats-Sidebar.
7. **FAQ** CSS-only-Accordion (`<details>` + `.faq-chev`) mit 8 Fragen, eine offen by default.
8. **CTA-Wiederholung** + Footer.
---
## 6. Backend-Anbindung der Startseite
Datei: `routes/web.php` → Closure `$businessportalHomeData`
Liefert dem Blade-View folgende Variablen:
| Variable | Quelle | Verwendung |
| --- | --- | --- |
| `$leadRelease` | Neueste veröffentlichte BP24-PM | `focus-hero` Hero |
| `$sideReleases` | Nächste 4 veröffentlichte PMs (ohne Lead) | `focus-hero` Sidebar |
| `$mostReadReleases` | Top 4 nach `hits` | `most-read` |
| `$activeNewsrooms` | Companies mit Press-Releases letzte 7 Tage, sortiert nach heute-aktiv | `active-newsrooms` (Mapped Array, kein Model) |
| `$industryIndex` | Top-Level-Categories mit Recent/Previous-Count + Delta | `industry-index` (Mapped Array) |
| `$homeStats` | publishedCount, publishedToday, archiveSince | `quality-summary` |
**SQLite-Kompatibilität:** Die `whereHas`-Bedingung für `activeNewsrooms` wurde bewusst ohne `HAVING` geschrieben, weil SQLite keine `HAVING`-Clauses ohne Aggregat unterstützt. Das ist relevant für die Test-Datenbank (`DB_DATABASE=testing`).
---
## 7. Responsive Strategie
| Breakpoint | Verhalten |
| --- | --- |
| `< sm` (< 640 px) | Kompaktes Datum, mini-Edition-Tabs (DE/AT/CH/EN), Such-Icon Overlay, PM"-Button kurz, Logo-Untertitel ausgeblendet |
| `sm` (≥ 640 px) | Voller Logo-Untertitel, vollständige Buttons („Anmelden", Veröffentlichen") |
| `md` (≥ 768 px) | Ausgabe"-Label sichtbar, inline-Suchfeld statt Icon-Button |
| `lg` (≥ 1024 px) | Sprache Deutsch" + Trennlinie + Newsletter/RSS/API sichtbar, horizontale Underline-Nav statt Burger, Live-Ticker DAX-Sparkline |
| `xl` (≥ 1280 px) | `⌘K`-Hinweis im Suchfeld |
### Mobile Navigation
Bei `< lg` blendet sich die Underline-Nav aus und wird durch einen **Burger-Trigger** ersetzt, der die **aktuelle Rubrik** prominent anzeigt. Klick öffnet ein abgesetztes Dropdown (`absolute z-40`) mit allen Rubriken als vertikale Liste. Aktive Rubrik ist Brand-farben + Check-Icon. Esc-Taste, `@click.outside` und das ausgewählte Item schließen das Menü.
### Such-Overlay
Such-Icon-Button öffnet einen modalen Layer (`fixed inset-0 z-50 bg-ink/70 backdrop-blur-sm`) mit großem Suchfeld, das via Alpine `$watch + $refs` automatisch fokussiert wird. Esc oder Klick auf Backdrop schließt.
---
## 8. Tests
### Datei: `tests/Feature/Web/Businessportal24HomeTest.php`
Drei Test-Szenarien:
1. **`renders the editorial shell`** Verifiziert Statik (Header, Sektionsüberschriften, Ticker, Newsletter, Quality-Summary). Stellt sicher, dass alte Marketing-Texte („führende Plattform", maximale Reichweite", Exklusiv-Interview") NICHT mehr erscheinen.
2. **`feed only shows published businessportal content`** Prüft Portal-Trennung (BP24 + Both sind sichtbar, Presseecho-Only und Drafts nicht).
3. **`shows most read releases in the sidebar`** Prüft Hits-Sortierung in der `most-read`-Komponente.
### Datei: `tests/Feature/Web/PresseechoHomeTest.php`
Drei spiegelbildliche Test-Szenarien:
1. **`renders the editorial shell`** Identische Sektions-Checks, gegen `presseecho.test`.
2. **`feed only shows published presseecho content`** Portal-Trennung gespiegelt: Presseecho + Both sichtbar, BP24-Only und Drafts nicht.
3. **`shows most read releases in the sidebar`** Hits-Sortierung.
### Datei: `tests/Feature/Web/PresseportaleHubHomeTest.php`
Fünf Test-Szenarien rund um die Hub-Landing:
1. **`renders the publisher landing shell`** prüft alle Hauptsektionen sind sichtbar (Publisher-Hub, Was Sie hier können, So funktioniert es, Vier Schritte, Tarife, Starter, Standard, Pro, Enterprise, Hinter presseportale.com, Plattform im Überblick, Häufige Fragen, Loslegen, Alle Systeme betriebsbereit).
2. **`loads the hub theme assets, not portal admin`** stellt sicher, dass `theme-presseportale` aus dem Manifest geladen wird (nicht `theme-businessportal24` oder `theme-presseecho`).
3. **`hides the brand-context banner without a from parameter`** Default-Aufruf zeigt keinen Sie kommen von …"-Banner.
4. **`shows the brand-context banner when arriving from presseecho`** `?from=presseecho` triggert den Banner inkl. Link Zurück zu presseecho.de".
5. **`shows the brand-context banner when arriving from businessportal24`** `?from=businessportal24` triggert den Banner für BP24.
**Stand:** 11 Web-Tests grün (BP24 3 + Presseecho 3 + Hub 5 = 79 Assertions). Gesamt-Suite: 220/221 (der eine Fail `ApiDocumentationTest` ist vorbestehend wegen fehlender `docs/api/v1.yml` und nicht UI-bezogen).
---
## 9. Build & Workflow
### Lokale Entwicklung
```bash
npm run dev:web # Vite Dev Server für Web-Domains (Port 5178)
npm run dev:portal # Vite Dev Server für Portal (Port 5177)
npm run dev:all # Beide parallel
```
### Production-Build
```bash
NODE_OPTIONS="--max-old-space-size=4096" npm run build:web
```
**Build-Memory:** Ohne `--max-old-space-size=4096` bricht Vite mit Exit-Code 137 (OOM) ab, sobald Alpine.js + die volle Tailwind-v4-Pipeline kompiliert werden.
### Tests
```bash
php artisan test --compact --filter=Businessportal24HomeTest
```
### Lint
```bash
vendor/bin/pint --dirty --format agent
```
---
## 10. Entwicklungs­schritte (chronologisch)
| # | Datum | Schritt | Status |
| --- | --- | --- | --- |
| 1 | 12.05.2026 | Umsetzungskonzept erstellt + offene Fragen geklärt | |
| 2 | 12.05.2026 | Mockup `Pass B _ _ Deutschland _aktiv` 1:1 in Blade/Volt überführt | |
| 3 | 12.05.2026 | Theme-CSS auf v3-Mockup-Werte migriert (vollständiges Surface/Ink/Brand-System, Gradient-Klassen, `max-w-layout`) | |
| 4 | 12.05.2026 | Ende Anzeige"-Hairline für `focus-ad` ergänzt, In-Feed-Anzeigen im Feed auf eine reduziert (am Ende vor Weitere Meldungen") | |
| 5 | 12.05.2026 | `cursor-pointer` + Hover-Effekte konsistent auf allen klickbaren Elementen (Tabs, Cards, Links, Buttons, Newsletter-Topics) | |
| 6 | 12.05.2026 | Responsive Header umgebaut: Burger-Mobile-Nav, Such-Overlay (Alpine.js), kompaktere TopBar, sichtbare Anmelden/Veröffentlichen-Buttons | |
| 7 | 12.05.2026 | Edition-Tabs (DE/AT/CH/EN) auch auf mobile sichtbar | |
| 8 | 12.05.2026 | Empty-State des Feeds liefert Mock-Top + Mock-Liste + Anzeige (analog Hero/Sidebar) | |
| 9 | 12.05.2026 | Live-Ticker-Animationen: Ad-Hoc-Meldungen als Endlos-Laufband (`ticker-marquee-track`, respektiert `prefers-reduced-motion`), rechte Kurszeile blättert via Alpine alle 5,2 s vertikal durch | |
| 10 | 12.05.2026 | Editorial-Akzente aus Hex-Hardcodings auf Theme-Tokens migriert (`accent-warm`, `ink-on-dark-muted`, `ink-on-dark-rule`, `card-warm-*`, `feature-*`) | |
| 11 | 12.05.2026 | Presseecho-Theme angelegt (`theme-presseecho.css` gleiche Token-Namen) und Presseecho-Startseite auf BP24-Komponenten umgestellt (`presseecho.blade.php`) | |
| 11a | 13.05.2026 | Editorial-Fonts-Loader im `web-master.blade.php` für presseecho freigeschaltet (Source Serif 4 + Inter Tight + JetBrains Mono via bunny.net, Montserrat nur noch für Portal/Legacy). | |
| 11b | 13.05.2026 | **Presseecho-Farbpalette finalisiert** (vom Design abgesegnet): grünlich-getintete Surfaces (`--color-bg: #f2f4ed`, Card-Warm `#ecefe3`/`#c7cfb6`), Brand bleibt **dunkles Forest** `#345636` mit Deep `#243c25` und Soft `#dbe7d3`. Topbar-Gradient nach Iteration auf `linear-gradient(135deg, #1a3d2e 0%, #122d22 100%)` festgelegt satter Forest-Ton, ohne zu hell zu wirken. Feature- und Hero-Gradient grün getintet (`#2c4733 → #15281c` / `#2c4733 → #1a2a1f`). Editorial-Akzent bleibt warm-amber (`accent-warm: #e8a95f`) für Eyebrows auf dunklem Grund. | |
| 12 | 12.05.2026 | `routes/web.php`: Daten-Provider generalisiert zu `$webHomeData(Portal)` beide Domains nutzen denselben Code-Pfad | |
| 13 | 12.05.2026 | Brand-Konfiguration in `config/domains.php` pro Domain (`brand.name`, `brand.accent`, `brand.tagline_*`, `brand.newsletter_topics`, `brand.footer_legal`, `brand.about_label`) `site-header`, `site-footer`, `newsletter-strip` lesen daraus | |
| 14 | 12.05.2026 | `press-release-feed`-Volt-Component portal-agnostisch (Prop `:portal`); Aufruf vom View-Layer aus | |
| 15 | 12.05.2026 | `PresseechoHomeTest` analog zu `Businessportal24HomeTest` (3 Szenarien, RefreshDatabase) | |
| 16 | 13.05.2026 | **presseportale-Hub-Landing live**: neues Web-Theme `presseportale` (Hub-Blau + Bernstein, `theme-presseportale.css`), eigener Komponenten-Namespace `components/web/hub/` (Top-Bar, Site-Header, Brand-Context-Banner, Site-Footer), Hub-View `web/presseportale.blade.php` mit Hero/Architektur-Diagramm, Features, How-it-works, Tarife (Starter/Standard/Pro+Ribbon, Enterprise-Streifen), Plattform-Familie, Aktive-Newsrooms, FAQ-Accordion, CTA. `routes/web.php` schaltet für `presseportale.test` auf das Hub-Theme um. Root-Route in `routes/admin.php` entfernt (Layout referenziert jetzt `route('dashboard')`). | |
| 17 | 13.05.2026 | `PresseportaleHubHomeTest` (5 Szenarien inkl. Brand-Context-Banner-Conditional). Vite-Config + ThemeHelper + `web-master`-Fonts (Inter Tight + JetBrains Mono ohne Serif) für `presseportale` ergänzt. | |
| 18 | 13.05.2026 | **Brand-Mark-Konvention etabliert** (Feintuning Marken-Schreibweise): keine TLD am Marken­schriftzug, Akzent farblich vom Basis-Wort abgesetzt. Single Source of Truth `<x-web.brand-mark>` (Marken-Tabelle inkl. Standard- und On-Dark-Akzentfarben, Serif/Sans-Switch). `config/domains.php` umgestellt (`presseecho`: `name=presse`/`accent=echo`; `presseportale`: `name=presse`/`accent=portale`; Footer-Legal & Meta-Texte ohne TLD). Hub-Komponenten und Hub-View durchgehend auf Brand-Mark migriert (Top-Utility-Bar, Site-Header, Brand-Context-Banner, Site-Footer, Hero-Headline, Architektur-Diagramm, Tarif-Subline, Plattform-Familie, FAQ). Hub-Theme bekommt Source Serif 4 als `--font-serif` (für Marken-Mentions) Bunny-Font-Loader erweitert. **+1 neuer Test `uses the brand-mark splitting without TLDs`**; alle 12 Web-Tests grün. | |
| 19 | 12.05.2026 | **Aktuell offen:** Detailseite, Branchenseite, Veröffentlichen-Landing für BP24 + Presseecho. Hub-Folgeseiten (Konto-Erstellen-Flow als Landing, Tarif-Detail, Doku-Hub) ebenfalls offen. | 🟡 |
---
## 11. Roadmap & nächste Schritte
| Reihenfolge | Aufgabe | Vorlage | Status |
| --- | --- | --- | --- |
| 1 | **Mobile-Feinschliff Startseite** gegen `dev/frontend/Mobile _ Startseite.png` durchgehen, alle Sektionen testen (besonders 7-Spalten-Events und 4×2 Branchen-Index Stack-Behavior) | `Mobile _ Startseite.html` | 🟡 noch nicht final geprüft |
| 2 | **Detailseite Pressemitteilung** umsetzen | `tailwind_v3/Detailseite Tailwind.html` + `Detailseite _ Pressemitteilung _aktiv.png` | 🔴 offen |
| 3 | **Branchenseite Energie & Klima** umsetzen (Template für alle Kategorien) | `tailwind_v3/Branchenseite Tailwind.html` + `Branchenseite _ Energie _ Klima _aktiv.png` | 🔴 offen |
| 4 | **Veröffentlichen-Landing** umsetzen (Variante A) | `tailwind_v3/Veröffentlichen Tailwind.html` + `Ver_ffentlichen _ Variante A _aktiv_.png` | 🔴 offen |
| 5 | **Echte Datenquellen** für aktuell statische Komponenten anbinden: Live-Ticker (Ad-Hoc-Meldungen), Events-Week, Newsletter-Topics, Industry-Spotlight-Studie | | 🔴 offen |
| 6 | **Legacy-URL-Mapping** für Kategorien + Pressemitteilungen festlegen + Tests | siehe Umsetzungskonzept §13 | 🔴 offen |
| 7 | **Presseecho-Ableitung** als zweites Web-Theme aus stabiler BP24-Basis | | **erledigt (13.05.2026)** Startseite live über `theme-presseecho.css` + Brand-Config, gleiche Komponenten wie BP24 |
| 8 | **Detailseite/Branchenseite ebenfalls für Presseecho** durchziehen, sobald BP24-Templates stehen (sollte ein reiner Theme-Switch werden) | siehe oben | 🔴 offen |
**Reihenfolge-Begründung:** Erst wenn Detailseite + Branchenseite + Veröffentlichen vorhanden sind, sind die wiederverwendbaren Bausteine klar genug abstrahiert. Eine zu frühe Abstraktion auf Basis nur der Startseite würde Re-Work erzeugen. Presseecho profitiert dann automatisch davon (nur Token-Switch).
---
## 12. Konventionen & Do/Don't
### ✅ Do
- **Mockup-Vorlage `tailwind_v3/...html` als Quelle der Wahrheit nutzen.** Spacings, Farben, Schriftgrößen 1:1 übernehmen.
- **Eigene Tailwind-v4-Tokens** (`bg-bg`, `text-ink-3`, `border-bg-rule`, …) statt fester Hex-Werte verwenden Ausnahme: TopBar-spezifische `#2A2723`, `#8A847B`, `#FF8B6F`, die ausschließlich auf dunklem Hintergrund vorkommen.
- **`cursor-pointer` + `transition-colors`** auf jedem klickbaren Element (Buttons brauchen das wegen Tailwind-Preflight explizit).
- **Mockup-Fallback** in Komponenten konsequent unterstützen (`@if ($release) … @else … @endif` oder Mock-Props), damit Empty-States nie leer" wirken.
- **Volt für interaktive Komponenten**, klassische Blade-Components für reine Darstellung.
- **Tests bei jeder Änderung pflegen** mindestens 1 Assertion pro neue sichtbare Sektion in `Businessportal24HomeTest`.
- **Pint nach jeder PHP-Änderung** ausführen.
- **Build mit `NODE_OPTIONS=--max-old-space-size=4096`** dokumentieren in Skripten / CI.
### ❌ Don't
- Keine FluxUI-Komponenten im Web-Bundle (nur im Portal verfügbar).
- Keine Marketing-Phrasen wie führende Plattform", maximale Reichweite", Exklusiv-Interview" das war Pass A, wir sind auf Pass B.
- Keine `HAVING`-Clauses ohne Aggregat (SQLite-Test-DB bricht).
- Keine festen Pixel-Container > 1280 px (Layout-Token).
- Keine Inline-`style="background-color:..."` für Theme-Farben stattdessen `@theme`-Token verwenden.
---
## 13. Wiederkehrende Snippets
### Sektions-Header
```blade
<section class="max-w-layout mx-auto px-8 mt-16">
<header class="flex items-baseline justify-between mb-4 flex-wrap gap-3">
<h2 class="font-serif text-[28px] font-semibold m-0 tracking-[-0.3px] text-ink">
Sektionstitel <span class="text-brand">· Subtitle</span>
</h2>
<div class="eyebrow muted">Meta-Information</div>
</header>
<hr class="rule-strong">
{{-- ... --}}
</section>
```
### Feed-Listen-Item (60 / 100 / 1fr)
```blade
<a href="#" class="grid items-baseline gap-4 py-3.5 border-b border-bg-rule cursor-pointer hover:bg-bg-elev transition-colors group"
style="grid-template-columns: 60px 100px 1fr;">
<span class="font-mono text-[12px] text-ink-3">14:18</span>
<span class="bp-cat">Kategorie</span>
<div>
<div class="font-serif text-[15.5px] leading-[1.3] font-medium text-ink group-hover:text-brand transition-colors">
Titel der Meldung
</div>
<div class="text-[11px] text-ink-3 mt-1">Unternehmen · Stadt</div>
</div>
</a>
```
### Anzeigen-Block (warm-beige)
```blade
<div class="-mx-4 my-2">
<div class="flex items-center gap-2.5 px-4">
<span class="h-px flex-1 bg-bg-card-warm-rule"></span>
<span class="text-[9px] font-bold tracking-[0.22em] uppercase text-ink-on-dark-muted">Anzeige</span>
<span class="h-px flex-1 bg-bg-card-warm-rule"></span>
</div>
<a href="#" rel="sponsored nofollow" class="block px-4 py-4 bg-bg-card-warm cursor-pointer hover:bg-bg-card-warm-hover transition-colors">
{{-- Titel: text-card-warm-title; Kategorie/Meta: text-card-warm-cat --}}
</a>
<div class="flex items-center gap-2.5 px-4">
<span class="h-px flex-1 bg-bg-card-warm-rule"></span>
<span class="text-[9px] font-bold tracking-[0.22em] uppercase text-ink-on-dark-muted">Ende Anzeige</span>
<span class="h-px flex-1 bg-bg-card-warm-rule"></span>
</div>
</div>
```
### Dunkles Panel (Newsletter / CTA / Footer)
```blade
<section class="bg-topbar-grad text-ink-on-dark p-12">
<div class="eyebrow on-dark mb-3">Eyebrow</div>
<h2 class="font-serif text-[30px] font-semibold text-white leading-[1.18] tracking-[-0.4px]">Headline</h2>
{{-- ... --}}
</section>
```
---
## 14. Pflege dieses Dokuments
- **Wer ein neues Feature umsetzt:** Eintrag in Tabelle §10 ergänzen + ggf. §5.3 (Komponenten) und §11 (Roadmap) aktualisieren.
- **Wer einen neuen Designtoken hinzufügt:** §4 aktualisieren.
- **Wer eine neue Seite/Route ergänzt:** §3 (Routing) erweitern.
- **Status-Indikator pflegen:**
- ✅ erledigt und in Production-tauglichem Zustand
- 🟡 in Arbeit oder Feinschliff nötig
- 🔴 offen, noch nicht begonnen
Die `tailwind_v3`-Mockups sind die normative Quelle. Bei Konflikten zwischen `.png`, Roh-`.html` und `tailwind_v3/...html` gewinnt **immer** das `tailwind_v3/`-Pendant.