# CSS selbstdokumentierend machen: BEM, ITCSS und die Bootstrap-Frage

Ziel: **Dem CSS ansehen, wofür es ist.** Eine Klasse soll sagen, zu welcher
Komponente sie gehört und welche Rolle sie darin spielt — ohne Rätselraten, ohne
Rückwärts-Lesen des PHP-Markups. Dieses Dokument analysiert den echten
CSS-Bestand, zeigt an konkreten Beispielen, wie BEM (Block\_\_Element--Modifier)
das leistet, klärt die Koexistenz mit **Bootstrap 4.3.1** und empfiehlt begründet
eine Gesamt­strategie samt Alternativen.

Es baut auf [UI-Verbesserung](ui-verbesserung.md) und
[Frontend-Abhängigkeiten](frontend-abhaengigkeiten.md) auf und widerspricht ihnen
nicht: Die dort geplante Konsolidierung zu `css/app.css`, das Token-CSS und der
Vorrang von Bootstrap-Utilities sind die Grundlage, auf der die
Namenskonvention hier aufsetzt.

> **Umsetzungsstand** (siehe `CHANGELOG.md`): Der *strukturelle* Teil ist erledigt,
> der *Benennungs*-Teil bewusst anders gelöst als hier skizziert. **Erledigt:** die
> neun `style.css` sind zu **einer** `css/app.css` konsolidiert, totes CSS ist raus
> (u. a. der `.termin-item`-Block, die Legacy-`#header`-Regeln), das hartkodierte
> `#4578A5` **im CSS** ist durch `var(--primary)` ersetzt, FontAwesome auf eine
> Version vereinheitlicht. Die Widersprüche (`.col1`, `.content`, `.table`-Override)
> löst die Umsetzung jedoch **nicht** über den hier vorgeschlagenen `lbm-`-Namespace,
> sondern über **seiten-Scoping per Body-Kontextklasse** (`page-detail`, `page-search`
> … in `partials/head.php`), unter der `css/app.css` die seiteneigenen Regeln kapselt.
> Das erreicht das Kollisionsziel ohne die projektweite Umbenennung — die „BEM light"-
> Blocknamen (§7) sind damit **nicht** umgesetzt und angesichts der möglichen
> Laravel-Migration (§5/§6) auch nicht mehr zwingend. **Noch offen:** Token-Schicht
> vervollständigen (`custom-colors.css` trägt bislang nur `--primary`), die 36
> Inline-Styles in den PHP-`echo`-Ausgaben auf Utilities/Token umstellen (z. B.
> `settings/index.php:64,110`, `cron/termin_reminder.php`). Die Analyse in §1
> beschreibt den **Ausgangs**befund vor der Konsolidierung.

## 1. Befund: Warum man dem CSS heute *nicht* ansieht, wofür es ist

### 1.1 Neun verstreute Stylesheets, teils widersprüchlich

Eigenes CSS (ohne die Bibliotheken unter `library/`) liegt in neun Dateien:

| Datei | Zeilen | Bytes | Grobes Muster |
|---|---|---|---|
| `style.css` | 317 | 5286 | Tabelle `.bp`, `#header`, Termin-Sidebar |
| `settings/style.css` | 99 | 1335 | `.col1`–`.col4`, `.subHead`, `.updCol*` |
| `search/style.css` | 161 | 1898 | `.col1`–`.col4`, `.colForm0`–`.colForm5`, `#header` |
| `dokumente/style.css` | 167 | 2520 | `.ordner-box-1/2/3`, `.mybutton`, `ul.tree` |
| `detail/style.css` | 122 | 1685 | `.ordner-box-*`, `#header`, `table.detail` |
| `detail/comment/style.css` | 97 | 1433 | `.termin-row`, `.commentTable`, Badges |
| `news/style.css` | 47 | 530 | `.col1`–`.col3`, `.subtitle` |
| `login/style.css` | 44 | 816 | `.form-signin` |
| `css/custom-colors.css` | 17 | 697 | Design-Token `--primary` + Bootstrap-Overrides |

Dieselben Selektoren tragen **je nach Datei andere Werte** — das ist der Kern des
Problems:

- `.content` ist in `style.css:5` `max-width: 1250px`, in `search/style.css:62`
  aber `width: 1100px`. Welcher gilt, hängt davon ab, welche `style.css` die Seite
  lädt.
- `.col1` bedeutet in `settings/style.css:33` `width: 70%`, in
  `search/style.css:1` `15%`, in `news/style.css:1` ebenfalls `15%`. Der Name
  `col1` sagt *nichts* über Zweck oder Breite.
- `#header { background-color: blue }` steht dreifach (`style.css:172`,
  `search/style.css:116`, `detail/style.css:77`) — dennoch rendert die Navbar
  heute über Bootstrap `bg-primary` (`index.php:10`), die `#header`-Regeln sind
  toter Ballast einer früheren Navigation.
- `body { font-family: "Helvetica" }` ist sechsfach kopiert.

### 1.2 Nichtssagende Namen

Die Namen benennen Position oder Zufall, nicht Zweck:

- `.col1`–`.col4`, `.colForm0`–`.colForm5` (`search/style.css:17-41`) — reine
  Nummerierung.
- `.ordner-box-1`, `.ordner-box-1u`, `.ordner-box-2`, `.ordner-box-3`
  (`dokumente/style.css:60-87`) — was unterscheidet Box 2 von Box 3? Nur der Blick
  ins Markup verrät es.
- `.mybutton`, `.myinput` (`dokumente/style.css:40-54`), `.subHead`
  (`settings/style.css:16`), `.folder1`/`.folder2` (`dokumente/style.css:94-104`).

### 1.3 Totes CSS, das man für lebendig hält

`style.css:233-291` definiert einen ausführlichen `.termin-item`-Block
(`.termin-item`, `.termin-item-header`, `.termin-item-date`, `.termin-item-title`,
`.termin-item-projekt`, `.termin-item-users`, Modifier `.termin-urgent`). **Nichts
davon wird noch benutzt**: `termineSidebar.php:29` rendert die Termin-Karten
längst mit Bootstrap `card` + `card-header`/`card-body`/`card-footer`. Nur die
*Hülle* `.termine-sidebar`/`.termine-header`/`.termine-list`/`.termine-empty` lebt
noch (`index.php:99-102`, `termineSidebar.php:9,14`). Wer die CSS liest, kann tote
von lebender Regel nicht unterscheiden — genau das soll die Strategie beheben.

### 1.4 Kollisionen mit Bootstrap

Eigene Regeln überschreiben Bootstrap-Klassen unter demselben Namen:

- `.table { width: 60% }` (`settings/style.css:9`) kapert Bootstraps `.table`.
- `.badge-danger`/`.badge-info` neu definiert (`detail/comment/style.css:92-97`) —
  dupliziert Bootstrap-Werte hart kodiert.
- `.selected { background-color: #0005f1 }` (`dokumente/style.css:117`),
  `.subtitle` mit/ohne Hintergrund (`settings/style.css:72` vs. `news/style.css:21`).

### 1.5 Inline-Styles und hartkodierte Farben trotz Token

36 `style=`-Attribute stecken in PHP-`echo`-Ausgaben. Die Marken­farbe `#4578A5`
ist als Token `--primary` vorhanden (`css/custom-colors.css:2`), wird aber
weiterhin hart kodiert: `settings/index.php:65,111`, `style.css:123,220,224,280`,
`settings/style.css:29,74`, `cron/termin_reminder.php:96,103`.

**Fazit:** Nicht die Menge an CSS ist das Problem (gut 1150 Zeilen eigenes CSS),
sondern die fehlende **Zuordnung Klasse → Komponente → Rolle** und die
Zerstreuung über neun Dateien mit widersprüchlichen Definitionen.

## 2. Was BEM ist und was es hier löst

BEM strukturiert Klassennamen nach einer festen Grammatik:

- **Block** — eine eigenständige Komponente: `termine-sidebar`, `bp-table`,
  `termin-card`.
- **Element** — ein Teil, der nur im Block Sinn ergibt, mit `__`:
  `bp-table__row`, `termine-sidebar__title`.
- **Modifier** — eine Variante von Block oder Element, mit `--`:
  `termin-card--frist`, `bp-table__row--collapsed`.

Der Gewinn ist genau das geforderte Ziel: Am Namen `bp-table__row--collapsed` liest
man Komponente (`bp-table`), Teil (`row`) und Zustand (`collapsed`) ab. Die flache
Spezifität (immer eine Klasse, nie verschachtelte Selektoren) macht `!important`
überflüssig und beendet Kollisionen wie `.col1`, weil jeder Name seinen Block
trägt.

### 2.1 Beispiel A — Termin-Sidebar

**Heute** (`index.php:99-102`, `style.css:204-231`):

```html
<div class="termine-sidebar">
    <h5 class="termine-header">Termine</h5>
    <div class="termine-list">…</div>
</div>
```

```css
.termine-sidebar { … }
.termine-header  { border-bottom: 2px solid #4578A5; }
.termine-header i { color: #4578A5; }
.termine-list    { display: flex; flex-direction: column; gap: 10px; }
```

`termine-` ist ein informeller Präfix, aber `termine-header` und der tote
`termin-item-header` (`style.css:253`) sehen fast gleich aus — Singular/Plural
entscheidet, und das ist nicht erkennbar. **Nach BEM** wird der Block eindeutig,
die Farbe kommt aus dem Token:

```html
<div class="lbm-termine">
    <h5 class="lbm-termine__title">Termine</h5>
    <div class="lbm-termine__list">…</div>
</div>
```

```css
.lbm-termine__title        { border-bottom: 2px solid var(--primary); }
.lbm-termine__title-icon   { color: var(--primary); }
.lbm-termine__list         { display: flex; flex-direction: column; gap: var(--space-2); }
```

### 2.2 Beispiel B — Aufklappbare Brennpunkt-Tabelle

**Heute** (`bpTable.php:120-135`, `style.css:29-140`): Die Zeilentypen tragen
teils sprechende, teils technische Klassen gemischt mit IDs und Inline-Style:

```html
<tr onClick="setVisibility('kntID3','kntID3-gemeinde')">
    <td colspan="2" id="kntID3" class="kanton table-secondary">▸ Luzern</td>
</tr>
<tr class="kntID3-gemeinde" style="display:none;visibility:hidden" …>
    <td class="gemeinde table-secondary" …>▸ Malters</td>
</tr>
<tr class="brennpunkt kntID3 gemID12" style="display:none;visibility:hidden" …>
```

Problematisch: `.kanton`/`.gemeinde`/`.brennpunkt` sind die *Rolle*, aber
`kntID3`/`gemID12` sind zugleich **funktionale JS-Hooks** (siehe §9), und
der Aufklapp-Zustand steckt im Inline-Style, nicht im Klassennamen. **Nach BEM**
wird die Rolle zur Element-Klasse, der Zustand zum Modifier, die JS-Hooks werden
per `data-`-Attribut von der Optik getrennt:

```html
<tr class="lbm-bptable__group" data-group="kntID3" data-target="kntID3-gemeinde">
    <td class="lbm-bptable__cell lbm-bptable__cell--kanton" colspan="2">▸ Luzern</td>
</tr>
<tr class="lbm-bptable__group lbm-bptable__group--collapsed" data-group="gemID12">
    <td class="lbm-bptable__cell lbm-bptable__cell--gemeinde">▸ Malters</td>
</tr>
<tr class="lbm-bptable__row lbm-bptable__row--collapsed" data-project="42">
```

```css
.lbm-bptable                       { /* ex table.bp */ border-radius: var(--radius); … }
.lbm-bptable__cell--kanton         { /* ex td.kanton */ background: var(--surface-2); … }
.lbm-bptable__cell--gemeinde       { /* ex td.gemeinde */ … }
.lbm-bptable__row--collapsed       { display: none; }   /* ersetzt Inline-Style */
```

Hier zeigt sich der Doppelnutzen: BEM macht den **Zustand** (`--collapsed`) zur
Klasse, die das JS toggeln kann — das ersetzt das direkte
`element.style.display`-Gefummel aus `script.js:12-14`.

### 2.3 Beispiel C — `#head01` / `.subHead` in den Einstellungen

**Heute** (`settings/index.php:114`, `settings/style.css:16-31`):

```html
<div id="head01" class="subHead">…</div>
```

```css
.subHead { background-color: #4578A5; border-color: darkblue; cursor: pointer; … }
```

`#head01` ist eine nichtssagende ID, an der zugleich ein Klick-Handler hängt
(`settings/index.php:151`), und `.subHead` verrät nicht, wofür der Kopf steht.
**Nach BEM** (Optik über Klasse, Klick über `data-`):

```html
<div class="lbm-collapse-head" data-collapse="update-info">…</div>
```

```css
.lbm-collapse-head { background: var(--primary); cursor: pointer; … }
```

## 3. Die Bootstrap-Frage: Koexistenz statt Konkurrenz

Bootstrap 4.3.1 ist bestätigt (`library/bootstrap/bootstrap.min.css:2`, geladen in
`partials/head.php:33`) und bleibt (kein BS5-Upgrade in diesem Vorhaben, siehe
[Frontend-Abhängigkeiten](frontend-abhaengigkeiten.md)). Bootstrap folgt **nicht**
BEM: `btn btn-primary`, `card-header`, `text-white`, `col-lg-8` sind
Utility-/Komponenten-Klassen ohne `__`/`--`-Grammatik. BEM und Bootstrap müssen
sich also eine Seite teilen. Die tragfähige Grenze:

**Bootstrap behält die Zuständigkeit für:**

- **Layout & Grid**: `row`, `col-lg-8`, `container` (`index.php:88-108`).
- **Spacing-/Text-Utilities**: `mb-3`, `m-auto`, `text-white`, `text-right` — genau
  die Ersetzung der Inline-Styles, die [UI-Verbesserung](ui-verbesserung.md#2) plant.
- **Fertige Komponenten, die passen**: `card`, `dropdown`, `modal`, `badge`,
  `table` (Basis), Navbar. Die Termin-Karte (`termineSidebar.php:29`) ist das
  Vorbild — sie ist bereits reines Bootstrap und braucht **kein** eigenes CSS.

**BEM (eigene Blöcke) übernimmt nur, was Bootstrap nicht abdeckt:**

- Die aufklappbare Kanton/Gemeinde/Brennpunkt-Tabelle (`bpTable.php`) — eine
  echte Eigenentwicklung.
- Die Termin-Sidebar-Hülle, den Dokumente-Baum (`ul.tree`,
  `dokumente/style.css:148-167`), die Ordner-Leiste (`.ordner-box-*`).

### 3.1 Drei Regeln für die Koexistenz

1. **Namespace `lbm-` für jeden eigenen Block.** Das trennt Eigenes sichtbar von
   Bootstrap und verhindert Kollisionen wie `.table` (`settings/style.css:9`) oder
   `.badge-danger` (`detail/comment/style.css:92`), die heute Bootstrap kapern.
   Am Präfix `lbm-` erkennt man sofort: „das haben wir gebaut, nicht das Framework".

2. **`!important` und ID-Selektoren vermeiden.** Die 20+ `!important` in
   `style.css` (z. B. `:64,66,72,101`) und alle in `custom-colors.css` existieren
   nur, weil eigene Regeln gegen Bootstrap-Spezifität ankämpfen. Mit flachen
   BEM-Klassen (Spezifität 0-1-0) und der Ladereihenfolge aus Abschnitt 4 (eigenes
   CSS nach Bootstrap) verschwindet der Grund. Wo Bootstrap gezielt anzupassen ist,
   geschieht das über **Design-Token** (`--primary` in `custom-colors.css`), nicht
   über Selektor-Krieg.

3. **Bootstrap-Utility vor eigener Klasse.** Faustregel aus
   [UI-Verbesserung §2](ui-verbesserung.md): erst Utility (`mb-3`), dann Token
   (`var(--primary)`), und nur wenn beides fehlt eine `lbm-`-Klasse. Ein eigener
   Block mischt beides: `<div class="lbm-termine mb-3">` — BEM für Identität,
   Bootstrap-Utility für Abstand.

### 3.2 Was NICHT BEM wird

Bootstrap-eigene Klassen werden **nicht** umbenannt — `col-lg-8` bleibt
`col-lg-8`, nicht `lbm-grid__col`. Utilities bleiben Utilities. BEM greift
ausschließlich für die eigenen Blöcke.

## 4. Alternativen — abgewogen für *dieses* Projekt

Das Projekt ist klein (~1150 Zeilen eigenes CSS), frameworklos, Bootstrap-4-basiert,
ohne Build-Schritt (Deploy per `git pull`, siehe
[Frontend-Abhängigkeiten §1](frontend-abhaengigkeiten.md)), gepflegt von wenigen
Personen. Danach richtet sich die Bewertung.

### (a) Utility-first / bei Bootstrap-Utilities + Token bleiben

Kaum eigenes CSS; fast alles über `mb-3`, `text-white`, `d-flex` etc., Farben über
Token.

- **Pro:** Deckt die 36 Inline-Styles direkt ab; null neue Konzepte; exakt das,
  was [UI-Verbesserung §2](ui-verbesserung.md) ohnehin vorsieht.
- **Contra:** Für echte Komponenten (aufklappbare Tabelle, Dokumente-Baum) reichen
  Utilities nicht — es entstünden lange, unlesbare Klassenketten im PHP-`echo`, und
  die *Selbst­dokumentation* („was ist dieser Block?") ginge verloren. Utility-Ketten
  sagen *wie es aussieht*, nicht *was es ist*.

### (b) ITCSS (Inverted Triangle CSS)

Keine Namenskonvention, sondern eine **Schichtung** einer Datei nach steigender
Spezifität: *Settings* (Token) → *Tools* → *Generic* (Reset) → *Elements* (bare
Tags) → *Objects* → *Components* → *Utilities*.

- **Pro:** Löst genau das Zerstreuungs- und Reihenfolge-Problem aus Abschnitt 1.1;
  kombiniert sich hervorragend mit Bootstrap (Bootstrap = Generic+Objects+Components
  vorweg, eigenes CSS in den späteren Schichten) und mit BEM (ITCSS ordnet, BEM
  benennt). Beantwortet die `.content`-Widersprüche strukturell.
- **Contra:** Ordnet, aber **benennt nicht** — `col1` bliebe `col1`. ITCSS allein
  macht das CSS nicht selbstdokumentierend.

### (c) BEM

Siehe Abschnitt 2.

- **Pro:** Trifft das Kernziel „ansehen, wofür es ist" direkter als jede
  Alternative; flache Spezifität eliminiert `!important`; klare Grenze zu Bootstrap
  über den `lbm-`-Namespace.
- **Contra:** Sagt nichts über Datei-Organisation und Ladereihenfolge (das leistet
  ITCSS); etwas mehr Tipparbeit im Markup; verlangt Disziplin bei
  Block-Zuschnitten.

### (d) CUBE CSS

*Composition, Utility, Block, Exception* — bewusst utility-lastig, Blöcke nur wo
nötig, lockerer als BEM.

- **Pro:** Passt philosophisch zu „Bootstrap-Utilities + wenige eigene Blöcke".
- **Contra:** Jünger, weniger verbreitet, unschärfere Namensregeln — für ein
  kleines Wartungs­team ohne Frontend-Spezialisierung ist die Strenge von BEM
  eindeutiger und leichter zu prüfen.

### Zwischenfazit (vor der Laravel-Frage)

Betrachtet man das Projekt *isoliert im heutigen Zustand*, genügt keine Option
allein — sie adressieren verschiedene Achsen, und ihre Kombination wäre technisch
das Naheliegende:

- **ITCSS** ordnet die *eine* konsolidierte `css/app.css` (das Zerstreuungsproblem).
- **BEM mit `lbm-`-Präfix** benennt die eigenen Blöcke selbstdokumentierend und
  hält sie kollisionsfrei neben Bootstrap (das Namensproblem).
- **Bootstrap-Utilities + Token** ersetzen Inline-Styles und tragen Layout/Spacing
  (das Inline-Style-Problem).

Konkret sieht `css/app.css` so aus (die verstreuten `style.css` fließen hier ein,
`custom-colors.css` bleibt die reine Token-Schicht davor):

```css
/* 1 SETTINGS  – Token (bleibt in css/custom-colors.css, davor geladen) */
/* 2 GENERIC   – minimaler Reset, body font-family (heute 6× dupliziert) */
/* 3 ELEMENTS  – bare a, table, textarea */
/* 4 OBJECTS   – Layout ohne Kosmetik: .lbm-content, .lbm-nav-content */
/* 5 COMPONENTS– die eigenen Blöcke:
   .lbm-bptable, .lbm-termine, .lbm-doctree, .lbm-ordnerbar, .lbm-signin */
/* 6 UTILITIES – nur was Bootstrap NICHT hat (sonst Bootstrap nutzen) */
```

Diese Kombination macht das CSS lesbar (BEM), aufgeräumt (ITCSS) und schlank
(Bootstrap trägt die Last), ohne Build-Schritt, ohne Framework, ohne
Bootstrap-Upgrade — und deckt sich mit der Richtung der bestehenden Doku.

**Aber ein entscheidender Faktor fehlt in dieser isolierten Betrachtung:** die
*Haltbarkeit* der Arbeit gegenüber einer möglichen späteren Laravel-Migration. Der
volle BEM-Ausbau könnte sich als Wegwerfarbeit erweisen. Bevor die Empfehlung
steht, wägen §5 (Laravel) und §6 (Branchenstandards) das ab; die verbindliche
Endempfehlung steht in §7 — sie korrigiert dieses Zwischenfazit an genau einem
Punkt (Umfang der BEM-Umbenennung).

## 5. CSS im Hinblick auf eine mögliche Laravel-Migration

Perspektivisch könnte das Projekt auf **Laravel** umziehen. Der moderne
Laravel-Default-Stack (seit ~v9) ist **Vite** (Asset-Bundling + HMR),
**Blade-Components** (component-scoped Markup) und **Tailwind** (utility-first).
Die früheren Bootstrap-Scaffolds (`laravel/ui`) gelten als Legacy; die aktuellen
Starter Kits (Breeze, Jetstream) liefern Tailwind. Das heißt nicht, dass Bootstrap
in Laravel unmöglich ist — es ist über Vite problemlos einbindbar — aber es ist
nicht mehr der Pfad des geringsten Widerstands.

Leitfrage für heute: **Welche CSS-Arbeit überlebt einen Laravel-Umzug, welche
würde er entwerten?**

### (a) Durable vs. Wegwerfarbeit

**Durable** (zahlt sich in *jedem* Szenario aus):

- **Design-Token als CSS Custom Properties** (`css/custom-colors.css`). Tailwind v4
  definiert sein Theme selbst über CSS-Variablen (`@theme`), Tailwind v3 über
  `tailwind.config`. In beiden Fällen ist `--primary: #4578A5` die Quelle, die 1:1
  übernommen wird. `color-mix()` (bereits in `custom-colors.css:11`) ist natives
  CSS und überlebt ohnehin alles.
- **Konsolidierung** der neun `style.css` zu einer `css/app.css`. Vite bündelt
  ohnehin einen `app.css`-Entry — eine Datei ist der Startpunkt, neun sind
  Migrationsballast.
- **Totes CSS entfernen** (der `.termin-item`-Block `style.css:233-291`, die toten
  `#header`-Regeln). Weniger zu migrieren ist immer richtig.
- **Optik/Funktion trennen** (Klasse vs. `id`/`data-`, §9). Blade-Components und
  ggf. Tailwind erwarten genau diese Trennung; die `setVisibility()`-Entkopplung
  ist reine Hygiene.
- **Semantische Komponenten-Identität** — dass ein Block „termine" oder „bptable"
  *ist*. Dieser Name wird in Laravel zum **Blade-Component-Namen** (`<x-termine>`,
  `<x-bptable>`). Die Erkenntnis, *wo* eine Komponente anfängt, ist durable,
  unabhängig davon, ob sie am Ende mit Bootstrap-, BEM- oder Tailwind-Klassen
  gefüllt wird.

**Wegwerfarbeit** (nur wertvoll, solange wir bei plain-CSS-Bootstrap bleiben):

- Die **schwere, projektweite BEM-Umbenennung** der `__element--modifier`-Bäume
  über alle 36 `echo`-Stellen. Zieht Laravel Blade + Tailwind ein, wird das Markup
  in Components neu geschrieben und die feingranularen BEM-Klassen durch Utilities
  ersetzt — die mechanische Umbenennung wäre zweimal Arbeit am selben Markup. Der
  **Block-Name überlebt, der Element/Modifier-Apparat nicht.**
- Eigene Utility-Klassen, die Bootstrap-Utilities duplizieren — Tailwind ersetzt
  sie ohnehin.

### (b) „Kein Build, `dist/` committen" vs. Laravels Vite-Pipeline

Der heutige Ansatz (keine Build-Stufe, `dist/` nach `library/` committen,
`git-pull`-Deploy; [Frontend-Abhängigkeiten §1](frontend-abhaengigkeiten.md)) ist
für den Bootstrap-4-Bestand richtig und bleibt es bis zu einem Framework-Wechsel.
Er ist aber explizit eine **Brücke, keine durable Investition**: Laravel setzt Vite
voraus (`npm run build` erzeugt gehashte Assets in `public/build`, referenziert via
`@vite`), ein Build-Schritt kommt mit der Migration zwangsläufig. Konsequenz für
jetzt: keine Energie in ausgefeilte Build-freie Tooling-Konstruktionen stecken, die
Vite später wegräumt. Die **Token-Datei und die eine `app.css`** sind hingegen
genau die Artefakte, die ein Vite-Entry direkt importiert — sie überstehen den
Übergang ohne Änderung.

### (c) Bootstrap behalten vs. auf Tailwind wechseln

Bootstrap ist in Laravel via Vite lauffähig (`import 'bootstrap'`, SCSS-Theming).
Ein Wechsel auf Tailwind ist **kein CSS-Refactoring, sondern ein visuelles
Redesign plus Markup-Neuschrift jeder Komponente** — großer Aufwand, verzahnt mit
dem ohnehin offenen BS4→BS5-Thema. **Empfehlung: jetzt Bootstrap behalten.** Einen
Tailwind-Wechsel weder vorwegnehmen noch durch heutige Arbeit verbauen. Der
richtige Entscheidungszeitpunkt für Tailwind ist der Laravel-Entscheid selbst —
dann liegt der Redesign-Aufwand ohnehin auf dem Tisch und Tailwind ist der
Default-Pfad. Bis dahin gilt die Doppelregel: nichts tun, das *nur* bei dauerhaftem
Bootstrap-Verbleib zahlt (schwere BEM-Bäume), und nichts, das Tailwind vorwegnimmt
(Markup ohne Framework auf Utilities umbauen).

### (d) Blade-Components und Komponenten-CSS

Blade-Components kapseln Markup pro Komponente (`<x-termine-sidebar>`). Das passt
exakt zur „ein Block = eine Komponente"-Sicht: Der semantische Block-Name aus
unserer Arbeit wird zum Component-Namen, das heute in `bpTable.php` /
`termineSidebar.php` verstreute `echo`-Markup zieht in *eine* Blade-Datei.
**Component-scoped Markup macht global-eindeutige Klassennamen — BEMs Kernnutzen
gegen Kollisionen — weniger wichtig**, weil die Kapselung die Kollision verhindert.
Genau deshalb ist die schwere BEM-Disziplin in einem Blade-Ziel teilweise
redundant, während die Komponenten-Grenze (welcher Block?) genau die Information
ist, die Blade braucht. Fazit: **in Komponenten denken, die Namensgebung aber leicht
halten.**

## 6. Branchenstandards heute

Eine ehrliche Einordnung von BEM gegenüber dem aktuellen Mainstream:

- **Utility-first / Tailwind dominiert Greenfield.** Für neue Projekte *mit
  Build-Schritt* ist utility-first die Norm; Klassen wie `mb-3 text-primary` sind
  dort Regel, nicht Ausnahme — und Bootstraps eigene Utilities gehen in dieselbe
  Richtung.
- **Design-Tokens sind Standard, nicht mehr optional** — als CSS Custom Properties,
  zunehmend nach dem W3C-Design-Tokens-Format. `custom-colors.css` ist damit auf
  aktuellem Stand.
- **Natives CSS hat aufgeholt**: Custom Properties (überall), **Cascade Layers**
  (`@layer`, ordnet Spezifität nativ — ein Teil dessen, wofür man früher
  ITCSS-Disziplin brauchte), CSS Nesting, `:has()`, `color-mix()` (nutzt das
  Projekt bereits, `custom-colors.css:11`). Manches, wofür BEM/ITCSS Konventionen
  erfand, löst die Plattform heute selbst.
- **Component-scoped CSS** (Vue/Svelte `scoped`, CSS Modules, Astro; in Laravel via
  Blade + Vite) verlagert die Kollisionsvermeidung von der Namenskonvention in die
  Werkzeugkette.

**Wo BEM heute noch richtig ist:** framework-agnostische Komponentenbibliotheken,
die als reines CSS ausgeliefert werden; Build-lose Umgebungen; Teams, die
explizite, sprechende Namen ohne Tooling-Magie wollen. BEM ist solide und
keineswegs „falsch" — aber **traditionell**, und sein stärkster Nutzen (globale
Kollisionsfreiheit per Namensdisziplin) wird von component-scoped CSS und Cascade
Layers zunehmend übernommen. **Wo überholt:** sobald ein Build-Schritt und/oder
Utility-first vorhanden sind, ist die schwere BEM-Notation oft mehr Zeremonie als
Nutzen.

**Für UNSER Projekt:** Zwei BEM-Nutzenargumente greifen *heute* — kein
Build-Schritt und framework-agnostisch — beide aber nur so lange, wie kein Laravel
kommt. Das mögliche Laravel-Ziel untergräbt die Investition in schweres BEM, weil
es Build + component-scoped + (wahrscheinlich) Tailwind mitbringt. Die durable
Essenz aus BEM ist **nicht** die `__`/`--`-Notation, sondern zwei Ideen: (1) in
Komponenten/Blöcken denken und (2) sprechende, absichtsvolle Namen. Beides nehmen
wir mit — ohne die volle Mechanik.

## 7. Endempfehlung: durable jetzt, Wegwerfarbeit vermeiden

Die Kombination aus §4 (ITCSS-Ordnung + Bootstrap-Utilities + Token) bleibt
technisch richtig — mit **einer Korrektur** im Licht von §5/§6: Die BEM-Komponente
wird auf ihre *durable Essenz* reduziert. **Keine schwere, projektweite
`__element--modifier`-Umbenennung**; stattdessen leichtgewichtige, sprechende
Block-Namen, die ein späterer Laravel/Blade/Tailwind-Weg nicht entwertet.

Die Namenskonvention als **„BEM light"**:

- Jede echte Eigen-Komponente bekommt **einen** sprechenden, genamespaceten
  Block-Namen: `lbm-termine`, `lbm-bptable`, `lbm-doctree`, `lbm-signin`. Dieser
  Name ist zugleich der spätere Blade-Component-Name.
- **Element-Klassen** (`lbm-bptable__row`) **nur dort, wo ein echter Style-Hook
  oder JS-Zustand sie braucht** (etwa der Aufklapp-Zustand statt Inline-Style) —
  nicht flächendeckend für jedes `<td>`.
- **Modifier** für echte Zustände/Varianten (`--collapsed`, `--frist`), wo sie
  Inline-Styles oder JS-Fummelei ersetzen und damit ohnehin Hygiene sind.
- Alles Übrige bleibt **Bootstrap-Utility**.

So entsteht kein CSS, das ein Laravel-Umzug zweimal anfassen muss: Block-Namen
wandern zu Blade-Components, die wenigen Zustands-Modifier lassen sich im Zweifel
gegen Tailwind-Utilities tauschen — der Aufwand bleibt minimal, weil die Menge
klein gehalten wurde.

### Was tun wir JETZT (durable, unabhängig von Laravel)

1. **Token-Schicht** in `custom-colors.css` vervollständigen (Graustufen,
   `--radius`, `--space-*`, Sidebar-Offset). → wird in Laravel zu Tailwind
   `@theme` / `config`.
2. **Neun `style.css` zu einer `css/app.css`** konsolidieren, Widersprüche
   (`.content`, `.col1`, `#header`) auflösen; Schichtung wo möglich über natives
   **`@layer`** statt bloßer Kommentar-Sektionen. → Vite-Entry-tauglich.
3. **Totes CSS entfernen** (`.termin-item`-Block `style.css:233-291`, tote
   `#header`-Regeln).
4. **Inline-Styles → Bootstrap-Utilities + Token** (36 Stellen, `#4578A5` →
   `var(--primary)`).
5. **Kollisionen zurückbauen** (`.table` `settings/style.css:9`, `.badge-*`
   `detail/comment/style.css:92-97`), zugehörige `!important` entfernen.
6. **In Komponenten denken**: pro echtem Block *einen* sprechenden `lbm-`-Namen
   vergeben und die schlimmsten nichtssagenden/kollidierenden Namen (`.col1`,
   `.subHead`, `.mybutton`) mitziehen — leichtgewichtig, kein Vollausbau.
   Optik(Klasse) / Funktion(`id`, `data-`) trennen, wo es `setVisibility()` & Co.
   entkoppelt (§9).

### Was erst BEI einem Laravel-Entscheid

- **Vite einführen** (Build-Schritt), die `dist/`-Brücke abbauen.
- **Bootstrap behalten vs. Tailwind** entscheiden — der natürliche Moment,
  verzahnt mit BS4→BS5.
- **Komponenten in Blade-Components überführen**; die `lbm-`-Block-Namen werden
  Component-Namen, das `echo`-Markup zieht in `.blade.php`.
- **Token in `@theme`/`config` übernehmen** (Copy der Custom Properties).
- Erst hier, *falls* Tailwind: feingranulares Styling auf Utilities umstellen —
  dann ist es kein Doppelaufwand, weil wir es jetzt gar nicht erst aufgebaut haben.

**Kurz:** Wir investieren jetzt in das, was jeder Weg mitnimmt (Token, eine
`app.css`, totes CSS raus, sprechende Komponenten-Namen, Optik/Funktion getrennt)
und verzichten bewusst auf die schwere BEM-Mechanik, die ein Laravel/Tailwind-Ziel
wieder verwerfen würde.

## 8. Umsetzungs-Skizze (inkrementell, Golden-Master-abgesichert)

Der Golden-Master (`tests/goldenmaster.sh`) vergleicht die gerenderte HTML-Ausgabe
gegen eine Baseline — dieselbe Absicherung wie in
[UI-Verbesserung §4](ui-verbesserung.md). CSS-Umbenennung ändert Markup-Bytes,
also gilt durchweg: **Diff bewusst prüfen, im Browser sichten, dann Baseline
nachziehen.** Die folgende Reihenfolge ist die abgesicherte Ausführung der
„Was jetzt"-Liste aus §7 (setzt die Head-/CSS-Konsolidierung aus der bestehenden
Doku als Schritt 0 voraus):

1. **Token-Schicht vervollständigen.** In `css/custom-colors.css` neben `--primary`
   die real vorkommenden Werte als Token ergänzen: Graustufen (`#f8f9fa`, `#e9ecef`,
   `#dee2e6`, `#495057`, `#6c757d`), `--radius`, `--space-*`, Sidebar-Offset. Erst
   Token, dann kann alles Weitere sie konsumieren. Kein Markup-Effekt → leerer Diff.

2. **Konsolidieren zu `css/app.css` nach ITCSS.** Die neun `style.css`
   zusammenführen, dabei die Widersprüche (`.content`, `.col1`, `#header`) auflösen
   und **totes CSS entfernen** — zuerst der `.termin-item`-Block
   (`style.css:233-291`) und die `#header`-Regeln. Die seitenweisen `$extraHead`-
   Einträge (z. B. `index.php:5`) auf `app.css` umstellen. Sichttest pro Seitentyp.

3. **Sprechende Block-Namen vergeben — leichtgewichtig, je Block ein Commit**
   („BEM light", §7). Nicht global auf einmal, nicht als voller
   `__element--modifier`-Ausbau. Pro Block: (a) *einen* `lbm-<block>`-Namen setzen,
   Element-/Modifier-Klassen nur für echte Style-Hooks/Zustände, (b) Markup im
   PHP-`echo` nachziehen, (c) betroffene JS-Selektoren (§9), (d) `check` +
   Baseline. Reihenfolge nach Isolation: `lbm-signin` (nur `login/`) →
   `lbm-termine` → `lbm-doctree`/`lbm-ordnerbar` (`dokumente/`, `detail/`) →
   `lbm-bptable` (am stärksten mit JS verzahnt, zuletzt).

4. **Inline-Styles auflösen** (gebündelt pro Muster, wie
   [UI-Verbesserung §2](ui-verbesserung.md)): `style='text-align:right'` → `text-right`,
   `#4578A5` → `var(--primary)`, `display:none;visibility:hidden`
   (`bpTable.php:128,132`) → Modifier `lbm-bptable__row--collapsed`.

5. **Kollisionen zurückbauen:** `.table`-Override (`settings/style.css:9`),
   `.badge-*`-Duplikate (`detail/comment/style.css:92-97`) auf Bootstrap-Bordmittel
   bzw. Token zurückführen; die dadurch überflüssigen `!important` entfernen.

## 9. Risiken: CSS-Namen sind hier auch Funktions-Hooks

CSS-Umbenennung ist in diesem Projekt **nicht rein kosmetisch**, weil Klassen und
IDs zugleich von PHP-`echo`-Markup und JS als Selektoren benutzt werden. Vor jeder
Umbenennung prüfen:

- **`setVisibility()` (`script.js:6-25`)** greift Zeilen über
  `getElementsByClassName(className)`, wobei `className` die Gruppen-Klasse
  `$KantonId-gemeinde` bzw. `$GemeindeId` ist (`bpTable.php:122,128,132`), und
  toggelt direkt `style.display`/`style.visibility`. Wird die Tabelle auf BEM
  umgestellt, müssen **CSS-Klasse und JS-Hook getrennt** werden: Optik über
  `lbm-bptable__row`, Funktion über `data-group`/`data-target`, und das Toggeln
  über `classList.toggle('lbm-bptable__row--collapsed')` statt Inline-Style. CSS-
  und JS-Änderung gehören in **denselben** Commit.

- **`#head01`** ist CSS-Kosmetik *und* Klick-Handler (`settings/index.php:114`
  gestylt via `.subHead`, geklickt via `$("#head01")` in `:151`). Beim Umbenennen
  beide Stellen zusammen ändern.

- **`.display-none`** (`settings/style.css:5`) und Bootstraps `d-none`: bei der
  Utility-Umstellung nicht verwechseln; die JS-Logik, die sie toggelt, mit umziehen
  (vgl. `setVisibility()`-Hinweis in [UI-Verbesserung §2](ui-verbesserung.md)).

- **IDs mit funktionaler Rolle** (`#bpTableWrapper` in `index.php:92`, Ziel von
  `filterTableAjax`; `#brennpunktTabelle`, `#favTable`) sind JS-/AJAX-Anker —
  **nicht** anfassen. BEM betrifft die *Klassen* der Optik, die *IDs* der Funktion
  bleiben.

**Grundprinzip für dieses Projekt:** Klassen sind Optik (BEM, `lbm-`), IDs und
`data-`-Attribute sind Funktion (JS/AJAX). Die Umstellung trennt diese heute
vermischten Rollen — das ist zugleich Risiko (jede Umbenennung berührt Markup und
JS) und langfristiger Gewinn (Styling und Verhalten entkoppelt).

## 10. Was hier bewusst NICHT passiert

Kein Bootstrap-4→5-Upgrade (eigenes Vorhaben,
[Frontend-Abhängigkeiten §2](frontend-abhaengigkeiten.md)), kein Build-Schritt/kein
Bundler, kein SCSS, kein CSS-Modules/scoped-CSS (setzt Build voraus), keine
Backend-Änderung. Die Strategie kommt mit reinem, committetem CSS und
Suchen-Ersetzen im Markup aus — passend zum `git-pull`-Deploy.
