From 4dd2ea1d18325ae927b4318ca83acb13936e9db4 Mon Sep 17 00:00:00 2001 From: DeeCee03 Date: Tue, 20 Oct 2026 18:03:33 +0200 Subject: [PATCH] Regel: Oberflaechen immer aus den Produkt-Komponenten MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rules.md §0 macht es zur Pflicht, komponenten.md ist das Nachschlagewerk mit Tokens, Komponenten, Bausteinen und Vorgehen, CLAUDE.md weist jeden Agenten darauf hin. Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 13 +++ komponenten.md | 209 +++++++++++++++++++++++++++++++++++++++++++++++++ rules.md | 42 ++++++++-- 3 files changed, 257 insertions(+), 7 deletions(-) create mode 100644 CLAUDE.md create mode 100644 komponenten.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c93b61f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,13 @@ +# posts (PostGrid) + +Hier entstehen die Bild- und Animationsposts von HiveGrid. Regeln in `rules.md`. + +**PFLICHT, ohne Ausnahme:** Jede Oberfläche in einem Post wird aus den echten Komponenten von `hivegrid-cloud` +nachgebaut, mit deren Maßen, Farben, Schrift, Icons und Beschriftungen, und bildet einen Screen nach, den es im Produkt +gibt. Keine ausgedachten, „vibecoded“ Grafiken. Vor jedem neuen Post `komponenten.md` lesen und die Bausteine aus +`post8.html` übernehmen (rules.md §0). + +- Code von hivegrid-cloud immer von `origin/main` lesen (`git show origin/main:`), die Arbeitskopie ist veraltet + und wird nicht angefasst. +- PostGrid starten: `./serve.sh`, dann http://127.0.0.1:4321/. Der Export (`node animation.mjs`) lädt immer von Port 4321. +- Texte: schlichtes Deutsch, keine Geviertstriche. diff --git a/komponenten.md b/komponenten.md new file mode 100644 index 0000000..fe33836 --- /dev/null +++ b/komponenten.md @@ -0,0 +1,209 @@ +# Produkt-Komponenten für Posts + +**Stand:** 20.10.2026. Quelle: `hivegrid-cloud`, Stand `origin/main` vom 19.10.2026. +**Referenz-Umsetzung:** `post8.html`, Abschnitt „Post 8 · E-Mail-Marketing“. + +Diese Datei ist das Nachschlagewerk für jede Zeichnung, die in einem Post die Software zeigt. Die Regel dazu steht in +`rules.md` §0 und gilt ohne Ausnahme. + +--- + +## 1. Die Regel + +**Jede Oberfläche in einem Post wird aus den echten Komponenten von hivegrid-cloud nachgebaut, mit ihren Maßen, +Farben, Schriften, Icons und Beschriftungen. Keine eigenen, ausgedachten Grafiken.** + +- Jede Zeichnung bildet einen Screen nach, den es im Produkt gibt. Im Kommentar steht die Datei, aus der er stammt. +- Beschriftungen stehen wörtlich in `apps/web/public/locales/de/translations.json`. +- Was im Produkt nicht existiert, wird nicht gezeichnet. Auch nicht, wenn es gut aussähe. +- Was nicht auf die Slide passt, wird weggelassen, nicht umgebaut. Im Kommentar steht, was fehlt und warum. +- Erfunden werden darf nur Demo-Inhalt: Namen, Betreffzeilen, Texte, Daten, Zahlen. Die Zahlen müssen aufgehen. + +**Warum:** Die erste Fassung von Post 8 hatte ein eigenes Design (Pillen mit Rand, Häkchen-Chips, Reiter und Kacheln, die +es im Produkt nicht gibt). Dejan: „sieht total vibecoded aus“. Nach dem Umbau auf die Komponenten: „sieht jetzt genau so +aus wie die Software“ (20.10.2026). + +--- + +## 2. So gehst du vor + +1. **Screens finden.** Für das Thema des Posts das Modul in hivegrid-cloud suchen: + `apps/web/app/components/screens//`, `apps/web/app/modules//`, die Routen unter + `apps/web/app/routes/app.$tenant/`, die Texte in `translations.json`. +2. **Immer `origin/main` lesen, nie die Arbeitskopie.** Die lokale Kopie von hivegrid-cloud ist veraltet und wird nicht + angefasst (kein pull, kein checkout ohne Dejan). + - Einzelne Datei: `git -C ../hivegrid-cloud show origin/main:` + - Für viele Dateien ein Schnappschuss ins Scratchpad: + `git -C ../hivegrid-cloud archive origin/main apps/web/app apps/web/public/locales/de | tar -x -C /hg-main` + - Vorher `git -C ../hivegrid-cloud fetch` (holt nur, ändert nichts). +3. **Für jede Slide einen echten Screen wählen.** Aufbau von oben nach unten aus dem Code lesen: Kopf, Knöpfe, Tabs, + Felder, Tabellenspalten, welche Badge für welchen Status. +4. **Mit den Bausteinen zeichnen** (Abschnitt 3). Sie stehen in `post8.html` und werden in den neuen Post kopiert, weil + jeder Post eine einzelne Datei ist. +5. **Prüfen:** + - Streifen-Ansicht `?nur=streifen`: Die Karte darf nicht in den Text der Slide ragen. + - PNG-Export: Die Oberfläche muss in Instrument Sans stehen, nicht in einer Ersatzschrift (siehe Fallen). + - MP4 mit `node animation.mjs postN.html `. + +--- + +## 3. Bausteine in `post8.html` + +Alle Werte sind Produkt-Pixel und werden mit `PZ = 1.15` vergrößert, wie ein Browserzoom. Koordinaten sind Pixel der +Zeichnung. Nur Schriften, Icons und Komponentenhöhen laufen über `pz()`. + +| Baustein | Bildet nach | Aufruf | +|---|---|---| +| `P`, `P_TON`, `P_KNOPF`, `P_KARTE` | Rollen aus `ui/theme.css` | Farbkonstanten | +| `pText(x, y, t, gr, gew, farbe, o)` | Text in Instrument Sans | `o.anker` für Ausrichtung | +| `pMess(t, gr, gew)` | Textbreite in Instrument Sans | | +| `pMitte(ym, gr)` | Grundlinie für Text mittig in einem Kasten | | +| `pIkon(name, cx, cy, gr, farbe)` | Feather/Lucide-Icon, Strich 2 auf 24 | Namen aus `LUCIDE` | +| `pKarte(x, y, b, h, art, radius)` | `Card`, `InlineMessage` | `art`: std, weiss, neutral, info, warnung | +| `pBadge(x, ym, t, ton, klein)` | `BadgeFeedback` subtle | `ton`: positiv, warnung, info, neutral | +| `pKnopf(x, y, t, art, o)` | `Button` | `art`: primaer, sekundaer, tertiaer, geist, aus; `o.ikon`, `o.ikonRechts`, `o.klein` | +| `pFeld(x, y, b, o)` | `TextInput`, `Select`, `TextArea` | `o.label`, `o.wert`, `o.platzhalter`, `o.auswahl`, `o.hoch`, `o.hilfe` | +| `pTabs(x, y, b, reiter, aktiv, innen)` | `Tabs` | | +| `pUmschalter(xRechts, y, eintraege, aktiv)` | `ToggleGroup` klein | Einträge `[icon, text]` | +| `pTabelle(x, y, spalten, zeilen, zh, zelle)` | `Table` | Spalten `[titel, icon, breite]` | +| `pRahmen(h, inhalt, kopf)` | Seite mit `PageHeader` | `kopf.ikon`, `kopf.titel`, `kopf.badge`, `kopf.ikonKasten`, `kopf.rechts` | +| `pKopfKnopf(t, art, o)` | Knopf rechts im Kopf | | +| `emKpi(...)` | `WidgetRahmen` mit `KPICard` | | + +**Icons:** `LUCIDE` enthält die Formen aus `lucide-static@0.460.0`. Subframes `Feather*`-Icons haben dieselben Formen. +Fehlt ein Icon, die SVG von `https://cdn.jsdelivr.net/npm/lucide-static@0.460.0/icons/.svg` holen und das Innere +der `` in die Tabelle eintragen. Phosphor (`ikon()`) gehört nur noch in ältere Posts, nicht in Oberflächen. + +**Schrift:** Die Dateien liegen in `assets/fonts/instrument-sans-*.woff2`, dieselben wie in +`hivegrid-cloud/apps/web/public/fonts/`. Der Post braucht dafür drei Dinge: +1. den `@font-face`-Block im `` +2. beim Start `document.fonts.load(...)` für 400, 500 und 600, bevor zum ersten Mal gemessen wird +3. `instrumentSansCss()`, angehängt an `fontEmbedCss`, sonst fehlt die Schrift im PNG + +Alles drei steht in `post8.html`. + +--- + +## 4. Tokens, aufgelöst + +### Schrift +Instrument Sans, variabel 400 bis 700. Laufweite überall 0. + +| Token | px / Zeilenhöhe / Gewicht | Wofür | +|---|---|---| +| `subtitle` | 32/40/600 | Seitentitel im `PageHeader`, Wert in `StatsCard` | +| `heading-` | 24/32/500 | Dialogtitel | +| `body-large` | 20/24 (‑0: 26)/500 | Abschnitte wie „E-Mail gestalten“, EmptyState-Titel | +| `body-default-regular` | 16/24 (‑0: 22)/400 | **Knopfbeschriftung**, Eingaben, Fließtext | +| `body-default-medium` | 16/24/500 | Feldbeschriftungen | +| `body-default-semibold` | 16/24/600 | Kartentitel | +| `body-small-regular` | 14/21 (‑0: 18)/400 | Hilfetexte, Tabs, Seitenleiste | +| `body-small-medium` | 14/21/500 | Badges, Menüeinträge, Checkbox-Beschriftung | +| `body-extra-small` | 12/18 (‑0: 16)/400 bis 600 | Tabellenkopf (500), Tooltip | + +`text-heading-2` und `text-heading-3` werden im Code benutzt, sind aber nirgends definiert. Sie rendern als 16/24/400. + +### Farben + +**Neutral:** 0 `#FAFAFA` · 50 `#F5F4F4` · 100 `#F0F0F0` · 200 `#E5E5E5` · 300 `#CECECF` · 400 `#B5B5B7` · 500 `#9D9DA0` · +600 `#858589` · 700 `#6D6D71` · 800 `#505057` · 850 `#37373E` · 900 `#24242B` · 950 `#111114` + +| Rolle | Wert | +|---|---| +| Seite (`surface-neutral-primary`) | `#F5F4F4` | +| Karte, Kopfzeile, Tabellenzeile (`secondary`) | `#FAFAFA` | +| Tabellenkopf, Hover (`tertiary`) | `#F0F0F0` | +| Rand, Rand stark | `#E5E5E5`, `#B5B5B7` (Eingabefelder) | +| Text primär, sekundär, tertiär | `#24242B`, `#505057`, `#6D6D71` | +| Platzhalter, deaktiviert | `#CECECF` | +| Link | `#08739C` | +| Icons primär, sekundär, tertiär | `#24242B`, `#505057`, `#858589` | +| Akzent für aktiv und ausgewählt | `#E1F4FD` (information subtle) | +| Sekundärknopf | `#E3F1FF` | + +| Ton | 100 | 200 | 500 | 600 | 700 | +|---|---|---|---|---|---| +| Erfolg (grün) | `#DCFCE4` | `#BAF8CB` | `#20C54F` | `#15A43E` | `#148134` | +| Warnung (gelb, nicht Marke) | `#FCF6C5` | `#FAEB8E` | `#E1AB11` | `#C2840C` | `#9B5E0D` | +| Fehler (rot) | `#FEE2E2` | `#FDCBCB` | `#ED4646` | `#DA2828` | `#C52020` | +| Information (ocean) | `#E1F4FD` | `#BCEAFB` | `#15B1E2` | `#0890C1` | `#08739C` | + +**Kein Markengelb in der Oberfläche.** Die Rolle „brand“ ist im Produkt auf Grau gemappt, Primärknöpfe sind `#24242B`. +Gelb gehört auf der Slide nur zur Überschrift und zu Marken-Elementen außerhalb der Oberfläche. + +### Radien und Schatten +- `rounded-sm` 4 px (Eingabefelder) · `rounded-md` **6 px** (Knöpfe, Karten, Tabs) · `rounded-lg` 8 px (Widgets) · + `rounded-xl` 12 px. In `theme.css` steht md = 8, `globals.css` überschreibt das danach mit 6. +- Schatten im Produkt: sm `0 1px 2px rgb(0 0 0 / .08)`, md und lg größer. In den Zeichnungen lassen wir sie weg + (rules.md §5). Der Stapel um die Karte hat seinen eigenen Schatten und bleibt. + +--- + +## 5. Komponenten + +| Komponente | Maße und Farben | +|---|---| +| **Button** | klein h32, px12, Abstand 8 · mittel h36, px16, Abstand 12 · groß h48. Radius md. Beschriftung 16/400, Icon 16. primär `#24242B`/`#FAFAFA` · sekundär `#E3F1FF`/`#24242B` · tertiär `#F5F4F4` mit Rand `#E5E5E5` · ghost transparent · information `#0890C1` · destructive `#DA2828` · deaktiviert `#F0F0F0`/`#CECECF` | +| **IconButton** | rund, quadratisch mit `square` (md). 24/32/36/48 Kasten, Icon 16/20/20/24 | +| **BadgeFeedback** (alle Status) | Pille **ohne Rand**, h24 (klein 20), px10, Abstand 8, Punkt 4 px, Schrift 14/500. positiv `#DCFCE4`, Text und Punkt `#148134` · Warnung `#FCF6C5`, Text `#24242B`, Punkt `#9B5E0D` · information `#E1F4FD`, Text `#24242B`, Punkt `#08739C` · neutral `#F0F0F0`, Text und Punkt `#24242B` · negativ `#FEE2E2`, `#C52020` | +| **Badge** (Farbtöne) | Pille h24 mit 1-px-Rand, sonst wie oben. Standard `#F0F0F0`, Rand `#E5E5E5` | +| **Tabs** | Reiter px16, py10 (rund 40 hoch), oben rund, `#FAFAFA`, unten 2 px `#E5E5E5`, Schrift 14/400 `#505057`. **Aktiv:** Fläche `#E1F4FD`, unten 2 px `#24242B`, Schrift 14/500 `#24242B` | +| **TextInput / Select** | h36, px12, Radius 4, Rand `#B5B5B7`, Fläche `#F5F4F4`. Beschriftung 16/500 `#505057`, 6 px darüber. Wert 16 `#505057`, Platzhalter `#CECECF`, Hilfe 14 `#6D6D71`. Pfeil 16 `#858589` | +| **TextArea** | wie oben, mindestens 96 hoch, Innenabstand 12×8 | +| **Checkbox** | 16, Radius 4, Rand 2 px `#B5B5B7`. An: `#24242B` mit Haken `#FAFAFA`. Beschriftung 14/500 | +| **Switch** | 36×22, rund. Aus: `#F5F4F4` mit dunklem Knopf. An: `#24242B` mit hellem Knopf | +| **Table** | Außenrand `#E5E5E5`. Kopf h32, `#F0F0F0`, Schrift 12/500 `#505057`, Icon 12 `#858589`. Zeilen `#FAFAFA` mit Trennlinien `#E5E5E5`, Höhe aus dem Inhalt (rund 31) | +| **Avatar** | rund, 24/32/40/48/64. Ohne Bild `#F0F0F0`, Kürzel 16/500 `#505057` | +| **IconWithBackground** | Radius 4. Kasten 22/24/28/32/40, Icon 14/16/20/24/32. information `#E1F4FD` mit `#08739C` | +| **Card** | Radius md, Rand `#E5E5E5`, Fläche `#FAFAFA`, Innenabstand 16 (lg 24). Varianten information, warning, negative, positive, neutral | +| **InlineMessage** | Card in Ton-Variante, px16, py12, Text 16 `#24242B`. Standard information | +| **Alert** | Radius md, Rand, px16, py20, Icon 24. Titel 16/500 im Ton, Text 16 `#505057` | +| **Widget** (`WidgetRahmen`) | Radius lg, Rand, weiß. Kopf h44 mit Titel 13/600. KPI: Wert halbfett, Fußzeile 11 `#6D6D71` über einer Linie | +| **ToggleGroup** | h36 (klein 32), Innenabstand 2, Rand, `#F0F0F0`. Aktiv: `#24242B` mit Schrift `#FAFAFA` | +| **DropdownMenu** | `#FAFAFA`, Rand, Radius md, Innenabstand 4. Einträge 14/500 `#6D6D71`, Hover `#F0F0F0` | +| **Tooltip** | `#505057`, Schrift 12/500 `#FAFAFA`, Radius 4 | +| **Progress** | 6 px, rund, Spur `#F0F0F0`, Füllung `#24242B` | +| **EmptyState** | Titel 20/500, Text 16 `#505057`. Umrandet: Rand und `#F5F4F4` | +| **Dialog** | weiß, Rand, Radius md, Overlay `rgb(0 0 0 / .4)`. DecisionDialog 420 oder 560 breit, Titel 24/500 | + +### App-Rahmen +- **Seite:** Hintergrund `#F5F4F4`. Kopfleiste h64, `#FAFAFA`, Linie unten. +- **PageHeader:** `#FAFAFA`, px24, py20, Linie unten. Icon 24 in `#858589`, Abstand 8, Titel 32/600 `#24242B`. + Knöpfe rechts mit Abstand 8. In den Zeichnungen Titel 24, weil die Karte schmaler ist als ein Bildschirm. +- **Filterleiste:** `#F5F4F4`, px24, py10. Suchfeld `#FAFAFA`, Facetten-Chips h24 mit Rand `#B5B5B7`. Aktiv `#BCEAFB`. +- **Seitenleiste:** 240 breit, `#FAFAFA`. Einträge h40, Icon 20 mit Strich 1.5, Schrift 14. Gewählt: `#E1F4FD`. + +--- + +## 6. Fallen + +1. **Schrift im PNG.** html-to-image bettet nur die Schrift ein, die im HTML vorkommt, also Manrope. Instrument Sans + steckt nur im SVG und fehlte im Export. Lösung: `instrumentSansCss()` an `fontEmbedCss` hängen. Prüfen, indem man + Export und Vorschau übereinanderlegt. +2. **Messen vor dem Laden.** `pMess()` speichert Breiten zwischen. Wird vor dem Laden der Schrift gemessen, bleibt die + Breite der Ersatzschrift hängen. Darum `document.fonts.load` am Anfang von `boot()`. +3. **Was in den Übersetzungen steht, ist nicht automatisch zu sehen.** Beispiel: „Pre-Send-Prüfung“ und die sechs + Prüfpunkte stehen in `translations.json`, angezeigt werden sie nirgends. Immer im Screen-Code nachsehen, ob ein Text + wirklich gerendert wird. +4. **Website und Produkt unterscheiden.** Die Website zeigt manches, was es im Produkt nicht gibt (in Post 8 die + Produktkacheln im Mail-Baukasten). Maßgeblich ist das Produkt. +5. **Höhe der Karte.** Zu hohe Karten ragen in den Text der Slide. Lieber Schritte oder Hilfetexte weglassen als die + Komponenten zu verkleinern. +6. **Feste Höhe im Bewegtbild.** Die Höhe der Zeichnung darf nicht vom Zeitpunkt abhängen, sonst ändert sich der + viewBox und alles springt. + +--- + +## 7. Beispiel: E-Mail-Marketing (Post 8) + +| Slide | Screen | Datei in `apps/web/app/components/screens/email-marketing/` | +|---|---|---| +| Bewegtbild | Kampagnenbericht | `EmailMarketingDetailScreens.tsx` | +| Zielgruppe | Dialog „Zielgruppe bearbeiten“ | `SegmentEditorDialog.tsx`, `SegmentFilterBuilder.tsx` | +| Vorlagen | Vorlagenseite | `EmailMarketingTemplateScreens.tsx` | +| Rechtssicher | „Empfänger & Versand“ mit „Bereit zum Versand?“ | `EmailMarketingCampaignEditorPage.tsx` | +| Baukasten | Gestaltung | `CampaignContentBuilder.tsx`, `CampaignBuilderSidebar.tsx`, `campaign-mail-look.ts` | + +Status-Badges dort: „Gesendet“ positiv · „Geplant“, „Pausiert“ Warnung · „Wird gesendet“ information · „Entwurf“, +„Archiviert“ neutral. Empfänger: „Zugestellt“, „Geöffnet“, „Geklickt“ positiv · „Ausstehend“ Warnung · „Gebounced“ +negativ. Vorlagen: „Standard“ information · „Eigen“ neutral. Versandbereitschaft: „Erledigt“ positiv · „Offen“ neutral. diff --git a/rules.md b/rules.md index c1b5588..ab139e5 100644 --- a/rules.md +++ b/rules.md @@ -1,13 +1,41 @@ # Post-Generator — Regeln & Konventionen Arbeitsgrundlage für alles, was in diesem Repo an Social-Grafiken entsteht. -**Stand:** 15.08.2026 +**Stand:** 20.10.2026 Der Generator läuft lokal: `./serve.sh` → (Post 1, Carousel). --- +## 0. PFLICHT: Oberflächen aus den Produkt-Komponenten, nie eigene Grafik + +> **Diese Regel gilt für jeden Post und hat Vorrang vor allem anderen in dieser Datei.** +> +> Jede Zeichnung, die die Software zeigt, wird aus den echten Komponenten von +> `hivegrid-cloud` nachgebaut: mit deren Maßen, Farben, Schrift (Instrument Sans), +> Icons (Feather/Lucide) und Beschriftungen aus `translations.json`. Jede Zeichnung +> bildet einen Screen nach, den es im Produkt wirklich gibt. +> +> **Verboten:** ausgedachte Oberflächen, eigene Marken-Pillen, Häkchen-Chips, +> Reiter, Kacheln oder Effekte, die es im Produkt nicht gibt. Kurz: keine +> „vibecoded“ Grafiken. +> +> - Nachschlagewerk mit allen Tokens, Komponenten, Bausteinen und dem Vorgehen: +> **`komponenten.md`**. Vor jedem neuen Post lesen. +> - Referenz-Umsetzung: `post8.html` (seit 20.10.2026). Die Bausteine `pText`, +> `pBadge`, `pKnopf`, `pFeld`, `pTabs`, `pTabelle`, `pRahmen` und so weiter von +> dort übernehmen. +> - Code immer von `origin/main` lesen (`git show origin/main:`), nicht aus +> der veralteten Arbeitskopie. +> - Was nicht auf die Slide passt, weglassen und im Kommentar vermerken. Nicht +> umbauen, nicht erfinden. Erfunden werden darf nur Demo-Inhalt. +> +> **Warum:** Post 8 sah mit eigenem Design „total vibecoded“ aus. Nachgebaut aus +> den Komponenten „sieht jetzt genau so aus wie die Software“ (Dejan, 20.10.2026). + +--- + ## 1. Wo die Wahrheit steht > **Neue Basis ab 12.10.2026: `hivegrid-cloud`.** Das ist die aktuelle Version @@ -27,7 +55,7 @@ Der Generator läuft lokal: `./serve.sh` → > > | Was | Wert | > |---|---| -> | Schrift | Instrument Sans (heute hier: Manrope) | +> | Schrift | Instrument Sans: in allen Oberflächen-Zeichnungen (§0), die Slide-Überschriften bleiben Manrope | > | Text, Knöpfe | `#24242B` (grey-900), Knöpfe sind fast schwarz | > | Text zweitrangig | `#505057`, drittrangig `#6D6D71` | > | Markengelb | `#F1B729` (brand-600), unverändert | @@ -36,12 +64,12 @@ Der Generator läuft lokal: `./serve.sh` → > | Rahmen | `#E5E5E5` (neutral-200) | > | Radien | 4, 8, 12 px | > | Größen | Hero 72/72, Seite 48/56, Untertitel 32/40, alle 600 | -> | Symbole | Feather über `@subframe/core` (heute hier: Phosphor) | +> | Symbole | Feather über `@subframe/core`: in Oberflächen als Lucide-Formen (§0), Phosphor nur noch in älteren Posts | > -> Drei Punkte widersprechen den bisherigen Regeln und sind noch nicht -> entschieden: die Schatten (`--shadow-md`, `--shadow-lg`) gegen §5 „Keine -> Schatten“, der Rahmen `#E5E5E5` gegen `#D5DBE1` aus §1a, Feather gegen -> Phosphor. Die Werte sind hier noch nicht gespiegelt. +> Entschieden am 20.10.2026: Oberflächen nehmen Rahmen `#E5E5E5` und +> Feather/Lucide aus dem Produkt (§0). Offen bleiben die Schatten +> (`--shadow-md`, `--shadow-lg`) gegen §5 „Keine Schatten“: In den Zeichnungen +> lassen wir sie weg, siehe `komponenten.md`. Alle Marken-Werte stammen aus der Website, nicht aus diesem Repo. Bei Zweifel **dort nachschauen, nicht hier raten**: