From e291ca8438740b672b53e93d59f04da3719fb8ed Mon Sep 17 00:00:00 2001 From: Erik Dunin Date: Mon, 2 Nov 2026 15:07:32 +0100 Subject: [PATCH] =?UTF-8?q?Neues=20Design=20=E2=80=9EBauplan=E2=80=9C,=20D?= =?UTF-8?q?ashboard,=20Notizen-Bereich,=20Seitenleiste?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Gestaltung „Bauplan“: ruhigere Farben, Schriftskala, Abstände im 4-px-Raster, Kalenderwochen und Nummern in Mono-Ziffern, Glas beruhigt - Dashboard „Meine Aufgaben“: Kopf mit Kalenderwoche, Band „Diese Woche“ (Mo–Fr), je Projekt Meine Rolle / Team / Notizen; offene Termine blau hervorgehoben; Monatskalender unverändert - Neuer Bereich „Notizen“ in der Seitenleiste: Notizen aller eigenen Projekte und eigene Notizen ohne Projekt, später einem Projekt zuordenbar - Seitenleiste neu gegliedert (Projekte, Team, Notizen, Studenten, Einstellungen/Admin unten), Admin-Punkte in Personen/Vorgaben/System - Reiter im Projektkopf wie die Seitenleiste hervorgehoben - Behoben: „&…“ in Kommentaren wuchs bei jedem Speichern; bestehende Kommentare werden beim Start repariert - Behoben: Lösch-Rückfrage bei Notizen unlesbar bzw. blieb stehen, Cursor im Notiztitel verdeckt, Dropdown im Dunkelmodus gekachelt Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 120 ++ public/App.html | 141 +-- public/glas.css | 185 +-- public/js/admin/admin.js | 7 + public/js/dashboard/dashboard.js | 200 ++- public/js/einfuehrung.js | 2 +- public/js/globals.js | 1 + public/js/notizen/notizen.js | 408 +++++++ public/js/plan/plan-gantt.js | 6 +- public/js/plan/plan-notizen.js | 7 + public/js/plan/plan-protokoll-todos.js | 2 +- public/js/plan/plan-protokoll.js | 4 +- public/js/plan/plan-schedule.js | 2 +- public/js/store.js | 6 +- public/js/tabs-auth.js | 8 +- public/plan-styles.css | 650 +++++----- public/styles.css | 1543 +++++++++++++----------- server.js | 143 ++- 18 files changed, 2185 insertions(+), 1250 deletions(-) create mode 100644 public/js/notizen/notizen.js diff --git a/CLAUDE.md b/CLAUDE.md index 51661eb..a4dcd4a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1837,6 +1837,58 @@ step into a project explicit. Everything lives in `public/js/auftrag.js`: `plan-gantt.js` both bail out unless `currentTab === 'plan'` — they now run while completely different tabs are on screen. +### Notizen in der Seitenleiste (Tab `notizen`, `js/notizen/notizen.js`) + +Eriks Wunsch: ein eigener Bereich „Notizen“ (Seitenleiste, eigene Gruppe +„Notizen“ unter „Team“, `/Notizen`), in dem jedes Konto die Notizen ALLER seiner +Projekte sieht und **projektunabhängige Notizen** anlegt, die sich später +einem Projekt zuordnen lassen. Gleicher Aufbau wie der Projekt-Reiter +(Liste + Editor, Werkzeugleiste, automatisches Speichern, Anheften, Löschen +zweistufig), dazu oben ein **Projektfilter** (Alle / Ohne Projekt / je +Projekt mit Anzahl) und im Editor die Auswahl **„Projekt“** (Ohne Projekt, +„Meine Projekte“, „Weitere Projekte“ der aktuellen Sitzung) plus „Im Projekt +öffnen“. „+ Neu“ legt im gefilterten Projekt an, sonst ohne Projekt. Eigene +Element-ids (`mn…`) und Funktionen (`mnNeu()`, `mnZuordnen()` …), weil der +Projekt-Reiter gleichzeitig im DOM liegt; Stile aus `.notizen-*` +(plan-styles.css) plus Block „NOTIZEN (Seitenleiste)“ am Ende von +`styles.css`. +- **Server:** Eine projektunabhängige Notiz ist eine Zeile in + `projekt_notizen` mit `project_uid = ''`; sie sieht und ändert NUR ihr + Verfasser (`notizDarf()`). `GET /meine-notizen` liefert die Notizen der + eigenen Projekte (`meineProjektUids()`: jüngste echte Sitzung, zugeordnet + oder mit eigener Aufgabe — Regel wie `dashDaten()`) plus die eigenen + projektunabhängigen, dazu `meineProjekte`. `PUT /projekt-notizen/:id` nimmt + `uid` zum Zuordnen (Ziel-Projekt braucht `proj.plan`, Lösen nur der + Verfasser). `POST`/`PUT`/`DELETE`/`aus-mail` prüfen jetzt selbst + (`notizDarf()`) statt pauschal `requireRecht('proj.plan')`: ohne Projekt + genügt die Anmeldung. `GET /projekt-notizen/anzahl` zählt nur + Projekt-Notizen. +- **Live:** `{typ:'notizen'}` geht in `store.js` an `meineNotizenLive()` und + `notizenLiveAenderung()`; das Echo der eigenen Speicherung (kommt auch im + selben Tab an) wird 3 s lang ausgelassen, sonst verschwände die Anzeige + „Gespeichert ✓“. + +### Seitenleiste — Gliederung nach Arbeitsbereich (11/2026) + +Eriks Wahl „A“ (unslop + Taste-Skill): Die Einträge stehen in Gruppen +(`.sidebar-gruppe` in `App.html`): **Dashboard** · **Projekte** +(Projekte, darunter eingezogen das geöffnete Projekt `#planNavItem` mit +Projektnummer in Mono, Wochenbericht, Terminplan) · **Team** (Auslastung, +Abwesenheiten) · **Notizen** (eigene Gruppe, Eriks Wunsch) · **Studenten** (Plan Checker, ganze Gruppe `nur-recht +wz.checker`) · unten `.sidebar-unten` mit **Einstellungen** und **Admin**. +Die Überschriften „Navigation“ und „Planung“ sind entfallen; der Menüpunkt +heißt weiter „Dashboard“. Admin-Unterpunkte in drei Zwischengruppen +(`.sidebar-subgruppe`: Personen, Vorgaben, System); `adminNavAbgleichen()` +blendet eine Zwischengruppe aus, wenn keiner ihrer Punkte erlaubt ist. +Maße: Einträge 32 px, Icon 18 px + 8 px, Rubrik 16 px über der Gruppe und +4 px über ihren Einträgen. Stile: Block „SEITENLEISTE“ am Ende von +`styles.css`. + +**Falle in CSS-Kommentaren:** `*/` beendet einen Kommentar auch mitten im +Text (z. B. „--dash-*/--wt-*“). Der Rest wird dann als Regel gelesen und +verschluckt die nächste echte Regel. So fehlten zeitweise `--font-mono` +(alle Mono-Ziffern) und `--accent` im automatischen Dunkelmodus. + ### Termin aus Mail (`js/plan/plan-mail-eintrag.js`) Eriks Wunsch: Mailtext per Drag & Drop (markierter Text oder ganze @@ -3604,6 +3656,26 @@ Stile: Block „Verlauf der Vorwochen im Wochenbericht“ (`.bv-*`, ### Dashboard ("Meine Aufgaben", now the default landing tab) +**Stand 11/2026 — Entwurf „Bauplan“ (Eriks Wahl, Vorlage im Artifact +„Projektübersicht neu gestaltet“):** Kopf ohne Begrüßung und Uhr: Zeile +„KW 45, Mo 2. bis Fr 6. November 2026“ (Mono) über dem Titel „Meine +Aufgaben“, rechts die Sitzung (`renderDashboardKopf()`, `dashWochenMontag()`; +`greetingForHour()`/`startDashboardClock()` sind entfallen). Band mit Satz und +vier Zahlen: offene Aufgaben, überfällig (rot), diese Woche fällig (aus +`dashDaten()`, heute bis Sonntag), Freigaben. Neu darunter **„Diese Woche“** +(`renderDashWoche()`): Mo–Fr als Spalten mit den Terminen der eigenen +Projekte, getönt nach eigene Aufgabe / Aufgabe im Projekt / Meilenstein / +überfällig, je Tag höchstens `DASH_WOCHE_JE_TAG` (4). Jeder Projektblock hat +die Zeile **„Meine Rolle | Team | Notizen“** (`renderDashProjektInfo()`, Eriks +Wunsch): Team = übrige Beteiligte als Kürzel-Kreise in Rollenfarben +(`beteiligteJePerson()`/`beteiligtenAvatarHtml()`, höchstens 5, Namen +gekürzt), Notizen nur wenn vorhanden, mit Sprung in den Reiter „Notizen“. +Die Anzahl liefert **`GET /projekt-notizen/anzahl`** (`{uid: {anzahl, +zuletzt}}`, requireAuth), parallel zu `/my-dashboard` geladen +(`dashNotizen`). Die Rollen-Chips im Projektkopf sind dafür entfallen. Der +**Monatskalender bleibt unverändert** (Eriks Vorgabe). Stile: Block „MEINE +AUFGABEN — Entwurf Bauplan“ am Ende von `styles.css`. + **Aktueller Aufbau (Entwurf „B — Monatsblatt“, Eriks Wahl aus drei Varianten):** Kopf und Band wie unten beschrieben; darunter **links „Meine Projekte“**, je Projekt ein Block (`renderDashProjekte()`): eigene Rollen als Chips (gestrichelt @@ -4433,6 +4505,39 @@ minütlich. Ein Klick markiert als gelesen und springt in die Aufgaben des Projekts — gesucht in der AKTUELLEN Sitzung über die Projektnummer (die Projekt-ID wechselt je Sitzung), Planung-Terminpläne über ihre ID. +## Gestaltung „Bauplan“ (unslop-Überarbeitung, 11/2026) + +Eriks Wunsch: das gesamte Design mit dem Skill „unslop“ überarbeiten, Wahl +„volle Überarbeitung“, Glas „beruhigen“. Inhalte, Aufbau und Funktionen sind +unverändert; geändert sind nur Stylesheets, ein paar Texte und Inline-Größen. +- **Richtung:** Planköpfe und Raster eines Bauplans — Flächen fast neutral + (Graphit, leicht kühl), ein Akzent (Logo-Blau `#0f5a85`, dunkel + `#86bfdf`), Farbe nur in Inhalten (Terminplan, Auslastung, Status). + Löst die frühere Dunkel-Palette in Wandtafel-Blau ab. +- **Regeln, die neue Stile einhalten sollten:** Schriftgrößen 11/12/13/15/19/24 + (keine halben Pixel), Gewichte 400/500, 600 nur selten; keine gesperrten + Großbuchstaben-Labels; keine negative Laufweite unter 40px; Abstände im + 4px-Raster (2 und 6 nur in kleinen Bedienelementen); Rundungen 4–6 + (Schildchen/Chips), 8 (Knöpfe, Eingaben, Umschalter), 12–16 (Karten); + Kapselform nur für dünne Balken, Schalter, Zählpunkte und Avatare; keine + farbigen Schatten/Leuchten, keine Emoji, keine Ausrufezeichen in Texten. +- **Kennzeichen:** Kalenderwochen, Projektnummern und Kennzahlen in + Monospace-Ziffern (`--font-mono`, tabellarisch) — Block „BAUPLAN“ am Ende + von `styles.css` (auch: ruhige aktive Navigation, Knopf-Übergänge). +- **Dunkel:** Hauptknöpfe in `--knopf` (`#276f9c`, weiße Schrift 5,6:1), weil + weiße Schrift auf dem hellen Akzent nur ~2:1 erreicht. +- **Glas beruhigt** (`glas.css`): Flächen fast deckend, nur noch zwei + schwache Lichtflächen in den Logo-Blautönen (Mint entfallen), Rundungen + 8/14/16, neutrale Schatten, kein `saturate()`, aktive Einträge mit Haarlinie + statt farbigem Schatten. +- **Ausgenommen:** die Wandtafel (eigenes Design, `--dash-*`/`--wt-*`) und + die Login-Seite bei den Schriftgrößen. +- Das Umbauskript arbeitete je CSS-Regel; geprüft: gleiche Regelzahl wie + vorher (kein Parse-Verlust), keine Überläufe/Großbuchstaben auf Dashboard, + Projekte, Wochenbericht, Auslastung, Abwesenheiten, Einstellungen und in + den Projektbereichen. Methode nach „unslop“ von Damir Sokolovsky + (@heydamir), CC BY 4.0. + ## Glas-Darstellung (`public/glas.css`) Eriks Wahl aus dem Gestaltungsvorschlag „Projektübersicht in Glas“ (Annäherung @@ -4751,6 +4856,21 @@ Abweichungen: Rendern des Wochenberichts mit. `esc()` wandelt jetzt über `String()` um (nur `null`/`undefined` werden zu `''`). +## Behobener Fehler: wachsende „&…“ in Kommentaren (11/2026) + +Eriks Meldung nach dem Sitzungswechsel KW 45: In Kommentaren stand +„ “. Ursache: `sanitizeFormatHtml()` (server.js) +maskierte den Text zwischen den Tags mit `htmlEscape()` — auch ein `&`, das +schon eine fertige Entity begann. Weil `serializeProject()` die Kommentare +bei JEDEM Speichern eines Projekts erneut bereinigt (auch wenn nur eine +Aufgabe geändert wurde), kam pro Speichern eine Stufe dazu (  → +  →   …). Jetzt maskiert `textMaskieren()` ein `&` nur, +wenn es keine Entity beginnt — beliebig oft wiederholbar (geprüft: alle +Kommentare nach dreimaligem Bereinigen unverändert). `entitiesReparieren()` +(beim Start und nach `/import`, idempotent) führt gestapelte Stufen in +`project_kommentare.status` und `protokoll_punkte.text` aller Sitzungen über +`entitiesEntstapeln()` zurück. + ## Behobene Fehler (Testlauf 10/2026, fünf Test-Agents) - **Gesperrte Sitzungen sind für Nicht-Admins auch inhaltlich unveränderlich**: diff --git a/public/App.html b/public/App.html index 06b0f5e..870a9e3 100644 --- a/public/App.html +++ b/public/App.html @@ -38,13 +38,13 @@ - - + + - + + - + @@ -1994,6 +1968,7 @@ + - + - + - + - - + + diff --git a/public/glas.css b/public/glas.css index e6d3e95..6674fd7 100644 --- a/public/glas.css +++ b/public/glas.css @@ -1,5 +1,8 @@ /* =========================================================================== - GLAS-DARSTELLUNG (Eriks Wahl: Gestaltungsvorschlag "Projektübersicht in + GLAS-DARSTELLUNG — beruhigt in der unslop-Überarbeitung „Bauplan“ (Eriks + Wahl „Beruhigen“): Flächen fast deckend, Lichtflächen schwach und nur noch + in den zwei Logo-Blautönen, kleinere Rundungen und neutrale Schatten. + Ursprünglich: (Eriks Wahl: Gestaltungsvorschlag "Projektübersicht in Glas", Annäherung an Apple Liquid Glass) --------------------------------------------------------------------------- Eine eigene Schicht über styles.css und plan-styles.css, geladen als LETZTES @@ -27,107 +30,105 @@ /* ---------- Tokens: hell ---------- */ html.glas { - --bg: #e8eef3; - --surface: rgba(255,255,255,.58); - --surface-alt: rgba(255,255,255,.40); - --surface-sunk: rgba(15,90,133,.07); - --line: rgba(20,45,65,.16); - --line-soft: rgba(20,45,65,.09); + --bg: #eef1f4; + --surface: rgba(255,255,255,.82); + --surface-alt: rgba(255,255,255,.66); + --surface-sunk: rgba(16,24,32,.05); + --line: rgba(16,24,32,.13); + --line-soft: rgba(16,24,32,.07); --accent: #0f5a85; --accent-hover: #0d5079; --accent-active: #0a4565; - --accent-soft: rgba(15,90,133,.11); + --accent-soft: rgba(15,90,133,.09); --band-neu: #0f5a85; - --text: #14212b; - --text-muted: #4b5d6b; - --text-subtle: #6f8291; + --text: #16191d; + --text-muted: #4d545c; + --text-subtle: #69707a; - --r-md: 10px; - --r-lg: 18px; - --r-xl: 22px; + --r-md: 8px; + --r-lg: 14px; + --r-xl: 16px; - --sh-1: 0 8px 28px rgba(21,58,86,.10), 0 1px 4px rgba(21,58,86,.06); - --sh-2: 0 12px 34px rgba(21,58,86,.13), 0 2px 6px rgba(21,58,86,.07); - --sh-3: 0 20px 60px rgba(21,58,86,.20), 0 4px 14px rgba(21,58,86,.10); + --sh-1: 0 1px 2px rgba(16,24,32,.05); + --sh-2: 0 4px 16px rgba(16,24,32,.07), 0 1px 2px rgba(16,24,32,.04); + --sh-3: 0 12px 32px rgba(16,24,32,.12), 0 2px 6px rgba(16,24,32,.06); - --glas-rahmen: rgba(255,255,255,.62); - --glas-dicht: rgba(255,255,255,.86); + --glas-rahmen: rgba(255,255,255,.84); + --glas-dicht: rgba(255,255,255,.94); --glas-deckend: #f7fafc; - --glas-kante: rgba(255,255,255,.80); - --glas-kante-2: rgba(255,255,255,.35); - --glas-blur: 24px; + --glas-kante: rgba(255,255,255,.70); + --glas-kante-2: rgba(255,255,255,.25); + --glas-blur: 16px; --glas-hell: #94b0cc; --glas-tief: #116896; - --glas-logo: .16; + --glas-logo: .07; } /* ---------- Tokens: dunkel (System und manuell) ---------- */ @media (prefers-color-scheme: dark) { html.glas:not([data-theme="light"]) { - --bg: #0b141b; - --surface: rgba(30,46,60,.50); - --surface-alt: rgba(30,46,60,.34); - --surface-sunk: rgba(255,255,255,.06); - --line: rgba(255,255,255,.14); - --line-soft: rgba(255,255,255,.08); - --accent: #8cc9e6; - --accent-hover: #a3d4ec; - --accent-active: #6fb3d3; - --accent-soft: rgba(140,201,230,.15); + --bg: #111315; + --surface: rgba(26,29,33,.80); + --surface-alt: rgba(26,29,33,.62); + --surface-sunk: rgba(255,255,255,.05); + --line: rgba(236,238,240,.13); + --line-soft: rgba(236,238,240,.07); + --accent: #86bfdf; + --accent-hover: #9dcbe5; + --accent-active: #6aa9cc; + --accent-soft: rgba(134,191,223,.13); --band-neu: #116896; - --text: #e8f0f5; - --text-muted: #a9bccb; - --text-subtle: #7790a2; - --sh-1: 0 10px 30px rgba(0,0,0,.40), 0 1px 4px rgba(0,0,0,.30); - --sh-2: 0 14px 38px rgba(0,0,0,.45), 0 2px 8px rgba(0,0,0,.30); - --sh-3: 0 22px 64px rgba(0,0,0,.55), 0 4px 16px rgba(0,0,0,.35); - --glas-rahmen: rgba(28,42,54,.58); - --glas-dicht: rgba(22,34,44,.90); - --glas-deckend: #15212b; - --glas-kante: rgba(255,255,255,.18); - --glas-kante-2: rgba(255,255,255,.07); + --text: #eceef0; + --text-muted: #a5abb2; + --text-subtle: #878d95; + --sh-1: 0 1px 2px rgba(0,0,0,.4); + --sh-2: 0 4px 16px rgba(0,0,0,.45); + --sh-3: 0 16px 40px rgba(0,0,0,.55), 0 2px 8px rgba(0,0,0,.35); + --glas-rahmen: rgba(24,27,30,.84); + --glas-dicht: rgba(22,24,27,.95); + --glas-deckend: #181a1d; + --glas-kante: rgba(255,255,255,.12); + --glas-kante-2: rgba(255,255,255,.05); --glas-hell: #2c5675; --glas-tief: #1d6f99; - --glas-logo: .10; + --glas-logo: .06; } } html.glas[data-theme="dark"] { - --bg: #0b141b; - --surface: rgba(30,46,60,.50); - --surface-alt: rgba(30,46,60,.34); - --surface-sunk: rgba(255,255,255,.06); - --line: rgba(255,255,255,.14); - --line-soft: rgba(255,255,255,.08); - --accent: #8cc9e6; - --accent-hover: #a3d4ec; - --accent-active: #6fb3d3; - --accent-soft: rgba(140,201,230,.15); + --bg: #111315; + --surface: rgba(26,29,33,.80); + --surface-alt: rgba(26,29,33,.62); + --surface-sunk: rgba(255,255,255,.05); + --line: rgba(236,238,240,.13); + --line-soft: rgba(236,238,240,.07); + --accent: #86bfdf; + --accent-hover: #9dcbe5; + --accent-active: #6aa9cc; + --accent-soft: rgba(134,191,223,.13); --band-neu: #116896; - --text: #e8f0f5; - --text-muted: #a9bccb; - --text-subtle: #7790a2; - --sh-1: 0 10px 30px rgba(0,0,0,.40), 0 1px 4px rgba(0,0,0,.30); - --sh-2: 0 14px 38px rgba(0,0,0,.45), 0 2px 8px rgba(0,0,0,.30); - --sh-3: 0 22px 64px rgba(0,0,0,.55), 0 4px 16px rgba(0,0,0,.35); - --glas-rahmen: rgba(28,42,54,.58); - --glas-dicht: rgba(22,34,44,.90); - --glas-deckend: #15212b; - --glas-kante: rgba(255,255,255,.18); - --glas-kante-2: rgba(255,255,255,.07); + --text: #eceef0; + --text-muted: #a5abb2; + --text-subtle: #878d95; + --sh-1: 0 1px 2px rgba(0,0,0,.4); + --sh-2: 0 4px 16px rgba(0,0,0,.45); + --sh-3: 0 16px 40px rgba(0,0,0,.55), 0 2px 8px rgba(0,0,0,.35); + --glas-rahmen: rgba(24,27,30,.84); + --glas-dicht: rgba(22,24,27,.95); + --glas-deckend: #181a1d; + --glas-kante: rgba(255,255,255,.12); + --glas-kante-2: rgba(255,255,255,.05); --glas-hell: #2c5675; --glas-tief: #1d6f99; - --glas-logo: .10; + --glas-logo: .06; } /* ---------- Hintergrund: Lichtflächen und Logo ---------- */ html.glas body { background: - radial-gradient(55% 50% at 8% 4%, color-mix(in srgb, var(--glas-hell) 70%, transparent), transparent 70%), - radial-gradient(45% 45% at 92% 12%, color-mix(in srgb, var(--glas-tief) 26%, transparent), transparent 70%), - radial-gradient(50% 55% at 72% 96%, color-mix(in srgb, #7fc3b6 26%, transparent), transparent 70%), - radial-gradient(40% 40% at 28% 82%, color-mix(in srgb, var(--glas-hell) 42%, transparent), transparent 70%), + radial-gradient(60% 55% at 8% 4%, color-mix(in srgb, var(--glas-hell) 26%, transparent), transparent 70%), + radial-gradient(50% 50% at 92% 12%, color-mix(in srgb, var(--glas-tief) 9%, transparent), transparent 70%), var(--bg); background-attachment: fixed; } @@ -157,6 +158,7 @@ html.glas .abw-team-kopf, html.glas .report-card, html.glas .load-card, html.glas .settings-card, +html.glas .mn-notizen, html.glas .dash-karte, html.glas .dash-band, html.glas .bericht-panel, @@ -181,8 +183,8 @@ html.glas .plan-toast, html.glas .glocke-menue, html.glas .wiz { background: var(--surface); - -webkit-backdrop-filter: blur(var(--glas-blur)) saturate(170%); - backdrop-filter: blur(var(--glas-blur)) saturate(170%); + -webkit-backdrop-filter: blur(var(--glas-blur)); + backdrop-filter: blur(var(--glas-blur)); border: 1px solid var(--glas-kante-2); box-shadow: var(--sh-1), inset 0 1px 0 var(--glas-kante), inset 0 -1px 0 var(--glas-kante-2); } @@ -191,7 +193,7 @@ html.glas .wiz { html.glas .app-topbar { background: var(--glas-rahmen); border-width: 0 0 1px 0; - box-shadow: 0 1px 0 var(--glas-kante-2), 0 6px 24px rgba(21,58,86,.06); + box-shadow: 0 1px 0 var(--glas-kante-2), 0 6px 24px rgba(16,24,32,.06); } html.glas .topbar-logo { height: 26px; } @@ -248,11 +250,11 @@ html.glas .modal-bg { margin: 12px 12px 0; border-radius: var(--r-xl); background: var(--glas-rahmen); - -webkit-backdrop-filter: blur(var(--glas-blur)) saturate(170%); - backdrop-filter: blur(var(--glas-blur)) saturate(170%); + -webkit-backdrop-filter: blur(var(--glas-blur)); + backdrop-filter: blur(var(--glas-blur)); border: 1px solid var(--glas-kante-2); box-shadow: var(--sh-2), inset 0 1px 0 var(--glas-kante); - padding: 4px 12px 10px; + padding: 4px 12px 12px; } /* Kopf und Reiter sind innerhalb der Karte keine eigenen Flächen mehr. */ html.glas .plan-kopf .plan-header, @@ -265,19 +267,25 @@ html.glas .modal-bg { } /* Inhalt bündig unter der Kopfkarte und im selben 12px-Abstand. */ html.glas .plan-page .plan-main-content { padding-left: 12px; padding-right: 12px; padding-top: 12px; } - html.glas .plan-kopf .plan-header { padding: 10px 12px 6px; } + html.glas .plan-kopf .plan-header { padding: 12px 12px 8px; } html.glas .plan-kopf .plan-nav { padding: 0; gap: 2px; } + /* Reiter wie die Einträge der Seitenleiste (html.glas .nav-item.active): + 32 px, helle Fläche mit Haarlinie, Schrift dunkel statt Akzentblau. */ html.glas .plan-kopf .plan-nav-item { border-bottom: 0; - border-radius: 999px; - padding: 8px 16px; - font-size: 13.5px; + border-radius: 8px; + height: 32px; + padding: 0 12px; + font-size: 13px; } html.glas .plan-kopf .plan-nav-item:hover { background: var(--surface-sunk); } + /* Der Kopf ist selbst eine helle Karte — eine weiße Kapsel wie in der + (grau durchscheinenden) Seitenleiste verschwände darauf. Deshalb hier + die umgekehrte Stufe: etwas dunkler als die Karte, mit Haarlinie. */ html.glas .plan-kopf .plan-nav-item.is-active { - background: var(--glas-dicht); - color: var(--accent); - box-shadow: inset 0 1px 0 var(--glas-kante), 0 2px 10px rgba(21,58,86,.10); + background: rgba(16,24,32,.07); + color: var(--text); + box-shadow: inset 0 0 0 1px rgba(16,24,32,.08); } } @media (min-width: 769px) and (prefers-color-scheme: dark) { @@ -293,13 +301,13 @@ html.glas .modal-bg { Grau, auf allen anderen Seiten den Glas-Hintergrund. */ html.glas .plan-main { background: transparent; } -html.glas .nav-item { border-radius: 999px; } +html.glas .nav-item { border-radius: 8px; } html.glas .nav-item:hover, html.glas .nav-item:visited:hover { background: var(--surface-sunk); } html.glas .nav-item.active { background: var(--glas-dicht); color: var(--text); - box-shadow: inset 0 1px 0 var(--glas-kante), 0 2px 10px rgba(21,58,86,.10); + box-shadow: 0 0 0 1px var(--line-soft); } html.glas .nav-item.active .nav-icon { color: var(--accent); } /* Die bestehenden Dunkel-Regeln für die Navigation setzen feste Werte — @@ -373,9 +381,8 @@ html.glas .gantt-row.gantt-days .gantt-label { background: var(--gantt-label-gru die (noch leere) App-Oberfläche, die nicht durchscheinen darf. */ html.glas .login-seite { background: - radial-gradient(55% 50% at 8% 4%, color-mix(in srgb, var(--glas-hell) 70%, transparent), transparent 70%), - radial-gradient(45% 45% at 92% 12%, color-mix(in srgb, var(--glas-tief) 26%, transparent), transparent 70%), - radial-gradient(50% 55% at 72% 96%, color-mix(in srgb, #7fc3b6 26%, transparent), transparent 70%), + radial-gradient(60% 55% at 8% 4%, color-mix(in srgb, var(--glas-hell) 26%, transparent), transparent 70%), + radial-gradient(50% 50% at 92% 12%, color-mix(in srgb, var(--glas-tief) 9%, transparent), transparent 70%), var(--bg); } diff --git a/public/js/admin/admin.js b/public/js/admin/admin.js index 7f4d320..12f84b5 100644 --- a/public/js/admin/admin.js +++ b/public/js/admin/admin.js @@ -76,6 +76,13 @@ function adminNavAbgleichen(){ const item = document.querySelector('#adminSubnav [data-admin-section="' + sec.key + '"]'); if(item) item.hidden = !adminAbschnittErlaubt(sec); }); + // Zwischenüberschriften (Personen/Vorgaben/System) nur, wenn darunter + // mindestens ein erlaubter Punkt steht. + document.querySelectorAll('#adminSubnav .sidebar-subgruppe').forEach(kopf => { + let el = kopf.nextElementSibling, sichtbar = false; + while(el && !el.classList.contains('sidebar-subgruppe')){ if(!el.hidden) sichtbar = true; el = el.nextElementSibling; } + kopf.hidden = !sichtbar; + }); } // adminAbschnittErlaubt: darf das Konto diesen Abschnitt sehen? diff --git a/public/js/dashboard/dashboard.js b/public/js/dashboard/dashboard.js index 4081f61..033c81f 100644 --- a/public/js/dashboard/dashboard.js +++ b/public/js/dashboard/dashboard.js @@ -55,8 +55,6 @@ const ABSENCE_TYPE_CLASS = { // renderDashboard()-Aufruf neu gestartet (vorheriges Intervall zuerst // gestoppt), damit beim wiederholten Tab-Wechsel nicht mehrere Intervalle // parallel laufen. -let dashboardClockTimer = null; - // renderDashboard: lädt GET /my-dashboard und rendert Begrüßung/Uhr, // Kennzahlen sowie die drei Bereiche in #dashboardContent. Wird nur beim // Wechsel auf den Tab aufgerufen (showTab()), nicht beim initialen @@ -66,6 +64,9 @@ async function renderDashboard(){ if(!container) return; container.innerHTML = '
Lade Dashboard…
'; + // Notizen je Projekt (Anzahl) parallel — fällt sie aus, fehlt nur die Angabe. + const notizenAnfrage = fetch(baseUrl() + '/projekt-notizen/anzahl') + .then(r => r.ok ? r.json() : null).catch(() => null); let data; try { const res = await fetch(baseUrl() + '/my-dashboard'); @@ -76,6 +77,8 @@ async function renderDashboard(){ return; } + const nz = await notizenAnfrage; + dashNotizen = (nz && nz.ok && nz.anzahl) || {}; const weekLabel = data.weekLabel || null; const tasks = Array.isArray(data.tasks) ? data.tasks : []; const projectDates = Array.isArray(data.projectDates) ? data.projectDates : []; @@ -103,12 +106,15 @@ async function renderDashboard(){ const heuteFaellig = tasks.filter(t => t.end === heute).length + projectDates.filter(d => d.heute).length; + const daten = dashDaten(); + const sonntag = formatDateISO(new Date(dashWochenMontag().getTime() + 6 * 86400000)); + const dieseWoche = daten.eintraege.filter(e => e.datum >= heute && e.datum <= sonntag).length; + let html = ''; html += renderDashboardKopf(weekLabel); html += renderDashboardBand({ - ueberfaellig, heuteFaellig, + ueberfaellig, heuteFaellig, dieseWoche, aufgaben: tasks.length, - termine: projectDates.length, freigaben: pending.length, abwesend: absencesToday, }); @@ -120,10 +126,10 @@ async function renderDashboard(){ // Neu zugewiesene Aufgaben (js/benachrichtigungen.js) — vor allem anderen, // weil es das ist, was sich seit dem letzten Blick geändert hat. html += '
'; + html += renderDashWoche(daten); html += '
'; // Linke Zone: die eigenen Projekte mit ihren Terminen - const daten = dashDaten(); html += '
'; const zuAlle = dashZuLesen(); const alleOffen = daten.projekte.some(x => !zuAlle.has(dashProjKey(x.p))); @@ -153,7 +159,6 @@ async function renderDashboard(){ if(typeof renderDashNeu === 'function'){ renderDashNeu(); ladeBenachrichtigungen(true); } dashKalDaten = daten; renderDashKalender(); - startDashboardClock(); } // ---------- Meine Projekte + Kalender (Entwurf B "Monatsblatt") ---------- @@ -164,6 +169,8 @@ async function renderDashboard(){ let dashKalDaten = null; let dashKalMonat = null; // { jahr, monat } (monat 0–11) let dashKalTag = null; // ISO-Datum +// dashNotizen: { project_uid: {anzahl, zuletzt} } aus GET /projekt-notizen/anzahl. +let dashNotizen = {}; // dashDaten: sammelt aus der aktuellen Sitzung (currentWeek()) die Projekte // des angemeldeten Kontos und alle Kalendereinträge. Ein Projekt gehört dazu, @@ -440,9 +447,8 @@ function renderDashProjekte(daten){ const key = dashProjKey(p); const istZu = zu.has(key); const rollen = x.rollen.length - ? x.rollen.map(r => '' + esc(r.rolle) + '').join('') - : 'nur Aufgabe'; + ? x.rollen.map(r => esc(r.rolle) + (r.state === 2 ? ', Unterstützung' : '')).join(' / ') + : 'nur eigene Aufgabe'; const aktLp = (typeof lpActiveList === 'function' ? lpActiveList(p) : [])[0]; const pct = aktLp && p.lph && p.lph[aktLp] !== undefined && p.lph[aktLp] !== '' ? Math.max(0, Math.min(100, Number(p.lph[aktLp]) || 0)) : null; const phase = aktLp @@ -463,7 +469,7 @@ function renderDashProjekte(daten){ // Eingeklappt bleibt sichtbar, was Aufmerksamkeit braucht: wie viele // Termine überfällig bzw. offen sind. const kurz = (ueber.length ? '' + ueber.length + ' überfällig' : '') - + '' + kommend.length + ' offen'; + + '' + kommend.length + ' offen'; return '
' + '
' + (daten.projekte.length > 1 ? '' + icon('grip') + '' : '') @@ -472,10 +478,10 @@ function renderDashProjekte(daten){ + '' + esc(p.nr || '') + '' + esc(p.name || '') + '' + '' + '' + kurz + '' - + '' + rollen + '' + 'Öffnen' + '
' + '
' + + renderDashProjektInfo(x, rollen) + '
' + phase + '
' + '
' + zeilen + mehr + '
' + '
' @@ -483,6 +489,103 @@ function renderDashProjekte(daten){ }).join('') + '
'; } +// renderDashWoche: Band „Diese Woche“ (Entwurf „Bauplan“): Mo bis Fr als +// Spalten mit den Terminen der eigenen Projekte an diesem Tag — eigene +// Aufgaben, Aufgaben im Projekt, Meilensteine, Überfälliges. Je Tag höchstens +// DASH_WOCHE_JE_TAG, der Rest als „+ N weitere“. Parameter: daten (dashDaten()). +const DASH_WOCHE_JE_TAG = 4; +function renderDashWoche(daten){ + if(!daten.geladen || !daten.projekte.length) return ''; + const heute = heuteIso(); + const mo = dashWochenMontag(); + const TAGE = ['Mo', 'Di', 'Mi', 'Do', 'Fr']; + let spalten = ''; + for(let i = 0; i < 5; i++){ + const d = new Date(mo); d.setDate(mo.getDate() + i); + const iso = formatDateISO(d); + const e = daten.eintraege.filter(x => x.datum === iso) + .sort((a, b) => (b.meins ? 1 : 0) - (a.meins ? 1 : 0)); + const sicht = e.slice(0, DASH_WOCHE_JE_TAG); + const rest = e.length - sicht.length; + spalten += '
' + + '
' + TAGE[i] + '' + d.getDate() + '.' + (d.getMonth() + 1) + '.
' + + '
' + + (sicht.map(x => { + const art = x.art === 'meilenstein' ? 'ist-ms' : (x.datum < heute ? 'ist-ueber' : (x.meins ? 'ist-meins' : 'ist-fremd')); + return '' + + '' + esc(x.titel) + '' + + '' + esc([x.projekt.nr, x.projekt.name].filter(Boolean).join(' ')) + ''; + }).join('') || 'keine Termine') + + (rest > 0 ? '+ ' + rest + ' weitere' : '') + + '
'; + } + const legende = '
' + + 'meine AufgabeAufgabe im Projekt' + + 'Meilensteinüberfällig
'; + return dashAbschnitt('Diese Woche', null, 'eigene Aufgaben und Termine meiner Projekte', + '
' + spalten + '
' + legende + '
'); +} + +// renderDashProjektInfo: Zeile „Meine Rolle | Team | Notizen“ im Projektblock +// (Eriks Wunsch): die eigene Rolle, die übrigen Beteiligten als Kürzel-Kreise +// in den Rollenfarben (wie Projektliste, beteiligtenAvatarHtml()) und — nur +// wenn vorhanden — die Zahl der Notizen mit Sprung in den Reiter „Notizen“. +// Parameter: x (Eintrag aus dashDaten()), rollenText. Rückgabe: HTML-String. +const DASH_TEAM_MAX = 5; +function renderDashProjektInfo(x, rollenText){ + const p = x.p; + const w = currentWeek(); + const ich = currentUser && currentUser.personId; + const personen = {}; + ((w && w.people) || []).forEach(q => { personen[q.id] = q; }); + const eintraege = []; + Object.keys(p.assign || {}).forEach(key => { + const [pid, role] = key.split('|'); + const state = Number(p.assign[key]) || 0; + if(state > 0) eintraege.push({ person: personen[pid] || { id: pid, name: pid, fullName: pid }, role, state }); + }); + const alle = beteiligteJePerson(eintraege); + const ichB = alle.find(b => b.person.id === ich); + const team = alle.filter(b => b.person.id !== ich); + const kreis = b => beteiligtenAvatarHtml(b, typeof roleClass === 'function' ? roleClass(b.role) : ''); + const kurzName = b => { + const teile = String(b.person.fullName || b.person.name || '').trim().split(/\s+/); + return teile.length > 1 ? teile[0] + ' ' + teile[teile.length - 1][0] + '.' : teile[0]; + }; + const namen = team.length > 2 + ? team.slice(0, 2).map(kurzName).join(', ') + ' +' + (team.length - 2) + : team.map(kurzName).join(', '); + + let html = '
' + + '
Meine Rolle' + + '' + (ichB ? kreis(ichB) : '') + '' + rollenText + '
' + + '
Team' + + '' + + (team.length + ? '' + team.slice(0, DASH_TEAM_MAX).map(kreis).join('') + '' + esc(namen) + '' + : 'niemand weiter') + + '
'; + const n = dashNotizen[p.projectUid]; + if(n && n.anzahl > 0){ + html += '' + + 'Notizen' + + '' + icon('fileText') + '' + n.anzahl + ' ' + (n.anzahl === 1 ? 'Notiz' : 'Notizen') + '' + + (n.zuletzt ? '' + esc(dashZuletzt(n.zuletzt)) + '' : '') + ''; + } + return html + '
'; +} + +// dashZuletzt: „zuletzt heute/gestern“ oder „vom 28.10.“ zu einem Zeitstempel. +function dashZuletzt(zeit){ + const d = new Date(zeit); + if(isNaN(d)) return ''; + const tage = -tageBis(formatDateISO(d)); + if(tage <= 0) return 'zuletzt heute'; + if(tage === 1) return 'zuletzt gestern'; + return 'vom ' + d.getDate() + '.' + (d.getMonth() + 1) + '.'; +} + // renderDashTermin: eine Terminzeile im Projektblock und in der Tagesliste // des Kalenders. Eigene Aufgaben tragen das Zeichen "A" in Akzentfarbe, // fremde Aufgaben dazu die Zuständigen, Meilensteine eine Raute. @@ -593,22 +696,30 @@ function dashKalBlaettern(n){ renderDashKalender(); } -// renderDashboardKopf: Begrüßung und Datum links, Sitzung und Uhr klein -// rechts. Die Uhrzeit war zuvor die größte Zahl auf dem Bildschirm — sie ist -// die Angabe, nach der man am wenigsten handelt, und steht deshalb am Rand. -// Die Inhalte füllt startDashboardClock() live nach. -// Parameter: weekLabel. Rückgabe: HTML-String. +// renderDashboardKopf: Titel und Kalenderwoche statt Begrüßung (Entwurf +// „Bauplan“, Eriks Wahl): „KW 45, Mo 2. bis Fr 6. November 2026“, rechts die +// Sitzung. Parameter: weekLabel. Rückgabe: HTML-String. function renderDashboardKopf(weekLabel){ + const MONATE = ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember']; + const mo = dashWochenMontag(); + const fr = new Date(mo); fr.setDate(mo.getDate() + 4); + const zeile = 'KW ' + getWeekNumber(mo) + ', Mo ' + mo.getDate() + '.' + + (mo.getMonth() !== fr.getMonth() ? ' ' + MONATE[mo.getMonth()] : '') + + ' bis Fr ' + fr.getDate() + '. ' + MONATE[fr.getMonth()] + ' ' + fr.getFullYear(); return '
' - + '

' - + '

' - + '
' - + (weekLabel ? '' + esc(weekLabel) + '' : '') - + '' - + '
' + + '' + + (weekLabel ? '
Sitzung' + esc(weekLabel) + '
' : '') + '
'; } +// dashWochenMontag: Montag der laufenden Woche (lokale Zeit, 0 Uhr). +function dashWochenMontag(){ + const d = parseDateISO(heuteIso()); + d.setDate(d.getDate() - ((d.getDay() + 6) % 7)); + return d; +} + // renderDashboardBand: der Befund des Tages als Satz, daneben die Kennzahlen. // // Zuvor standen hier vier gleich große Kacheln, von denen meist drei eine @@ -634,17 +745,17 @@ function renderDashboardBand(z){ satz = 'Nichts offen, nichts überfällig.'; } - const zahl = (wert, label) => - '
' + wert + '' + label + '
'; + const zahl = (wert, label, rot) => + '
' + label + '' + wert + '
'; const ruhig = z.ueberfaellig === 0 && z.heuteFaellig === 0; return '
' + '

' + satz + '

' + '
' + zahl(z.aufgaben, 'offene Aufgaben') - + zahl(z.termine, 'Termine im Blick') + + zahl(z.ueberfaellig, 'überfällig', z.ueberfaellig > 0) + + zahl(z.dieseWoche, 'diese Woche fällig') + zahl(z.freigaben, 'Freigaben') - + zahl(z.abwesend, 'heute abwesend') + '
'; } @@ -666,43 +777,6 @@ function dashLeer(text){ return '
' + esc(text) + '
'; } -// greetingForHour:// greetingForHour: liefert je Tageszeit eine passende Begrüßung. Parameter: -// hour (Number, 0-23). Rückgabe: String. -function greetingForHour(hour){ - if(hour < 5) return 'Gute Nacht'; - if(hour < 11) return 'Guten Morgen'; - if(hour < 18) return 'Guten Tag'; - if(hour < 22) return 'Guten Abend'; - return 'Gute Nacht'; -} - -// startDashboardClock: (re-)startet das Intervall, das Begrüßung, Datum und -// Uhrzeit im Dashboard-Header aktualisiert. Bricht sich selbst ab, sobald die -// Zielelemente nicht mehr im DOM sind (z. B. weil das Dashboard neu gerendert -// wurde). Keine Parameter, keine Rückgabe. -function startDashboardClock(){ - if(dashboardClockTimer) clearInterval(dashboardClockTimer); - const name = (currentUser && (currentUser.displayName || currentUser.username)) || ''; - const tick = () => { - const textEl = document.getElementById('dashboardGreetingText'); - const dateEl = document.getElementById('dashboardGreetingDate'); - const clockEl = document.getElementById('dashboardClock'); - if(!textEl || !dateEl || !clockEl){ - clearInterval(dashboardClockTimer); - dashboardClockTimer = null; - return; - } - const now = new Date(); - // Begrüßung und Datum stehen in EINER Zeile (früher untereinander), das - // Datum als gedämpfter Zusatz — deshalb der führende Gedankenstrich. - textEl.textContent = greetingForHour(now.getHours()) + (name ? ', ' + name : ''); - dateEl.textContent = ' — ' + now.toLocaleDateString('de-DE', { weekday: 'long', day: '2-digit', month: 'long', year: 'numeric' }); - clockEl.textContent = now.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' }); - }; - tick(); - dashboardClockTimer = setInterval(tick, 30000); -} - // relativerTag: "heute", "morgen", "in 5 Tagen", "seit 3 Tagen" zu einem // ISO-Datum. Die Angabe steht neben dem Datum, weil "12.08." allein nicht // sagt, ob das morgen oder in drei Wochen ist. diff --git a/public/js/einfuehrung.js b/public/js/einfuehrung.js index 5af060b..4ef552a 100644 --- a/public/js/einfuehrung.js +++ b/public/js/einfuehrung.js @@ -44,7 +44,7 @@ const EINFUEHRUNG_SCHRITTE = [ text: () => 'Dein Konto: Passwort, E-Mail-Adresse, deine KI-Schlüssel und die Darstellung. Hier kannst du diesen Rundgang jederzeit neu starten.' }, { id: 'admin', wenn: () => typeof hatAdminRecht === 'function' && hatAdminRecht(), ziel: '#adminAccordionToggle', titel: 'Admin', text: () => 'Du darfst Teile der Verwaltung pflegen: ' + esc(typeof ADMIN_SECTIONS !== 'undefined' ? ADMIN_SECTIONS.filter(adminAbschnittErlaubt).map(s => s.title).join(', ') : '') + '.' }, - { id: 'ende', tab: 'dashboard', titel: 'Fertig!', + { id: 'ende', tab: 'dashboard', titel: 'Rundgang abgeschlossen', text: () => { const hinweise = []; if(currentUser && !currentUser.personId){ diff --git a/public/js/globals.js b/public/js/globals.js index 84f8515..4d31e89 100644 --- a/public/js/globals.js +++ b/public/js/globals.js @@ -147,6 +147,7 @@ const TAB_SLUGS = { wochenbericht: 'Wochenbericht', load: 'Auslastung', abwesenheit: 'Abwesenheiten', + notizen: 'Notizen', people: 'Projektbeteiligte', planung: 'Planung', planchecker: 'PlanChecker', diff --git a/public/js/notizen/notizen.js b/public/js/notizen/notizen.js new file mode 100644 index 0000000..da2cac2 --- /dev/null +++ b/public/js/notizen/notizen.js @@ -0,0 +1,408 @@ +// ----------------------------- +// Seitenleiste „Notizen“ (Tab `notizen`, /Notizen) +// ----------------------------- +// Eriks Wunsch: Jedes Konto sieht hier die Notizen ALLER seiner Projekte und +// legt auch projektunabhängige Notizen an, die sich beim Bearbeiten einem +// Projekt zuordnen lassen. Gleicher Aufbau wie der Reiter „Notizen“ im +// Projektbereich (js/plan/plan-notizen.js: Liste + Editor, Werkzeugleiste, +// automatisches Speichern), dazu ein Projektfilter und im Editor die Auswahl +// „Projekt“. Eigene Element-ids (mn…), weil der Projekt-Reiter gleichzeitig +// im DOM liegt. +// +// Daten: GET /meine-notizen (Notizen meiner Projekte + meine +// projektunabhängigen, project_uid = ''), sonst dieselben Routen +// /projekt-notizen* wie der Projekt-Reiter; PUT nimmt `uid` zum Zuordnen. +// Projektunabhängige Notizen sieht und ändert nur, wer sie angelegt hat. +(function(){ + const SPEICHER_PAUSE_MS = 1200; + const OHNE = '__ohne__'; + + let liste = []; + let meineProjekte = new Set(); + let geladen = false; + let ladeFehler = ''; + let filter = ''; // '' = alle, OHNE = ohne Projekt, sonst uid + let suche = ''; + let aktivId = null; + let basis = ''; + let ungespeichert = false; + let speicherTimer = null; + let speichertGerade = false; + let beobachter = null; + let loeschenFragt = null; + let eigenesSchreiben = 0; // Zeitpunkt der letzten eigenen Änderung (Live-Echo auslassen) + + const el = () => document.getElementById('notizen'); + const aktiv = () => liste.find(n => n.id === aktivId) || null; + const darf = n => !n || !n.uid ? true : (typeof hatRecht === 'function' && hatRecht('proj.plan')); + const darfProjekte = () => typeof hatRecht === 'function' && hatRecht('proj.plan'); + + // Projekte der aktuellen Sitzung je projectUid (Name und Nummer). + function projekte(){ + const w = typeof currentWeek === 'function' ? currentWeek() : null; + const m = new Map(); + ((w && w.projects) || []).forEach(p => { if(p.projectUid) m.set(String(p.projectUid), p); }); + return m; + } + function projektName(uid, karte){ + if(!uid) return 'Ohne Projekt'; + const p = (karte || projekte()).get(uid); + return p ? [p.nr, p.name].filter(Boolean).join(' ') : 'Projekt nicht in der aktuellen Sitzung'; + } + function zeit(iso){ + if(!iso) return ''; + const d = new Date(iso); + if(isNaN(d)) return ''; + const heute = new Date(); + const gestern = new Date(heute); gestern.setDate(heute.getDate() - 1); + const uhr = d.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' }); + if(d.toDateString() === heute.toDateString()) return 'heute ' + uhr; + if(d.toDateString() === gestern.toDateString()) return 'gestern ' + uhr; + return d.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: d.getFullYear() === heute.getFullYear() ? undefined : 'numeric' }); + } + const klartext = html => typeof statusPlainText === 'function' ? statusPlainText(html) : String(html || '').replace(/<[^>]+>/g, ' '); + function sortieren(){ + liste.sort((a, b) => (b.angeheftet - a.angeheftet) || String(b.geaendertAm).localeCompare(String(a.geaendertAm))); + } + + // ---------- Laden ---------- + function laden(){ + ladeFehler = ''; + return fetch(baseUrl() + '/meine-notizen') + .then(r => r.json().then(d => ({ ok: r.ok, d }))) + .then(({ ok, d }) => { + if(!ok || !d.ok) throw new Error(d.error || 'Laden fehlgeschlagen'); + liste = d.notizen || []; + meineProjekte = new Set(d.meineProjekte || []); + sortieren(); + geladen = true; + }) + .catch(e => { ladeFehler = e.message || 'Die Notizen konnten nicht geladen werden.'; liste = []; geladen = true; }); + } + + // ---------- Darstellung ---------- + window.renderMeineNotizen = function(){ + const box = el(); + if(!box) return; + box.innerHTML = '
Notizen werden geladen…
'; + jetztSpeichern(); + laden().then(aufbauen); + }; + + function sichtbar(){ + const s = suche.trim().toLowerCase(); + return liste.filter(n => (!filter || (filter === OHNE ? !n.uid : n.uid === filter)) + && (!s || (n.titel + ' ' + klartext(n.html) + ' ' + projektName(n.uid)).toLowerCase().includes(s))); + } + + function filterOptionen(){ + const karte = projekte(); + const mitNotizen = new Set(liste.filter(n => n.uid).map(n => n.uid)); + const uids = Array.from(new Set([...meineProjekte, ...mitNotizen])) + .sort((a, b) => projektName(a, karte).localeCompare(projektName(b, karte), 'de')); + const zahl = f => liste.filter(n => f === OHNE ? !n.uid : n.uid === f).length; + return '' + + '' + + uids.map(u => '').join(''); + } + + function aufbauen(){ + const box = el(); + if(!box) return; + const treffer = sichtbar(); + if(!treffer.some(n => n.id === aktivId)) aktivId = treffer.length ? treffer[0].id : null; + box.innerHTML = ` +
+
+ + +
+
+ +
+
+
`; + listeZeichnen(); + editorZeichnen(); + } + + function listeZeichnen(){ + const box = document.getElementById('mnEintraege'); + if(!box) return; + if(ladeFehler){ box.innerHTML = '
' + esc(ladeFehler) + '
'; return; } + const treffer = sichtbar(); + if(!liste.length){ box.innerHTML = '
Noch keine Notizen. Mit „+ Neu“ eine eigene anlegen.
'; return; } + if(!treffer.length){ box.innerHTML = '
' + (suche ? 'Keine Notiz enthält „' + esc(suche) + '“.' : 'Keine Notizen in dieser Auswahl.') + '
'; return; } + const karte = projekte(); + const zeile = n => { + const vorschau = klartext(n.html).replace(/\s+/g, ' ').trim().slice(0, 90); + return ``; + }; + const oben = treffer.filter(n => n.angeheftet), rest = treffer.filter(n => !n.angeheftet); + box.innerHTML = (oben.length ? '
Angeheftet
' + oben.map(zeile).join('') : '') + + (rest.length ? (oben.length ? '
Weitere
' : '') + rest.map(zeile).join('') : ''); + } + + // projektAuswahl: Auswahl im Editor — „Ohne Projekt“, meine Projekte, dann + // die übrigen der Sitzung. Ohne Recht proj.plan nur „Ohne Projekt“ (und das + // aktuelle Projekt, damit der Stand lesbar bleibt). + function projektAuswahl(n){ + const karte = projekte(); + const name = u => projektName(u, karte); + const sort = arr => arr.sort((a, b) => name(a).localeCompare(name(b), 'de')); + const opt = u => ''; + const meine = sort(Array.from(meineProjekte).filter(u => karte.has(u))); + const weitere = sort(Array.from(karte.keys()).filter(u => !meineProjekte.has(u))); + const sperren = !darf(n) || (!darfProjekte() && !n.uid); + let html = ''; + if(darfProjekte()){ + if(meine.length) html += '' + meine.map(opt).join('') + ''; + if(weitere.length) html += '' + weitere.map(opt).join('') + ''; + } + if(n.uid && !karte.has(n.uid)) html += opt(n.uid); + return ''; + } + + function editorZeichnen(){ + const box = document.getElementById('mnEditor'); + if(!box) return; + if(beobachter){ beobachter.disconnect(); beobachter = null; } + const n = aktiv(); + if(!n){ + box.innerHTML = `
+ ${liste.length ? 'Notiz links auswählen' : 'Noch keine Notizen'} + Mit „+ Neu“ eine Notiz anlegen. Sie gehört zunächst nur Ihnen und lässt sich oben rechts einem Projekt zuordnen. +
`; + return; + } + const schreiben = darf(n); + basis = n.geaendertAm; + ungespeichert = false; + const projekt = n.uid ? projekte().get(n.uid) : null; + box.innerHTML = ` +
+ + ${schreiben ? ` + ` : ''} +
+
+ ${projektAuswahl(n)} + ${projekt ? `Im Projekt öffnen` : ''} + ${!n.uid ? 'Nur für Sie sichtbar, bis sie einem Projekt zugeordnet ist' : ''} +
+
+ ${schreiben ? richtextToolbarHtml('#mnText') : ''} + ${richtextFeldHtml('notizen-text', sanitizeStatusHtml(n.html || ''), 'Notiz schreiben…', 'id="mnText" onblur="mnJetztSpeichern()"', schreiben)} +
+
+ Angelegt von ${esc(n.erstelltVon)} ${esc(zeit(n.erstelltAm))}${n.geaendertAm !== n.erstelltAm ? ' · zuletzt geändert von ' + esc(n.geaendertVon) + ' ' + esc(zeit(n.geaendertAm)) : ''} + +
`; + const text = document.getElementById('mnText'); + if(text && schreiben){ + beobachter = new MutationObserver(() => mnGeaendert()); + beobachter.observe(text, { childList: true, subtree: true, characterData: true, attributes: true }); + } + } + + function status(text, art){ + const s = document.getElementById('mnStatus'); + if(!s) return; + s.className = 'notizen-status' + (art ? ' ist-' + art : ''); + s.innerHTML = text; + } + function hinweis(text){ if(typeof zeigeHinweis === 'function') zeigeHinweis(text); else status(esc(text), 'fehler'); } + + // ---------- Bedienung ---------- + window.mnFilter = function(wert){ jetztSpeichern(); filter = wert || ''; aufbauen(); }; + window.mnSuchen = function(wert){ suche = wert || ''; listeZeichnen(); }; + window.mnWaehlen = function(id){ + if(id === aktivId) return; + jetztSpeichern(); + aktivId = id; + listeZeichnen(); + editorZeichnen(); + }; + window.mnGeaendert = function(){ + const n = aktiv(); + if(!n || !darf(n)) return; + ungespeichert = true; + status('Ungespeichert'); + clearTimeout(speicherTimer); + speicherTimer = setTimeout(jetztSpeichern, SPEICHER_PAUSE_MS); + }; + window.mnJetztSpeichern = function(){ jetztSpeichern(); }; + + function senden(n, nutzlast){ + eigenesSchreiben = Date.now(); + return fetch(baseUrl() + '/projekt-notizen/' + encodeURIComponent(n.id), { + method: 'PUT', headers: { 'Content-Type': 'application/json; charset=utf-8' }, body: JSON.stringify(nutzlast) + }).then(r => r.json().then(d => ({ r, d }))); + } + + function jetztSpeichern(ohneBasis){ + clearTimeout(speicherTimer); + const n = aktiv(); + if(!n || !ungespeichert || !darf(n)) return Promise.resolve(); + if(speichertGerade){ speicherTimer = setTimeout(jetztSpeichern, 400); return Promise.resolve(); } + const titelEl = document.getElementById('mnTitel'); + const textEl = document.getElementById('mnText'); + const titel = titelEl ? titelEl.value : n.titel; + const html = textEl ? textEl.innerHTML : n.html; + ungespeichert = false; + speichertGerade = true; + status('Speichert…'); + return senden(n, { titel, html, basis: ohneBasis ? '' : basis }).then(({ r, d }) => { + if(r.status === 409 && d.konflikt){ + ungespeichert = true; + status(esc(d.error) + ' ' + + ' ', 'warnung'); + n._fremd = d.notiz; + return; + } + if(!r.ok || !d.ok) throw new Error(d.error || 'Speichern fehlgeschlagen'); + Object.assign(n, d.notiz, { titel, html }); + if(n.id === aktivId) basis = d.notiz.geaendertAm; + sortieren(); + listeZeichnen(); + if(!ungespeichert) status('Gespeichert ✓', 'ok'); + }).catch(e => { + ungespeichert = true; + status('Nicht gespeichert: ' + esc(e.message) + ' — wird erneut versucht.', 'fehler'); + speicherTimer = setTimeout(jetztSpeichern, 5000); + }).finally(() => { speichertGerade = false; }); + } + + window.mnKonflikt = function(meine){ + const n = aktiv(); + if(!n) return; + if(meine){ ungespeichert = true; jetztSpeichern(true); return; } + if(n._fremd) Object.assign(n, n._fremd); + delete n._fremd; + ungespeichert = false; + listeZeichnen(); + editorZeichnen(); + }; + + // mnNeu: neue Notiz — im gefilterten Projekt, sonst ohne Projekt. + window.mnNeu = function(){ + jetztSpeichern(); + const uid = filter && filter !== OHNE && darfProjekte() ? filter : ''; + eigenesSchreiben = Date.now(); + fetch(baseUrl() + '/projekt-notizen', { + method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8' }, + body: JSON.stringify({ uid, titel: '', html: '' }) + }).then(r => r.json()).then(d => { + if(!d.ok) throw new Error(d.error || 'Anlegen fehlgeschlagen'); + liste = liste.filter(x => x.id !== d.notiz.id).concat([d.notiz]); + sortieren(); + aktivId = d.notiz.id; + suche = ''; + aufbauen(); + const t = document.getElementById('mnTitel'); + if(t) t.focus(); + }).catch(e => hinweis('Notiz konnte nicht angelegt werden: ' + e.message)); + }; + + // mnZuordnen: Notiz einem Projekt zuordnen (oder wieder lösen). Offene + // Änderungen werden vorher gespeichert. + window.mnZuordnen = function(uid){ + const n = aktiv(); + if(!n) return; + jetztSpeichern().then(() => senden(n, { uid: uid || '' })).then(({ r, d }) => { + if(!r.ok || !d.ok) throw new Error(d.error || 'Zuordnen fehlgeschlagen'); + Object.assign(n, d.notiz); + if(n.uid) meineProjekte.add(n.uid); + if(filter && filter !== (n.uid || OHNE)) filter = n.uid || OHNE; + aufbauen(); + status(n.uid ? 'Dem Projekt zugeordnet ✓' : 'Vom Projekt gelöst ✓', 'ok'); + }).catch(e => { hinweis(e.message); editorZeichnen(); }); + }; + + window.mnAnheften = function(){ + const n = aktiv(); + if(!n) return; + jetztSpeichern().then(() => senden(n, { angeheftet: !n.angeheftet })).then(({ d }) => { + if(!d.ok) throw new Error(d.error || 'Fehler'); + n.angeheftet = d.notiz.angeheftet; + sortieren(); + listeZeichnen(); + editorZeichnen(); + }).catch(e => hinweis('Anheften fehlgeschlagen: ' + e.message)); + }; + + window.mnLoeschen = function(){ + const n = aktiv(); + const knopf = document.getElementById('mnLoeschen'); + if(!n || !knopf) return; + if(!loeschenFragt){ + knopf.textContent = 'Wirklich löschen?'; + knopf.classList.add('ist-fragend'); + loeschenFragt = setTimeout(() => { + loeschenFragt = null; + const k = document.getElementById('mnLoeschen'); + if(k){ k.textContent = 'Löschen'; k.classList.remove('ist-fragend'); } + }, 4000); + return; + } + clearTimeout(loeschenFragt); loeschenFragt = null; + clearTimeout(speicherTimer); ungespeichert = false; + eigenesSchreiben = Date.now(); + fetch(baseUrl() + '/projekt-notizen/' + encodeURIComponent(n.id), { method: 'DELETE' }) + .then(r => r.json().then(d => ({ r, d }))).then(({ r, d }) => { + if(!r.ok || !d.ok) throw new Error(d.error || 'Löschen fehlgeschlagen'); + liste = liste.filter(x => x.id !== n.id); + aktivId = null; + aufbauen(); + }).catch(e => { status(esc(e.message), 'fehler'); const k = document.getElementById('mnLoeschen'); if(k){ k.textContent = 'Löschen'; k.classList.remove('ist-fragend'); } }); + }; + + window.mnProjektOeffnen = function(pid){ + jetztSpeichern(); + location.hash = 'notizen'; + if(typeof openProjectPlan === 'function') openProjectPlan(pid); + return false; + }; + + // ---------- Live: Änderungen aus anderen Browsern ---------- + window.meineNotizenLive = function(uid){ + if(typeof currentTab === 'undefined' || currentTab !== 'notizen' || !geladen) return; + if(uid && !meineProjekte.has(uid)) return; + const vorher = aktiv(); + const tippt = document.activeElement && document.activeElement.closest && document.activeElement.closest('#mnEditor'); + // Das Echo der eigenen Speicherung (kommt auch in diesem Tab an) auslassen. + if(ungespeichert || tippt || Date.now() - eigenesSchreiben < 3000) return; + laden().then(() => { + if(vorher && liste.some(x => x.id === vorher.id)) aktivId = vorher.id; + aufbauen(); + }); + }; + + // Klick irgendwo anders: die Rückfrage „Wirklich löschen?“ zurücknehmen. + document.addEventListener('pointerdown', e => { + if(!loeschenFragt || (e.target.closest && e.target.closest('#mnLoeschen'))) return; + clearTimeout(loeschenFragt); loeschenFragt = null; + const k = document.getElementById('mnLoeschen'); + if(k){ k.textContent = 'Löschen'; k.classList.remove('ist-fragend'); } + }, true); + window.addEventListener('pagehide', () => { if(ungespeichert) jetztSpeichern(); }); +})(); diff --git a/public/js/plan/plan-gantt.js b/public/js/plan/plan-gantt.js index 7255ef5..71d9ffd 100644 --- a/public/js/plan/plan-gantt.js +++ b/public/js/plan/plan-gantt.js @@ -540,7 +540,7 @@ const ampel = loadAmpelColor(l.quote); const breite = Math.min(100, l.quote * 100); const absCount = app.countPersonAbsences(l.person.id); - const absBadge = absCount > 0 ? `
${absCount} Abwesenheit(en)
` : ''; + const absBadge = absCount > 0 ? `
${absCount} Abwesenheit(en)
` : ''; let todoListHtml; if(l.todos.length === 0){ @@ -566,12 +566,12 @@ : `
keine Aufgaben mit Aufwand
`; html += `
-

${esc(l.person.name)} (${esc(l.roles.join(' / '))})

+

${esc(l.person.name)} (${esc(l.roles.join(' / '))})

${stundenFormat(l.stunden)}h diese Woche
${offenText} ${otherBadge} -
${todoListHtml}
+
${todoListHtml}
${absBadge}
`; }); diff --git a/public/js/plan/plan-notizen.js b/public/js/plan/plan-notizen.js index 40f83d8..c948a34 100644 --- a/public/js/plan/plan-notizen.js +++ b/public/js/plan/plan-notizen.js @@ -406,5 +406,12 @@ ausDaten(e.clipboardData); }); // Beim Verlassen der Seite noch speichern, was offen ist. + // Klick irgendwo anders: die Rückfrage „Wirklich löschen?“ zurücknehmen. + document.addEventListener('pointerdown', e => { + if(!loeschenFragt || (e.target.closest && e.target.closest('#notizLoeschen'))) return; + clearTimeout(loeschenFragt); loeschenFragt = null; + const k = document.getElementById('notizLoeschen'); + if(k){ k.textContent = 'Löschen'; k.classList.remove('ist-fragend'); } + }, true); window.addEventListener('pagehide', () => { if(ungespeichert) jetztSpeichern(); }); })(); diff --git a/public/js/plan/plan-protokoll-todos.js b/public/js/plan/plan-protokoll-todos.js index 4f0a46a..d6a9b21 100644 --- a/public/js/plan/plan-protokoll-todos.js +++ b/public/js/plan/plan-protokoll-todos.js @@ -100,7 +100,7 @@ // ein Fallback ist ein akzeptiertes Ergebnis, kein Fehlschlag. function zeigeFallbackHinweis(msg){ const el = document.getElementById('protokollTodosFallback'); - if(el){ el.textContent = '⚠️ ' + msg; el.hidden = false; } + if(el){ el.textContent = msg; el.hidden = false; } } function verbergeFallbackHinweis(){ const el = document.getElementById('protokollTodosFallback'); diff --git a/public/js/plan/plan-protokoll.js b/public/js/plan/plan-protokoll.js index cbe06d9..c6426dc 100644 --- a/public/js/plan/plan-protokoll.js +++ b/public/js/plan/plan-protokoll.js @@ -548,7 +548,7 @@ // ab, verschwindet also nie von selbst, sondern nur wenn man das // Protokoll erneut öffnet — bewusst so, die Herkunft bleibt sichtbar. const importBanner = p.quelleDateiname - ? `
🔎 Punkte automatisch aus „${esc(p.quelleDateiname)}“ erkannt — bitte vor dem Speichern prüfen und bei Bedarf korrigieren.
` + ? `
Punkte automatisch aus „${esc(p.quelleDateiname)}“ erkannt — bitte vor dem Speichern prüfen und bei Bedarf korrigieren.
` : ''; // Rein clientseitiges Merkmal (siehe importiereProtokoll() oben) — nur // direkt nach GENAU dem Import gesetzt, der die KI angefordert, aber @@ -559,7 +559,7 @@ // das war Eriks Rückmeldung, nachdem er von einem KI-Fehlschlag nichts // in der Oberfläche sah. const kiFallbackBanner = p._kiFallbackHinweis - ? `
⚠️ Die KI-Erkennung ist fehlgeschlagen (${esc(p._kiFallbackHinweis)}) — die Punkte wurden stattdessen per Textmuster erkannt.
` + ? `
Die KI-Erkennung ist fehlgeschlagen (${esc(p._kiFallbackHinweis)}) — die Punkte wurden stattdessen per Textmuster erkannt.
` : ''; const kopf = ` ${kiFallbackBanner} diff --git a/public/js/plan/plan-schedule.js b/public/js/plan/plan-schedule.js index 3d73fac..8403f50 100644 --- a/public/js/plan/plan-schedule.js +++ b/public/js/plan/plan-schedule.js @@ -128,7 +128,7 @@ if(moved.size > 0){ app.savePlan(); renderPlanGantt(); - app.showToast(moved.size + ' Element(e) automatisch verschoben.' + (hasCycle ? ' Achtung: zyklische Abhängigkeit gefunden!' : '')); + app.showToast(moved.size + ' Element(e) automatisch verschoben.' + (hasCycle ? ' Zyklische Abhängigkeit gefunden — bitte Vorgänger prüfen.' : '')); } else if(hasCycle){ app.showToast('Achtung: zyklische Abhängigkeit gefunden – bitte Vorgänger prüfen.'); } else { diff --git a/public/js/store.js b/public/js/store.js index 37dad83..ed4253d 100644 --- a/public/js/store.js +++ b/public/js/store.js @@ -541,7 +541,11 @@ function liveEreignis(d){ if(d.typ === 'woche') return liveWocheNachladen(d.label, d.geloescht); if(d.typ === 'neu') return liveAllesNeu(); if(d.typ === 'personen') return personenNachladen(); - if(d.typ === 'notizen' && typeof notizenLiveAenderung === 'function') return notizenLiveAenderung(d.uid); + if(d.typ === 'notizen'){ + if(typeof meineNotizenLive === 'function') meineNotizenLive(d.uid); + if(typeof notizenLiveAenderung === 'function') notizenLiveAenderung(d.uid); + return; + } } // personenNachladen: Personenliste samt Abwesenheiten neu holen (nach einer diff --git a/public/js/tabs-auth.js b/public/js/tabs-auth.js index 5552ed9..0ce315f 100644 --- a/public/js/tabs-auth.js +++ b/public/js/tabs-auth.js @@ -23,7 +23,7 @@ // Bereich wie jeder andere: Menüband und Seitenleiste bleiben stehen, der // Wechsel dorthin läuft über denselben showTab()-Weg wie der Wechsel vom // Dashboard ins Projektboard. -const TAB_PANELS = ['board','wochenbericht','load','abwesenheit','people','planung','planchecker','dashboard','wand','settings','admin','plan']; +const TAB_PANELS = ['board','wochenbericht','load','abwesenheit','notizen','people','planung','planchecker','dashboard','wand','settings','admin','plan']; function showTab(t){ // Weichen nach Rollen & Rechte (UI-Gate, die Routen dahinter prüft der @@ -61,6 +61,7 @@ function showTab(t){ if(t==='wochenbericht') renderWochenbericht(); if(t==='load') renderLoad(); if(t==='abwesenheit'){ abwBeimOeffnen(); renderAbwesenheiten(); } + if(t==='notizen' && typeof renderMeineNotizen === 'function') renderMeineNotizen(); if(t==='people') renderPeople(); if(t==='planung') renderPlanung(); if(t==='planchecker') renderPlanChecker(); @@ -108,6 +109,9 @@ function syncPlanNavItem(){ const name = app && app.projName ? app.projName : ''; item.style.display = name ? '' : 'none'; const label = document.getElementById('planNavItemLabel'); - if(label) label.textContent = name || 'Projektbereich'; + // Projektnummer in Mono-Ziffern davor (Kennzeichen „Bauplan“). + if(label) label.innerHTML = name + ? (app.projNr ? '' + esc(app.projNr) + ' ' : '') + esc(name) + : 'Projektbereich'; item.title = name ? ('Projektbereich: ' + name) : 'Projektbereich'; } diff --git a/public/plan-styles.css b/public/plan-styles.css index 0d92602..fa8fdf4 100644 --- a/public/plan-styles.css +++ b/public/plan-styles.css @@ -12,20 +12,20 @@ .plan-page { display: flex; flex-direction: column; } .plan-header { - display: flex; align-items: center; gap: 14px; flex-wrap: wrap; + display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 12px 24px; background: var(--surface); border-bottom: 1px solid var(--line-soft); } -.plan-header h1 { font-size: 16px; margin: 0; font-weight: 600; white-space: nowrap; } +.plan-header h1 { font-size: 19px; margin: 0; font-weight: 500; white-space: nowrap; } .plan-header .plan-id { - font-family: ui-monospace, 'SF Mono', monospace; font-size: 12.5px; color: var(--text-muted); white-space: nowrap; + font-family: ui-monospace, 'SF Mono', monospace; font-size: 13px; color: var(--text-muted); white-space: nowrap; } -.plan-header .subtitle { color: var(--text-muted); font-size: 12.5px; white-space: nowrap; } +.plan-header .subtitle { color: var(--text-muted); font-size: 13px; white-space: nowrap; } .plan-header-spacer { flex: 1; min-width: 12px; } .plan-header-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; } .plan-body { flex: 1; display: flex; gap: 0; } .plan-main { flex: 1; display: flex; flex-direction: column; background: var(--bg); min-width: 0; } .plan-main-header { - padding: 0 0 14px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; + padding: 0 0 16px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; } .plan-main-content { flex: 1; padding: 20px 20px 20px; min-width: 0; } .todo-row:last-child { margin-bottom: 0; } @@ -45,7 +45,7 @@ .plan-toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%) translateY(20px); background: var(--surface); color: var(--text); border: 1px solid var(--line); - padding: 10px 18px; border-radius: var(--r-pill); + padding: 12px 20px; border-radius: 8px; font-size: 13px; opacity: 0; pointer-events: none; transition: opacity .25s, transform .25s; z-index: 1000; box-shadow: var(--sh-3); } @@ -53,11 +53,11 @@ .plan-resource-grid { display: grid !important; grid-template-columns: repeat(auto-fill, minmax(140px, max-content)) !important; - gap: 10px !important; + gap: 8px !important; justify-content: start !important; } .plan-resource-card { - padding: 8px 10px !important; + padding: 8px 12px !important; min-height: 0 !important; width: 140px !important; max-width: 140px !important; @@ -83,7 +83,7 @@ display: flex; align-items: center; gap: 8px; - padding: 5px 6px; + padding: 4px 6px; border-radius: var(--r-sm); cursor: pointer; font-size: 12px; @@ -96,8 +96,7 @@ color: var(--text-muted); margin-top: 6px; margin-bottom: 2px; - text-transform: uppercase; - letter-spacing: .03em; + letter-spacing: 0; } .todo-depends-group:first-child { margin-top: 0; } /* Im eingeklappten Bereich trägt bereits das
den Rahmen */ @@ -113,7 +112,7 @@ .todo-depends-item.is-blocked:hover { background: transparent; } .todo-depends-note { margin-left: auto; - font-size: 10.5px; + font-size: 11px; color: var(--amber); white-space: nowrap; } @@ -128,7 +127,7 @@ align-items: baseline; justify-content: space-between; gap: 12px; - margin-bottom: 18px; + margin-bottom: 16px; } .modal-head h2 { margin: 0; } .modal-kbd { font-size: 11px; color: var(--text-subtle); white-space: nowrap; } @@ -149,8 +148,8 @@ font-weight: 500; color: var(--text-muted); background: var(--surface-sunk); - border-radius: var(--r-pill); - padding: 3px 9px; + border-radius: 6px; + padding: 4px 8px; white-space: nowrap; font-variant-numeric: tabular-nums; } @@ -160,13 +159,13 @@ .person-chip { display: inline-flex; align-items: center; - gap: 7px; + gap: 8px; background: var(--surface); color: var(--text-muted); border: 1px solid var(--line); - border-radius: var(--r-pill); + border-radius: 6px; padding: 4px 12px 4px 4px; - font-size: 12.5px; + font-size: 13px; font-weight: 500; transition: border-color .15s var(--ease), background .15s var(--ease), color .15s var(--ease); } @@ -180,8 +179,8 @@ display: flex; align-items: center; justify-content: center; - font-size: 10px; - font-weight: 600; + font-size: 11px; + font-weight: 500; } .person-chip[aria-pressed="true"] { background: var(--accent-soft); @@ -208,7 +207,7 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .segmented { display: inline-flex; background: var(--surface-sunk); - border-radius: var(--r-pill); + border-radius: 8px; padding: 2px; gap: 2px; width: fit-content; @@ -216,9 +215,9 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .segmented button { background: transparent; color: var(--text-muted); - padding: 5px 14px; - font-size: 12.5px; - border-radius: var(--r-pill); + padding: 4px 16px; + font-size: 13px; + border-radius: 6px; display: flex; align-items: center; gap: 6px; @@ -227,7 +226,7 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .segmented button[aria-pressed="true"] { background: var(--surface); color: var(--text); - font-weight: 600; + font-weight: 500; box-shadow: var(--sh-1); } .segmented-dot { @@ -239,7 +238,7 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .segmented button[data-status="arbeit"][aria-pressed="true"] .segmented-dot { background: var(--amber); } .segmented button[data-status="fertig"][aria-pressed="true"] .segmented-dot { background: var(--green); } -.progress-row { display: flex; align-items: center; gap: 10px; margin-top: 10px; } +.progress-row { display: flex; align-items: center; gap: 8px; margin-top: 8px; } .progress-row[hidden] { display: none; } .progress-row input[type=range] { flex: 1; accent-color: var(--accent); } .progress-row output { @@ -260,38 +259,38 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .fold > summary { cursor: pointer; list-style: none; - padding: 9px 11px; + padding: 8px 12px; display: flex; align-items: center; - gap: 9px; - font-size: 12.5px; + gap: 8px; + font-size: 13px; user-select: none; } .fold > summary::-webkit-details-marker { display: none; } .fold > summary:hover { background: var(--surface-alt); } .fold-caret { color: var(--text-subtle); - font-size: 10px; + font-size: 11px; transition: transform .18s var(--ease); } .fold[open] > summary .fold-caret { transform: rotate(90deg); } .fold-count { margin-left: auto; font-size: 11px; - font-weight: 600; + font-weight: 500; background: var(--accent-soft); color: var(--accent); - border-radius: var(--r-pill); - padding: 1px 9px; + border-radius: 6px; + padding: 1px 8px; font-variant-numeric: tabular-nums; } .fold-count.zero { background: var(--surface-sunk); color: var(--text-subtle); } .fold-body { - padding: 9px 11px 11px; + padding: 8px 12px 12px; border-top: 1px solid var(--line-soft); display: flex; flex-direction: column; - gap: 7px; + gap: 8px; } .fold-search { position: relative; } .fold-search input { width: 100%; padding-left: 28px; } @@ -336,14 +335,14 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } box-shadow: var(--sh-1); } .plan-kpi-tile .kpi-label { - font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; - color: var(--text-subtle); font-weight: 600; margin-bottom: 4px; + font-size: 11px; letter-spacing: 0; + color: var(--text-subtle); font-weight: 500; margin-bottom: 4px; } .plan-kpi-tile .kpi-value { - font-size: 22px; font-weight: 700; letter-spacing: -0.02em; color: var(--text); + font-size: 24px; font-weight: 600; letter-spacing: 0; color: var(--text); font-variant-numeric: tabular-nums; } -.plan-kpi-tile .kpi-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; } +.plan-kpi-tile .kpi-sub { font-size: 12px; color: var(--text-muted); margin-top: 2px; } .plan-kpi-tile.warn .kpi-value { color: var(--amber); } /* Kompakt-Karten im Dashboard (Ressourcen-Auslastung, Dateien & Freigaben, @@ -352,23 +351,23 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .plan-card-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); - gap: 14px; - margin-top: 18px; + gap: 12px; + margin-top: 16px; } .plan-mini-card { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); - padding: 14px 16px; cursor: pointer; transition: box-shadow .15s, transform .15s; + padding: 16px 16px; cursor: pointer; transition: box-shadow .15s, transform .15s; } .plan-mini-card:hover { box-shadow: var(--sh-2); transform: translateY(-1px); } .plan-mini-card-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; } -.plan-mini-card-title { font-size: 13px; font-weight: 600; } +.plan-mini-card-title { font-size: 13px; font-weight: 500; } .plan-mini-card-expand { font-size: 11px; color: var(--accent); font-weight: 500; flex-shrink: 0; } .plan-mini-card-preview { - font-size: 12.5px; color: var(--text-muted); line-height: 1.5; + font-size: 13px; color: var(--text-muted); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .plan-mini-chip-row { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; } -.plan-mini-chip { font-size: 10.5px; padding: 2px 8px; border-radius: var(--r-pill); background: var(--surface-sunk); color: var(--text-muted); } +.plan-mini-chip { font-size: 11px; padding: 2px 8px; border-radius: 6px; background: var(--surface-sunk); color: var(--text-muted); } .plan-mini-chip.warn { background: rgba(178,80,0,.12); color: var(--amber); } .plan-heat-row { display: flex; gap: 4px; } .plan-heat-cell { flex: 1; height: 18px; border-radius: 4px; background: var(--accent); } @@ -415,57 +414,57 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } border: 1px solid var(--line-soft); border-left: 3px solid var(--amber); border-radius: var(--r-md); - padding: 10px 14px; + padding: 12px 16px; margin-bottom: 12px; } .plan-warning-head { - display: flex; align-items: center; gap: 7px; - font-size: 12.5px; font-weight: 600; color: var(--amber); + display: flex; align-items: center; gap: 8px; + font-size: 13px; font-weight: 500; color: var(--amber); } .plan-warning-list { - margin: 6px 0 0; padding-left: 26px; - font-size: 12.5px; color: var(--text-muted); line-height: 1.55; + margin: 6px 0 0; padding-left: 28px; + font-size: 13px; color: var(--text-muted); line-height: 1.55; } /* Projektübergreifende Auslastung in der Ressourcen-Karte */ .plan-resource-other { - font-size: 10px; margin-top: 4px; font-weight: 600; color: var(--amber); + font-size: 11px; margin-top: 4px; font-weight: 500; color: var(--amber); cursor: help; } .plan-resource-other.muted { color: var(--text-subtle); font-weight: 400; cursor: default; } /* --- Verlaufs-Modal (plan-history.js) --- */ .history-list { - display: flex; flex-direction: column; gap: 10px; + display: flex; flex-direction: column; gap: 8px; max-height: 58vh; overflow-y: auto; } .history-entry { border: 1px solid var(--line-soft); border-radius: var(--r-md); - background: var(--surface-alt); padding: 10px 12px; + background: var(--surface-alt); padding: 12px 12px; } .history-entry.current { border-color: var(--accent); background: var(--surface); } .history-entry-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; } -.history-week { font-size: 12.5px; font-weight: 600; } -.history-date { font-size: 11.5px; color: var(--text-subtle); } +.history-week { font-size: 13px; font-weight: 500; } +.history-date { font-size: 12px; color: var(--text-subtle); } .history-badge { - font-size: 10px; font-weight: 600; padding: 2px 7px; border-radius: var(--r-pill); + font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: 6px; background: var(--accent-soft); color: var(--accent); } .history-badge.muted { background: var(--surface-sunk); color: var(--text-subtle); } -.history-entry-text { font-size: 12.5px; line-height: 1.5; color: var(--text); } +.history-entry-text { font-size: 13px; line-height: 1.5; color: var(--text); } .history-entry-text p { margin: 0 0 4px; } .history-entry-text p:last-child { margin-bottom: 0; } /* --- Vorlagen-Modal (plan-templates.js) --- */ .template-head-grid { - display: grid; grid-template-columns: 1fr 1fr; gap: 14px; + display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } -.template-admin-list { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; } +.template-admin-list { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; } .template-admin-row { display: flex; align-items: center; gap: 8px; - font-size: 12.5px; padding: 4px 6px; + font-size: 13px; padding: 4px 6px; background: var(--surface-alt); border-radius: var(--r-sm); } .template-admin-title { flex: 1; min-width: 0; } @@ -474,27 +473,27 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .template-add-row input[type=number] { width: 70px; } /* --- Honorar-Terminplan (plan-honorar.js) --- */ -.honorar-check { display: flex; align-items: center; gap: 7px; font-size: 12.5px; cursor: help; } +.honorar-check { display: flex; align-items: center; gap: 8px; font-size: 13px; cursor: help; } .honorar-plan-wrap { overflow-x: auto; margin-top: 4px; } -.honorar-table { font-size: 12.5px; } +.honorar-table { font-size: 13px; } .honorar-table th.num, .honorar-table td.num { text-align: right; font-variant-numeric: tabular-nums; } .honorar-table td.nowrap { white-space: nowrap; } -.honorar-table input[type=number] { width: 58px; padding: 3px 6px; font-size: 12px; text-align: center; } +.honorar-table input[type=number] { width: 58px; padding: 4px 6px; font-size: 12px; text-align: center; } .honorar-table tfoot th, .honorar-table tfoot td { - border-top: 2px solid var(--line); font-weight: 600; background: var(--surface-alt); + border-top: 2px solid var(--line); font-weight: 500; background: var(--surface-alt); } .honorar-anteil-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); - gap: 8px; margin-bottom: 10px; + gap: 8px; margin-bottom: 8px; } .honorar-anteil-field { display: flex; align-items: center; gap: 6px; font-size: 12px; } .honorar-anteil-field span { width: 46px; flex-shrink: 0; color: var(--text-muted); } .honorar-anteil-field input { width: 100%; min-width: 0; padding: 4px 6px; font-size: 12px; text-align: right; } -.honorar-admin-foot { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; } -.honorar-satz-field { display: flex; align-items: center; gap: 6px; font-size: 12.5px; } -.honorar-satz-field input { width: 78px; padding: 4px 7px; font-size: 12.5px; text-align: right; } -.honorar-sum { font-size: 12.5px; font-weight: 600; } +.honorar-admin-foot { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; } +.honorar-satz-field { display: flex; align-items: center; gap: 6px; font-size: 13px; } +.honorar-satz-field input { width: 78px; padding: 4px 8px; font-size: 13px; text-align: right; } +.honorar-sum { font-size: 13px; font-weight: 500; } .honorar-sum.ok { color: var(--green); } .honorar-sum.warn { color: var(--amber); } @@ -507,25 +506,25 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } /* Upload-Maske des Bereichs "Dateien": oben ausgerichtet, damit Dateiauswahl und Prüferliste in der breiten Karte auf gleicher Höhe beginnen (im früheren Modal war sie unten ausgerichtet). */ -.plan-files-upload { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start; margin-bottom: 4px; } +.plan-files-upload { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start; margin-bottom: 4px; } .plan-files-upload .form-row { margin-bottom: 0; } .plan-files-upload #fileUploadReviewers { width: 240px; } -.files-list { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; max-height: 50vh; overflow-y: auto; } +.files-list { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; max-height: 50vh; overflow-y: auto; } .file-item { border: 1px solid var(--line-soft); border-radius: var(--r-md); - background: var(--surface-alt); padding: 10px 12px; + background: var(--surface-alt); padding: 12px 12px; } .file-item-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; } .file-item-name { font-weight: 500; font-size: 13px; word-break: break-all; } .file-item-meta { font-size: 11px; color: var(--text-muted); margin-top: 2px; } .file-status-badge { - font-size: 11px; padding: 2px 8px; border-radius: var(--r-pill); color: #fff; flex-shrink: 0; + font-size: 11px; padding: 2px 8px; border-radius: 6px; color: #fff; flex-shrink: 0; } .file-status-badge.pending, .file-reviewer-chip.pending { background: #d18b00; } .file-status-badge.approved, .file-reviewer-chip.approved { background: var(--green); } .file-status-badge.rejected, .file-reviewer-chip.rejected { background: var(--red); } -.file-reviewer-list { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; } -.file-reviewer-chip { font-size: 11px; padding: 2px 8px; border-radius: var(--r-pill); color: #fff; } +.file-reviewer-list { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; } +.file-reviewer-chip { font-size: 11px; padding: 2px 8px; border-radius: 6px; color: #fff; } .file-item-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; } .file-comments { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line-soft); } .file-comment-list { display: flex; flex-direction: column; gap: 6px; max-height: 160px; overflow-y: auto; } @@ -554,7 +553,7 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } border: none; border-bottom: 2px solid transparent; border-radius: 0; - padding: 10px 14px; + padding: 12px 16px; font-size: 13px; font-weight: 500; white-space: nowrap; @@ -563,7 +562,7 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .plan-nav-item.is-active { color: var(--accent); border-bottom-color: var(--accent); - font-weight: 600; + font-weight: 500; } .plan-section { display: none; } @@ -573,20 +572,20 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .plan-panel-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 14px; + gap: 12px; margin-top: 16px; } .plan-panel { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); - padding: 14px 16px; + padding: 16px 16px; } .plan-panel-wide { grid-column: 1 / -1; } .plan-panel-title { font-size: 13px; - font-weight: 600; - margin: 0 0 10px; + font-weight: 500; + margin: 0 0 8px; display: flex; align-items: baseline; gap: 8px; @@ -611,8 +610,8 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .plan-task-row { display: flex; align-items: center; - gap: 10px; - padding: 8px 10px; + gap: 8px; + padding: 8px 12px; background: var(--surface-alt); border: 1px solid var(--line-soft); border-radius: var(--r-md); @@ -626,36 +625,35 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .plan-task-dot.fertig { background: var(--green); } .plan-task-title { flex: 1; font-size: 13px; font-weight: 500; min-width: 0; } .plan-task-meta { - font-size: 11.5px; + font-size: 12px; color: var(--text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; } -.plan-task-meta.overdue { color: var(--red); font-weight: 600; } -.plan-task-no-schedule { color: var(--text-subtle); font-style: italic; } +.plan-task-meta.overdue { color: var(--red); font-weight: 500; } +.plan-task-no-schedule { color: var(--text-subtle); font-style: normal; } .plan-task-assignees { display: flex; flex-shrink: 0; } .plan-task-assignees .board-avatar { margin-left: -7px; border: 2px solid var(--surface-alt); } .plan-task-assignees .board-avatar:first-child { margin-left: 0; } -.plan-task-empty { font-size: 12.5px; color: var(--text-subtle); padding: 10px 0; } +.plan-task-empty { font-size: 13px; color: var(--text-subtle); padding: 12px 0; } /* --- Dashboard: Liste der nächsten Termine (renderPlanDashboard()) --- */ -.plan-upcoming-list { display: flex; flex-direction: column; gap: 7px; } -.plan-upcoming-item { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px; } +.plan-upcoming-list { display: flex; flex-direction: column; gap: 8px; } +.plan-upcoming-item { display: flex; align-items: baseline; gap: 8px; font-size: 13px; } .plan-upcoming-date { color: var(--text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; min-width: 82px; } -.plan-upcoming-item.overdue .plan-upcoming-date { color: var(--red); font-weight: 600; } +.plan-upcoming-item.overdue .plan-upcoming-date { color: var(--red); font-weight: 500; } .plan-upcoming-kind { - font-size: 10px; - text-transform: uppercase; - letter-spacing: .04em; + font-size: 11px; + letter-spacing: 0; color: var(--text-subtle); } -.plan-dash-team { display: flex; flex-direction: column; gap: 7px; } -.plan-dash-team-row { display: flex; align-items: center; gap: 8px; font-size: 12.5px; } +.plan-dash-team { display: flex; flex-direction: column; gap: 8px; } +.plan-dash-team-row { display: flex; align-items: center; gap: 8px; font-size: 13px; } /* === Bereich "Protokolle" (js/plan/plan-protokoll.js) === Listenansicht (.protokoll-row je Protokoll) und Detailansicht @@ -675,35 +673,35 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } Damit entfällt das frühere Gegeneinander von Zeilen-Gelb und Feldrahmen. */ -.protokoll-list-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; } +.protokoll-list-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; } .protokoll-row { display: grid; grid-template-columns: 64px 1fr 140px 170px 100px; align-items: center; - gap: 14px; - padding: 11px 4px; + gap: 12px; + padding: 12px 4px; border-bottom: 1px solid var(--line-soft); cursor: pointer; transition: background .12s var(--ease); } .protokoll-row:last-child { border-bottom: none; } .protokoll-row:hover { background: var(--surface-alt); } -.protokoll-nr { font-variant-numeric: tabular-nums; font-weight: 650; color: var(--text-muted); font-size: 13px; } +.protokoll-nr { font-variant-numeric: tabular-nums; font-weight: 500; color: var(--text-muted); font-size: 13px; } .protokoll-betreff { font-weight: 560; font-size: 13px; } -.protokoll-datum { display: block; font-weight: 400; color: var(--text-subtle); font-size: 11.5px; margin-top: 2px; } -.protokoll-verfasser { color: var(--text-muted); font-size: 12.5px; } -.protokoll-punkte-status { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-muted); } +.protokoll-datum { display: block; font-weight: 400; color: var(--text-subtle); font-size: 12px; margin-top: 2px; } +.protokoll-verfasser { color: var(--text-muted); font-size: 13px; } +.protokoll-punkte-status { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-muted); } .protokoll-status-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--amber); flex-shrink: 0; } .protokoll-punkte-status.ist-leer .protokoll-status-dot { background: var(--green); } -.protokoll-teilnehmer-count { color: var(--text-subtle); font-size: 12.5px; text-align: right; } +.protokoll-teilnehmer-count { color: var(--text-subtle); font-size: 13px; text-align: right; } .protokoll-back-link { display: flex; align-items: center; gap: 6px; color: var(--text-muted); font-size: 13px; - margin-bottom: 14px; cursor: pointer; width: fit-content; } + margin-bottom: 12px; cursor: pointer; width: fit-content; } .protokoll-back-link:hover { color: var(--text); } .protokoll-import-banner { background: var(--protokoll-neu-bg); border: 1px solid var(--protokoll-neu-border); - border-radius: var(--r-md); padding: 10px 14px; font-size: 12.5px; color: var(--text); margin-bottom: 14px; } + border-radius: var(--r-md); padding: 12px 16px; font-size: 13px; color: var(--text); margin-bottom: 12px; } /* KI-Erkennung angefordert, aber fehlgeschlagen (kein Schlüssel, Netzwerk- fehler, unerwartete Antwort …) — eigene, wärmere Farbe als der neutrale @@ -714,7 +712,7 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } Server aus ist er wieder weg, das einmalige Ereignis ist dann bereits zur Kenntnis genommen. */ .protokoll-ki-fallback-banner { background: color-mix(in srgb, var(--amber) 10%, transparent); border: 1px solid var(--amber); - border-radius: var(--r-md); padding: 10px 14px; font-size: 12.5px; color: var(--text); margin-bottom: 14px; } + border-radius: var(--r-md); padding: 12px 16px; font-size: 13px; color: var(--text); margin-bottom: 12px; } /* Ladehinweis im Import-Dialog (#protokollImportLoading, Test.html): ohne ihn wirkte der Dialog während eines länger laufenden KI-Aufrufs (bis zu @@ -728,9 +726,9 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } überschrieben und den Kasten dauerhaft sichtbar gemacht — genau das ist beim ersten Versuch ohne diese Zeile passiert. */ .protokoll-import-loading[hidden] { display: none; } -.protokoll-import-loading { display: flex; align-items: center; gap: 10px; margin-top: 12px; - padding: 10px 12px; background: var(--surface-alt); border: 1px solid var(--line-soft); - border-radius: var(--r-md); font-size: 12.5px; color: var(--text-muted); } +.protokoll-import-loading { display: flex; align-items: center; gap: 8px; margin-top: 12px; + padding: 12px 12px; background: var(--surface-alt); border: 1px solid var(--line-soft); + border-radius: var(--r-md); font-size: 13px; color: var(--text-muted); } .protokoll-import-spinner { width: 15px; height: 15px; flex-shrink: 0; border-radius: 50%; border: 2px solid var(--line); border-top-color: var(--accent); animation: protokoll-import-spin .8s linear infinite; } @@ -740,8 +738,8 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } oben im Dialog zeigen den Fortschritt durch Hochladen → Punkte → Aufgaben — erledigte/aktuelle Schritte gefüllt, kommende leer. Entwurf "A — Schritt-Dialog" (Taste-Skill-Vergleich, Eriks Wahl). */ -.protokoll-todos-steps { display: flex; gap: 5px; margin: 12px 0 16px; } -.protokoll-todos-steps .seg { flex: 1; height: 4px; border-radius: 2px; background: var(--line-soft); } +.protokoll-todos-steps { display: flex; gap: 4px; margin: 12px 0 16px; } +.protokoll-todos-steps .seg { flex: 1; height: 4px; border-radius: 4px; background: var(--line-soft); } .protokoll-todos-steps .seg.done { background: var(--accent); } /* Schritt 3 ("Aufgaben bestätigen"), Entwurfsrichtung "B — Kompakte Zeilen" @@ -753,29 +751,29 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } Zuständigen-Auswahl) erscheinen erst nach Antippen der Zeile (.protokoll-todo-vorschlag.open). */ .pt-sel-bar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; } -.pt-sel-count { font-size: 12.5px; color: var(--text-muted); } -.pt-sel-count b { color: var(--accent); font-weight: 700; } -.pt-sel-actions button { appearance: none; border: none; background: none; font: inherit; font-size: 11.5px; - font-weight: 650; color: var(--accent); cursor: pointer; padding: 2px 3px; } +.pt-sel-count { font-size: 13px; color: var(--text-muted); } +.pt-sel-count b { color: var(--accent); font-weight: 600; } +.pt-sel-actions button { appearance: none; border: none; background: none; font: inherit; font-size: 12px; + font-weight: 500; color: var(--accent); cursor: pointer; padding: 2px 4px; } .pt-sel-actions button:hover { text-decoration: underline; } .protokoll-todo-vorschlag { border-bottom: 1px solid var(--line-soft); } .protokoll-todo-vorschlag:last-child { border-bottom: none; } -.pt-row-main { display: flex; align-items: center; gap: 9px; padding: 8px 6px; cursor: pointer; } +.pt-row-main { display: flex; align-items: center; gap: 8px; padding: 8px 6px; cursor: pointer; } .protokoll-todo-vorschlag.off .pt-row-main { opacity: .45; } .pt-row-main .pt-vorschlag-check { flex-shrink: 0; accent-color: var(--accent); cursor: pointer; } .pt-row-main .pt-vorschlag-titel { flex: 1; min-width: 0; border: none; background: none; font: inherit; - font-weight: 650; font-size: 12.8px; color: var(--text); padding: 2px 0; + font-weight: 500; font-size: 12.8px; color: var(--text); padding: 2px 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .pt-row-badges { display: flex; align-items: center; gap: 6px; flex-shrink: 0; } -.pt-badge-date { font-size: 10.5px; font-weight: 650; padding: 2px 8px; border-radius: 999px; +.pt-badge-date { font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: 6px; background: var(--accent-soft); color: var(--accent); white-space: nowrap; } /* Pille statt perfektem Kreis: ein Kürzel ist 2-4 Zeichen lang (initialsForName(), js/utils.js), ein starrer 18px-Kreis hätte "THK" o. Ä. abgeschnitten. */ -.pt-badge-person { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px; +.pt-badge-person { min-width: 18px; height: 18px; padding: 0 4px; border-radius: 999px; background: var(--accent); color: var(--surface); - font-size: 9px; font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } -.pt-chevron { color: var(--text-subtle); font-size: 10.5px; width: 12px; text-align: center; + font-size: 11px; font-weight: 600; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } +.pt-chevron { color: var(--text-subtle); font-size: 11px; width: 12px; text-align: center; transition: transform .15s; flex-shrink: 0; } .protokoll-todo-vorschlag.open .pt-chevron { transform: rotate(90deg); } .pt-row-detail { display: none; padding: 0 6px 12px; } @@ -785,20 +783,20 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .protokoll-detail-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 20px; padding-bottom: 16px; border-bottom: 1px solid var(--line-soft); margin-bottom: 16px; } -.protokoll-detail-meta { color: var(--text-muted); font-size: 12.5px; } +.protokoll-detail-meta { color: var(--text-muted); font-size: 13px; } -.protokoll-field-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 20px; } -.protokoll-field { display: flex; flex-direction: column; gap: 5px; } -.protokoll-field label { font-size: 11.5px; color: var(--text-subtle); text-transform: uppercase; letter-spacing: .04em; } +.protokoll-field-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 20px; } +.protokoll-field { display: flex; flex-direction: column; gap: 4px; } +.protokoll-field label { font-size: 12px; color: var(--text-subtle); letter-spacing: 0; } .protokoll-block { margin-top: 20px; } -.protokoll-block-head { margin-bottom: 10px; display: flex; align-items: center; justify-content: space-between; } -.protokoll-block-head h4 { margin: 0; font-size: 13.5px; font-weight: 650; } +.protokoll-block-head { margin-bottom: 8px; display: flex; align-items: center; justify-content: space-between; } +.protokoll-block-head h4 { margin: 0; font-size: 13px; font-weight: 500; } -.protokoll-teilnehmer-row { display: grid; grid-template-columns: 1fr 160px 100px 24px; gap: 10px; align-items: center; - padding: 7px 0; border-bottom: 1px solid var(--line-soft); font-size: 13px; } +.protokoll-teilnehmer-row { display: grid; grid-template-columns: 1fr 160px 100px 24px; gap: 8px; align-items: center; + padding: 8px 0; border-bottom: 1px solid var(--line-soft); font-size: 13px; } .protokoll-teilnehmer-row:last-of-type { border-bottom: none; } -.protokoll-anwesend-toggle { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-muted); } +.protokoll-anwesend-toggle { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-muted); } .protokoll-anwesend-toggle input { accent-color: var(--green); } .protokoll-row-remove { color: var(--text-subtle); text-align: center; cursor: pointer; opacity: .6; flex-shrink: 0; } .protokoll-row-remove:hover { opacity: 1; color: var(--red); } @@ -811,15 +809,15 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } ein kleiner Fließtext, keine Tabellenzelle — in der Spalte blieb für den Text weder Breite noch Höhe, Thema und Text klebten übereinander und die Formatierungsleiste saß eingeklemmt dazwischen. */ -.protokoll-split { display: grid; grid-template-columns: 290px minmax(0, 1fr); gap: 14px; align-items: start; } +.protokoll-split { display: grid; grid-template-columns: 290px minmax(0, 1fr); gap: 12px; align-items: start; } .protokoll-liste { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; box-shadow: var(--sh-1); } .protokoll-liste-kopf { - padding: 9px 12px; background: var(--surface-alt); border-bottom: 1px solid var(--line); - font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-subtle); + padding: 8px 12px; background: var(--surface-alt); border-bottom: 1px solid var(--line); + font-size: 11px; font-weight: 600; letter-spacing: 0; color: var(--text-subtle); } /* Gruppen-Kopfzeile: Farbbalken links aus dem Gruppennamen gehasht (protokollGruppeFarbe(), plan-protokoll.js — dasselbe Prinzip wie @@ -827,7 +825,7 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } egal an welcher Position sie steht. Der Name selbst ist das Eingabefeld: umbenennen wirkt auf alle Punkte der Gruppe. */ .protokoll-liste-gruppe { - display: flex; align-items: center; gap: 7px; padding: 8px 10px 8px 11px; + display: flex; align-items: center; gap: 8px; padding: 8px 12px 8px 12px; background: var(--surface-sunk); border-bottom: 1px solid var(--line-soft); border-left: 3px solid var(--protokoll-gruppe-farbe, var(--accent)); } @@ -838,21 +836,21 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } weiter unten: die Dark-Mode-Fassung von input[type=text] (styles.css) hängt ein html-Element vor den Selektor und gewinnt sonst. */ .protokoll-liste-gruppe input.protokoll-gruppe-heading { - flex: 1; min-width: 0; font-size: 12px; font-weight: 700; letter-spacing: .01em; + flex: 1; min-width: 0; font-size: 12px; font-weight: 600; letter-spacing: .01em; border: none !important; background: none !important; border-radius: 4px !important; - color: var(--text) !important; padding: 2px 3px !important; + color: var(--text) !important; padding: 2px 4px !important; } -.protokoll-liste-gruppe input.protokoll-gruppe-heading::placeholder { color: var(--text-subtle); font-weight: 550; } +.protokoll-liste-gruppe input.protokoll-gruppe-heading::placeholder { color: var(--text-subtle); font-weight: 500; } .protokoll-liste-gruppe input.protokoll-gruppe-heading:focus { outline: none; } .protokoll-liste-gruppe input.protokoll-gruppe-heading:focus-visible { box-shadow: 0 0 0 2px var(--accent-soft) inset; } .protokoll-liste-gruppe .count { - font-size: 10px; font-variant-numeric: tabular-nums; color: var(--text-subtle); - background: var(--surface); border: 1px solid var(--line); border-radius: 980px; padding: 0 6px; flex-shrink: 0; + font-size: 11px; font-variant-numeric: tabular-nums; color: var(--text-subtle); + background: var(--surface); border: 1px solid var(--line); border-radius: 6px; padding: 0 6px; flex-shrink: 0; } .protokoll-liste-zeile { display: grid; grid-template-columns: 30px minmax(0, 1fr) auto; gap: 2px 8px; align-items: baseline; - padding: 8px 11px; cursor: pointer; border-bottom: 1px solid var(--line-soft); + padding: 8px 12px; cursor: pointer; border-bottom: 1px solid var(--line-soft); border-left: 3px solid transparent; } .protokoll-liste-zeile:hover { background: var(--surface-alt); } @@ -864,16 +862,16 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } auto-Spalte — die Unterzeile blieb dann auf zwei Zeichen abgeschnitten. */ .protokoll-liste-zeile .nr { grid-column: 1; grid-row: 1; - font-variant-numeric: tabular-nums; font-size: 11.5px; font-weight: 700; color: var(--text-muted); + font-variant-numeric: tabular-nums; font-size: 12px; font-weight: 600; color: var(--text-muted); } .protokoll-liste-zeile.ist-aktiv .nr { color: var(--accent); } .protokoll-liste-zeile .titel { grid-column: 2; grid-row: 1; - font-size: 12.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.protokoll-liste-zeile .titel.ist-leer { font-weight: 500; font-style: italic; color: var(--text-subtle); } +.protokoll-liste-zeile .titel.ist-leer { font-weight: 500; font-style: normal; color: var(--text-subtle); } .protokoll-liste-zeile .sub { - grid-column: 2; grid-row: 2; font-size: 10.5px; color: var(--text-subtle); + grid-column: 2; grid-row: 2; font-size: 11px; color: var(--text-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Das Neu-Kennzeichen steht rechts unter dem Status-Punkt statt in einer @@ -889,37 +887,37 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .protokoll-punkt-dot[data-status="info"] { background: var(--status-info); } .protokoll-liste-neu { - padding: 8px 11px 8px 14px; color: var(--accent); font-size: 12px; font-weight: 600; cursor: pointer; + padding: 8px 12px 8px 16px; color: var(--accent); font-size: 12px; font-weight: 500; cursor: pointer; border-bottom: 1px solid var(--line-soft); } .protokoll-liste-neu:hover { background: var(--surface-alt); color: var(--accent-hover); } .protokoll-liste-neu.ist-gruppe { border-bottom: none; border-top: 1px solid var(--line); } -.protokoll-liste-leer { padding: 14px 12px; font-size: 12.5px; color: var(--text-subtle); } +.protokoll-liste-leer { padding: 16px 12px; font-size: 13px; color: var(--text-subtle); } /* ---------- Schreibbereich ---------- */ .protokoll-schreiben { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; box-shadow: var(--sh-1); } -.protokoll-schreiben.ist-leer { padding: 28px 22px; color: var(--text-muted); font-size: 13px; } +.protokoll-schreiben.ist-leer { padding: 28px 24px; color: var(--text-muted); font-size: 13px; } .protokoll-schreiben.ist-leer p { margin: 0 0 6px; } .protokoll-schreiben.ist-leer p:last-child { margin-bottom: 0; } .protokoll-schreiben-kopf { - display: flex; align-items: center; gap: 9px; flex-wrap: wrap; - padding: 9px 16px; background: var(--surface-alt); border-bottom: 1px solid var(--line-soft); + display: flex; align-items: center; gap: 8px; flex-wrap: wrap; + padding: 8px 16px; background: var(--surface-alt); border-bottom: 1px solid var(--line-soft); } -.protokoll-schreiben-kopf .nr { font-variant-numeric: tabular-nums; font-weight: 700; font-size: 13px; } +.protokoll-schreiben-kopf .nr { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 13px; } .protokoll-schreiben-kopf .gruppe { - font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-subtle); + font-size: 11px; font-weight: 600; letter-spacing: 0; color: var(--text-subtle); } -.protokoll-schreiben-kopf .rechts { margin-left: auto; display: flex; align-items: center; gap: 9px; } +.protokoll-schreiben-kopf .rechts { margin-left: auto; display: flex; align-items: center; gap: 8px; } .protokoll-feld-label { - display: block; font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em; - color: var(--text-subtle); margin-bottom: 5px; + display: block; font-size: 11px; font-weight: 600; letter-spacing: 0; + color: var(--text-subtle); margin-bottom: 4px; } -.protokoll-schreiben-feld { padding: 13px 16px; } +.protokoll-schreiben-feld { padding: 12px 16px; } .protokoll-schreiben-feld + .protokoll-schreiben-feld { border-top: 1px solid var(--line-soft); } /* Thema und Text sitzen randlos in ihrem beschrifteten Abschnitt — der @@ -929,13 +927,13 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } (html:not([data-theme="light"]) …, styles.css), die sonst an Spezifität gewinnt und ein abgerundetes Eingabefeld-Rechteck durchscheinen lässt. */ .protokoll-schreiben-feld input.protokoll-punkt-thema { - font: inherit; font-size: 17px; font-weight: 650; letter-spacing: -.01em; width: 100%; line-height: 1.3; + font: inherit; font-size: 19px; font-weight: 500; letter-spacing: 0; width: 100%; line-height: 1.3; border: none !important; background: none !important; border-radius: 4px !important; color: var(--text) !important; padding: 1px 2px !important; display: block; } .protokoll-schreiben-feld input.protokoll-punkt-thema::placeholder { font-weight: 500; color: var(--text-subtle); } .protokoll-schreiben-feld .protokoll-punkt-text { - font: inherit; font-size: 13.5px; line-height: 1.65; color: var(--text); + font: inherit; font-size: 13px; line-height: 1.65; color: var(--text); min-height: 130px; max-width: 66ch; padding: 1px 2px; border-radius: 4px; } .protokoll-schreiben-feld .protokoll-punkt-text:empty::before { content: attr(data-placeholder); color: var(--text-subtle); } @@ -949,7 +947,7 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } Inhalt nicht. */ .protokoll-schreiben-feld input.protokoll-punkt-thema.ist-geaendert, .protokoll-schreiben-feld .protokoll-punkt-text.ist-geaendert { - background: var(--protokoll-neu-bg) !important; padding: 3px 6px !important; margin: 0 -4px; + background: var(--protokoll-neu-bg) !important; padding: 4px 6px !important; margin: 0 -4px; } /* Die Formatierungsleiste sitzt zwischen Thema und Text — sie gehört zum @@ -958,19 +956,19 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .protokoll-schreiben .richtext-toolbar { border-top: 1px solid var(--line-soft); } .protokoll-schreiben-raster { - display: grid; grid-template-columns: 1fr 1fr; gap: 14px; - padding: 13px 16px; border-top: 1px solid var(--line-soft); + display: grid; grid-template-columns: 1fr 1fr; gap: 12px; + padding: 12px 16px; border-top: 1px solid var(--line-soft); } .protokoll-schreiben-raster input { font: inherit !important; font-size: 13px !important; width: 100%; min-width: 0 !important; color: var(--text) !important; background: var(--surface) !important; - border: 1px solid var(--line) !important; border-radius: var(--r-sm) !important; padding: 6px 9px !important; + border: 1px solid var(--line) !important; border-radius: var(--r-sm) !important; padding: 6px 8px !important; } .protokoll-schreiben-raster input:focus { outline: none; border-color: var(--accent) !important; box-shadow: 0 0 0 3px var(--accent-soft); } .protokoll-schreiben-fuss { - padding: 9px 16px; border-top: 1px solid var(--line-soft); background: var(--surface-alt); + padding: 8px 16px; border-top: 1px solid var(--line-soft); background: var(--surface-alt); font-size: 11px; color: var(--text-subtle); } .protokoll-schreiben-fuss .hint { font-size: 11px; } @@ -978,15 +976,15 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } /* ---------- Chips, Verschieben, Entfernen ---------- */ .protokoll-chip-neu { display: inline-block; width: fit-content; background: var(--protokoll-neu-border); color: #3d2e00; - font-size: 9.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; padding: 1px 6px; - border-radius: var(--r-pill); + font-size: 11px; font-weight: 600; letter-spacing: 0; padding: 1px 6px; + border-radius: 6px; } /* Gnadenrunde eines erledigten Punkts — bewusst Fließtext statt Großbuchstaben-Pille: der Hinweistext ist zu lang dafür. */ .protokoll-chip-entfaellt { display: inline-block; max-width: 100%; background: color-mix(in srgb, var(--red) 15%, transparent); color: var(--red); - font-size: 9.5px; font-weight: 700; line-height: 1.3; padding: 2px 7px; border-radius: var(--r-sm); + font-size: 11px; font-weight: 600; line-height: 1.3; padding: 2px 8px; border-radius: var(--r-sm); } .protokoll-gruppe-move, .protokoll-punkt-move { display: inline-flex; gap: 4px; flex-shrink: 0; } /* button.secondary (styles.css) bringt eine eigene, leicht deckende Fläche @@ -1005,16 +1003,16 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } Senkrecht gestapelt in der Grundform; im Kopf des Schreibbereichs ist Platz, dort liegt er waagerecht. */ .protokoll-status-switch { - display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 7px; padding: 2px; + display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 8px; padding: 2px; background: var(--surface-sunk); gap: 1px; width: 56px; } -.protokoll-status-switch.ist-waagerecht { flex-direction: row; width: auto; border-radius: 980px; } +.protokoll-status-switch.ist-waagerecht { flex-direction: row; width: auto; border-radius: 8px; } .protokoll-status-switch button { - appearance: none; border: none; background: none; font: inherit; font-size: 10.5px; font-weight: 700; - letter-spacing: .01em; padding: 4px 0; border-radius: 5px; cursor: pointer; color: var(--text-subtle); + appearance: none; border: none; background: none; font: inherit; font-size: 11px; font-weight: 600; + letter-spacing: .01em; padding: 4px 0; border-radius: 6px; cursor: pointer; color: var(--text-subtle); text-align: center; transition: background .12s, color .12s; } -.protokoll-status-switch.ist-waagerecht button { padding: 3px 11px; border-radius: 980px; } +.protokoll-status-switch.ist-waagerecht button { padding: 4px 12px; border-radius: 6px; } .protokoll-status-switch button:hover:not(.is-active) { color: var(--text); } .protokoll-status-switch button:disabled { cursor: default; } .protokoll-status-switch button:disabled:hover { color: var(--text-subtle); } @@ -1032,7 +1030,7 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } } .add-row-btn { display: flex; align-items: center; gap: 6px; color: var(--accent); font-size: 13px; - font-weight: 600; cursor: pointer; padding: 8px 0; width: fit-content; } + font-weight: 500; cursor: pointer; padding: 8px 0; width: fit-content; } .add-row-btn:hover { color: var(--accent-hover); } .legend-swatch { width: 13px; height: 13px; border-radius: 4px; flex-shrink: 0; display: inline-block; } @@ -1110,19 +1108,19 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } } .plan-lage-zelle { padding: 12px 16px; min-width: 0; } .plan-lage-zelle + .plan-lage-zelle { border-left: 1px solid var(--line-soft); } -.plan-lage-zelle .kpi-label { font-size: 11px; font-weight: 650; letter-spacing: .05em; text-transform: uppercase; color: var(--text-subtle); } -.plan-lage-zelle .kpi-value { font-size: 22px; font-weight: 600; letter-spacing: -.01em; margin-top: 2px; font-variant-numeric: tabular-nums; } +.plan-lage-zelle .kpi-label { font-size: 11px; font-weight: 500; letter-spacing: 0; color: var(--text-subtle); } +.plan-lage-zelle .kpi-value { font-size: 24px; font-weight: 500; letter-spacing: 0; margin-top: 2px; font-variant-numeric: tabular-nums; } .plan-lage-zelle .kpi-sub { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.plan-lage-zelle .kpi-sub.ist-rot { color: var(--red); font-weight: 600; } -.plan-lage-phase { display: flex; align-items: center; gap: 14px; } +.plan-lage-zelle .kpi-sub.ist-rot { color: var(--red); font-weight: 500; } +.plan-lage-phase { display: flex; align-items: center; gap: 12px; } .plan-lage-ring { flex: none; width: 54px; height: 54px; border-radius: 50%; background: conic-gradient(var(--accent) calc(var(--p) * 1%), color-mix(in srgb, var(--text-subtle) 18%, transparent) 0); -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px)); mask: radial-gradient(farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px)); } -.plan-lage-raster { display: grid; grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr); gap: 14px; align-items: start; margin-top: 14px; } -.plan-lage-spalte { display: flex; flex-direction: column; gap: 14px; min-width: 0; } +.plan-lage-raster { display: grid; grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr); gap: 12px; align-items: start; margin-top: 12px; } +.plan-lage-spalte { display: flex; flex-direction: column; gap: 12px; min-width: 0; } .plan-lage-spalte .plan-panel { box-shadow: var(--sh-1); } @media (max-width: 1000px) { .plan-lage-band { grid-template-columns: 1fr 1fr; } @@ -1133,50 +1131,50 @@ html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); } .plan-panel-title .plan-panel-link, .plan-unterlage-kopf .plan-panel-link { margin-left: auto; } .plan-panel-link { appearance: none; border: 0; background: none !important; box-shadow: none !important; padding: 0; - color: var(--accent); font: inherit; font-size: 12px; font-weight: 550; cursor: pointer; + color: var(--accent); font: inherit; font-size: 12px; font-weight: 500; cursor: pointer; } .plan-panel-link:hover { text-decoration: underline; } .plan-panel-link:active { transform: none; } -.plan-kommentar-fuss { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 10px; } +.plan-kommentar-fuss { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 8px; } .plan-kommentar-autor { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-subtle); } .plan-kommentar-autor:empty { display: none; } -.plan-autor-ava { width: 24px; height: 24px; border-radius: 50%; display: inline-grid; place-items: center; font-size: 9.5px; font-weight: 700; background: var(--accent-soft); color: var(--accent); } +.plan-autor-ava { width: 24px; height: 24px; border-radius: 50%; display: inline-grid; place-items: center; font-size: 11px; font-weight: 600; background: var(--accent-soft); color: var(--accent); } .plan-kommentar-fuss .plan-verweis-row { margin-left: auto; } -.plan-termin-gruppe { display: flex; gap: 6px; align-items: baseline; font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--text-subtle); padding: 10px 0 2px; } +.plan-termin-gruppe { display: flex; gap: 6px; align-items: baseline; font-size: 11px; font-weight: 600; letter-spacing: 0; color: var(--text-subtle); padding: 12px 0 2px; } .plan-termin-gruppe:first-child { padding-top: 0; } .plan-termin-gruppe span { font-weight: 500; letter-spacing: 0; } .plan-termin-gruppe.ist-rot { color: var(--red); } -.plan-termin { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 8px 6px; margin: 0 -6px; border-top: 1px solid var(--line-soft); border-radius: 8px; } +.plan-termin { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; gap: 8px; align-items: center; padding: 8px 6px; margin: 0 -6px; border-top: 1px solid var(--line-soft); border-radius: 8px; } .plan-termin-gruppe + .plan-termin { border-top: 0; } .plan-termin.ist-klickbar { cursor: pointer; } .plan-termin.ist-klickbar:hover { background: var(--surface-sunk); } -.plan-termin-art { width: 22px; height: 22px; border-radius: 7px; display: grid; place-items: center; font-size: 10px; font-weight: 700; background: var(--surface-sunk); color: var(--text-muted); } +.plan-termin-art { width: 22px; height: 22px; border-radius: 8px; display: grid; place-items: center; font-size: 11px; font-weight: 600; background: var(--surface-sunk); color: var(--text-muted); } .plan-termin-art.ist-meins { background: var(--accent-soft); color: var(--accent); } .plan-termin-art.ist-ms { background: color-mix(in srgb, #6d4bb3 14%, transparent); color: #6d4bb3; } .plan-termin-text { min-width: 0; display: flex; flex-direction: column; } -.plan-termin-text b { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.plan-termin-text span { font-size: 11.5px; color: var(--text-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.plan-termin-text b { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.plan-termin-text span { font-size: 12px; color: var(--text-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .plan-termin-datum { text-align: right; font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap; } .plan-termin-datum em { display: block; font-style: normal; font-size: 11px; color: var(--text-subtle); } .plan-termin-datum.ist-rot, .plan-termin-datum.ist-rot em { color: var(--red); } .plan-termin-mehr { margin-top: 8px; } -.plan-team-zeile { display: grid; grid-template-columns: 30px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 7px 0; border-top: 1px solid var(--line-soft); } +.plan-team-zeile { display: grid; grid-template-columns: 30px minmax(0, 1fr) auto; gap: 8px; align-items: center; padding: 8px 0; border-top: 1px solid var(--line-soft); } .plan-team-zeile:first-child { border-top: 0; padding-top: 0; } -.plan-team-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; } -.plan-team-text b { font-weight: 550; } +.plan-team-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; } +.plan-team-text b { font-weight: 500; } .plan-team-rollen { display: flex; flex-wrap: wrap; gap: 4px; } -.plan-rolle { font-size: 10px; font-weight: 600; padding: 1px 7px; border-radius: 999px; background: var(--accent-soft); color: var(--accent); } +.plan-rolle { font-size: 11px; font-weight: 500; padding: 1px 8px; border-radius: 6px; background: var(--accent-soft); color: var(--accent); } .plan-rolle.ist-neben { background: transparent; border: 1px dashed var(--line); color: var(--text-muted); } .plan-team-offen { font-size: 12px; color: var(--text-muted); white-space: nowrap; } -.plan-unterlage { padding: 9px 6px; margin: 0 -6px; border-top: 1px solid var(--line-soft); border-radius: 8px; cursor: pointer; } +.plan-unterlage { padding: 8px 6px; margin: 0 -6px; border-top: 1px solid var(--line-soft); border-radius: 8px; cursor: pointer; } .plan-unterlage:first-child { border-top: 0; padding-top: 2px; } .plan-unterlage:hover { background: var(--surface-sunk); } .plan-unterlage-kopf { display: flex; align-items: baseline; gap: 8px; margin-bottom: 4px; } -.plan-unterlage-kopf b { font-weight: 600; } +.plan-unterlage-kopf b { font-weight: 500; } @media (prefers-color-scheme: dark) { html:not([data-theme="light"]) .plan-termin-art.ist-ms { color: #c3a6ff; } } html[data-theme="dark"] .plan-termin-art.ist-ms { color: #c3a6ff; } @@ -1184,9 +1182,9 @@ html[data-theme="dark"] .plan-termin-art.ist-ms { color: #c3a6ff; } allgemeine .status-edit ist auf die enge Zeile des Boards ausgelegt (11px). Hier ist er das wichtigste Lesefeld des Lagebilds. */ #planSection-dashboard #planStatusEdit { - font-size: 14.5px; + font-size: 15px; line-height: 1.6; - padding: 14px 16px; + padding: 16px 16px; min-height: 160px; border-radius: var(--r-md); border-style: solid; @@ -1197,19 +1195,19 @@ html[data-theme="dark"] .plan-termin-art.ist-ms { color: #c3a6ff; } sagt das der Hinweis darüber. Darunter eine Zeitleiste der früheren Kommentare je Gewerk (renderPlanKommentarVerlauf(), plan-info.js). */ .plan-kommentar-hinweis { - margin-bottom: 10px; padding: 8px 12px; border-radius: var(--r-sm, 8px); - font-size: 12.5px; line-height: 1.45; + margin-bottom: 8px; padding: 8px 12px; border-radius: var(--r-sm, 8px); + font-size: 13px; line-height: 1.45; color: var(--text); background: color-mix(in srgb, var(--amber) 16%, transparent); border: 1px solid color-mix(in srgb, var(--amber) 40%, transparent); } -.plan-kommentar-verlauf { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); } -.plan-verlauf-kopf { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 10px; } -.plan-verlauf-titel { font-size: 11.5px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted); } +.plan-kommentar-verlauf { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); } +.plan-verlauf-kopf { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 8px; } +.plan-verlauf-titel { font-size: 12px; font-weight: 500; letter-spacing: 0; color: var(--text-muted); } .plan-verlauf-anzahl { font-size: 12px; color: var(--text-subtle); } .plan-verlauf-liste { list-style: none; margin: 0; padding: 0; } -.plan-verlauf-eintrag { display: grid; grid-template-columns: 52px 12px minmax(0, 1fr); column-gap: 10px; } -.plan-verlauf-kw { font-size: 12px; font-weight: 600; color: var(--text); padding-top: 1px; white-space: nowrap; } +.plan-verlauf-eintrag { display: grid; grid-template-columns: 52px 12px minmax(0, 1fr); column-gap: 8px; } +.plan-verlauf-kw { font-size: 12px; font-weight: 500; color: var(--text); padding-top: 1px; white-space: nowrap; } .plan-verlauf-punkt { position: relative; } .plan-verlauf-punkt::before { content: ""; position: absolute; left: 1.5px; top: 5px; @@ -1221,13 +1219,13 @@ html[data-theme="dark"] .plan-termin-art.ist-ms { color: #c3a6ff; } content: ""; position: absolute; left: 5px; top: 17px; bottom: 0; width: 2px; background: var(--line); } .plan-verlauf-eintrag:last-child .plan-verlauf-punkt::after { display: none; } -.plan-verlauf-inhalt { padding-bottom: 14px; min-width: 0; } -.plan-verlauf-text { font-size: 13.5px; line-height: 1.5; color: var(--text); overflow-wrap: anywhere; } +.plan-verlauf-inhalt { padding-bottom: 16px; min-width: 0; } +.plan-verlauf-text { font-size: 13px; line-height: 1.5; color: var(--text); overflow-wrap: anywhere; } .plan-verlauf-text p { margin: 0; } -.plan-verlauf-meta { font-size: 11.5px; color: var(--text-subtle); margin-top: 3px; } +.plan-verlauf-meta { font-size: 12px; color: var(--text-subtle); margin-top: 4px; } .plan-verlauf-mehr { border: 1px solid var(--line); background: var(--surface); color: var(--accent); - border-radius: 999px; padding: 6px 14px; font: inherit; font-size: 12.5px; cursor: pointer; + border-radius: 8px; padding: 6px 16px; font: inherit; font-size: 13px; cursor: pointer; } .plan-verlauf-mehr:hover { background: var(--surface-alt); } @@ -1240,29 +1238,29 @@ html[data-theme="dark"] .plan-termin-art.ist-ms { color: #c3a6ff; } display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; font: inherit; color: var(--text); background: var(--surface-sunk); border: 1px solid var(--line-soft); border-radius: var(--r-md, 12px); - padding: 10px 12px; cursor: pointer; + padding: 12px 12px; cursor: pointer; } .plan-prot-kopf:hover { border-color: var(--accent); } .plan-prot-nr { - flex: none; font-size: 12px; font-weight: 700; color: var(--accent); + flex: none; font-size: 12px; font-weight: 600; color: var(--accent); background: var(--accent-soft); border-radius: 8px; padding: 4px 8px; } .plan-prot-titel { min-width: 0; display: flex; flex-direction: column; } -.plan-prot-titel b { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.plan-prot-titel b { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .plan-prot-titel span { font-size: 12px; color: var(--text-subtle); } .plan-prot-punkte { margin-top: 8px; } .plan-prot-punkte:empty { display: none; } .plan-prot-mehr { display: block; margin-top: 6px; } .plan-prot-frueher { - display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 10px; align-items: baseline; - width: 100%; text-align: left; font: inherit; font-size: 12.5px; color: var(--text-muted); - background: none; border: 0; border-top: 1px solid var(--line-soft); padding: 7px 6px; cursor: pointer; border-radius: 8px; + display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 8px; align-items: baseline; + width: 100%; text-align: left; font: inherit; font-size: 13px; color: var(--text-muted); + background: none; border: 0; border-top: 1px solid var(--line-soft); padding: 8px 6px; cursor: pointer; border-radius: 8px; } .plan-termin-gruppe + .plan-prot-frueher { border-top: 0; } .plan-prot-frueher:hover { background: var(--surface-sunk); } .plan-prot-frueher-titel { color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .plan-prot-frueher-zahl { color: var(--amber); font-size: 12px; white-space: nowrap; } -.plan-dash-leer { display: flex; align-items: center; gap: 10px; color: var(--text-subtle); font-size: 13px; } +.plan-dash-leer { display: flex; align-items: center; gap: 8px; color: var(--text-subtle); font-size: 13px; } /* Kachel "Team" nach Gewerk gruppiert (Eriks Wahl "A", plan-sections.js): je Gewerk eine Überschrift mit Personenzahl; ein Gewerk des Projekts ohne @@ -1270,32 +1268,32 @@ html[data-theme="dark"] .plan-termin-art.ist-ms { color: #c3a6ff; } .plan-team-gruppe + .plan-team-gruppe { margin-top: 6px; } .plan-team-gewerk { display: flex; align-items: center; gap: 8px; padding: 6px 0 4px; } .plan-team-gruppe:first-child .plan-team-gewerk { padding-top: 0; } -.plan-gewerk-schild { font-size: 10.5px; font-weight: 700; letter-spacing: .04em; padding: 2px 8px; border-radius: 6px; background: var(--accent-soft); color: var(--accent); } +.plan-gewerk-schild { font-size: 11px; font-weight: 600; letter-spacing: .04em; padding: 2px 8px; border-radius: 6px; background: var(--accent-soft); color: var(--accent); } .plan-gewerk-titel { font-size: 12px; color: var(--text-muted); white-space: nowrap; } .plan-gewerk-linie { flex: 1; height: 1px; background: var(--line-soft); } .plan-gewerk-anzahl { font-size: 12px; color: var(--text-subtle); white-space: nowrap; } .plan-team-gewerk + .plan-team-zeile { border-top: 0; } -.plan-team-luecke { font-size: 12.5px; color: var(--amber); padding: 2px 0 6px; } +.plan-team-luecke { font-size: 13px; color: var(--amber); padding: 2px 0 6px; } /* Einstellungen mit Unternavigation (Eriks Wahl "C", plan-settings.js): links vier Abschnitte mit Kurzfassung, rechts immer genau einer. */ -.plan-einst { display: flex; gap: 14px; align-items: flex-start; margin-top: 4px; } +.plan-einst { display: flex; gap: 12px; align-items: flex-start; margin-top: 4px; } .plan-einst-nav { flex: none; width: 260px; position: sticky; top: 90px; display: flex; flex-direction: column; gap: 4px; padding: 8px; background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); } .plan-einst-reiter { - display: flex; flex-direction: column; align-items: flex-start; gap: 3px; text-align: left; - min-height: 56px; padding: 9px 14px; border: 0; border-radius: 12px; + display: flex; flex-direction: column; align-items: flex-start; gap: 4px; text-align: left; + min-height: 56px; padding: 8px 16px; border: 0; border-radius: 12px; background: transparent; color: var(--text); font: inherit; cursor: pointer; } -.plan-einst-reiter b { font-size: 14px; font-weight: 600; } +.plan-einst-reiter b { font-size: 13px; font-weight: 500; } .plan-einst-reiter span { font-size: 12px; color: var(--text-muted); line-height: 1.35; } .plan-einst-reiter:hover { background: var(--surface-sunk); } .plan-einst-reiter.is-active { background: var(--surface-sunk); box-shadow: inset 3px 0 0 var(--accent); } -.plan-einst-inhalt { flex: 1; min-width: 0; padding: 22px 26px; } -.plan-einst-titel { margin: 0 0 16px; font-size: 18px; font-weight: 650; } +.plan-einst-inhalt { flex: 1; min-width: 0; padding: 24px 28px; } +.plan-einst-titel { margin: 0 0 16px; font-size: 19px; font-weight: 500; } .plan-einst-teil .form-row { max-width: 640px; } .plan-einst-paar { display: grid; grid-template-columns: 180px minmax(0, 1fr); gap: 0 12px; max-width: 640px; } .plan-einst-paar > .form-row { min-width: 0; margin-bottom: 6px; } @@ -1305,27 +1303,27 @@ html[data-theme="dark"] .plan-termin-art.ist-ms { color: #c3a6ff; } .plan-einst-schmal { max-width: 320px; } .plan-einst-chips { display: flex; gap: 8px; flex-wrap: wrap; } .plan-einst-chip { - min-height: 36px; padding: 0 16px; border-radius: 999px; font: inherit; font-size: 13px; cursor: pointer; + min-height: 36px; padding: 0 16px; border-radius: 6px; font: inherit; font-size: 13px; cursor: pointer; border: 1px solid var(--line); background: var(--surface); color: var(--text); } -.plan-einst-chip.an { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; } +.plan-einst-chip.an { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 500; } /* Umschalter (Leistungsphasen, Beteiligte) */ -.plan-einst-seg { display: inline-flex; gap: 2px; padding: 3px; border-radius: 999px; background: var(--surface-sunk); } +.plan-einst-seg { display: inline-flex; gap: 2px; padding: 4px; border-radius: 8px; background: var(--surface-sunk); } .plan-einst-seg button { - border: 0; background: transparent; color: var(--text-muted); font: inherit; font-size: 12.5px; - min-height: 30px; padding: 0 12px; border-radius: 999px; cursor: pointer; white-space: nowrap; + border: 0; background: transparent; color: var(--text-muted); font: inherit; font-size: 13px; + min-height: 30px; padding: 0 12px; border-radius: 6px; cursor: pointer; white-space: nowrap; } -.plan-einst-seg button.an { background: var(--surface); color: var(--accent); font-weight: 600; box-shadow: 0 1px 4px rgba(15,40,60,.12); } +.plan-einst-seg button.an { background: var(--surface); color: var(--accent); font-weight: 500; box-shadow: 0 1px 4px rgba(15,40,60,.12); } .plan-einst-seg button:disabled { cursor: default; } .plan-einst-phasen { display: flex; flex-direction: column; max-width: 760px; } -.plan-einst-phase { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px; align-items: center; padding: 9px 0; border-top: 1px solid var(--line-soft); } +.plan-einst-phase { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px; align-items: center; padding: 8px 0; border-top: 1px solid var(--line-soft); } .plan-einst-phase-name { display: flex; align-items: center; gap: 12px; min-width: 0; } .plan-einst-phase-name b { width: 52px; flex: none; font-size: 13px; } -.plan-einst-phase-name span { font-size: 14px; color: var(--text-muted); } +.plan-einst-phase-name span { font-size: 13px; color: var(--text-muted); } .plan-einst-phase.ist-an .plan-einst-phase-name span { color: var(--text); } -.plan-einst-phase-name em { font-style: normal; font-size: 11px; font-weight: 700; color: var(--accent); background: var(--accent-soft); border-radius: 999px; padding: 2px 8px; } +.plan-einst-phase-name em { font-style: normal; font-size: 11px; font-weight: 600; color: var(--accent); background: var(--accent-soft); border-radius: 6px; padding: 2px 8px; } @media (max-width: 900px) { @@ -1337,10 +1335,10 @@ html[data-theme="dark"] .plan-termin-art.ist-ms { color: #c3a6ff; } allgemeine Feldregel in styles.css kennt type=number nicht; sie dort aufzunehmen träfe auch kompakte Zahlenfelder anderer Bereiche. */ .plan-einst-teil input[type=number] { - padding: 7px 10px; border: 1px solid var(--line); border-radius: var(--r-md); + padding: 8px 12px; border: 1px solid var(--line); border-radius: var(--r-md); font: inherit; font-size: 13px; color: var(--text); background: var(--surface); } -.plan-einst-teil input[type=number]:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(0,113,227,.18); } +.plan-einst-teil input[type=number]:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); } /* Dunkel ist der Akzent hell — weiße Schrift darauf wäre kaum lesbar. */ @media (prefers-color-scheme: dark) { html:not([data-theme="light"]) .plan-einst-chip.an { color: #0b141b; } } html[data-theme="dark"] .plan-einst-chip.an { color: #0b141b; } @@ -1351,79 +1349,79 @@ html[data-theme="dark"] .plan-einst-chip.an { color: #0b141b; } = Unterstützung), Entfernen mit "Rückgängig". */ .plan-einst-teil[data-teil="team"] { position: relative; } .plan-einst-team-kopfzeile { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 8px 20px; } -.plan-einst-team-kopfzeile .plan-einst-hint { margin-bottom: 14px; } -.plan-einst-legende { display: flex; gap: 14px; font-size: 12px; color: var(--text-muted); margin-bottom: 16px; } +.plan-einst-team-kopfzeile .plan-einst-hint { margin-bottom: 12px; } +.plan-einst-legende { display: flex; gap: 12px; font-size: 12px; color: var(--text-muted); margin-bottom: 16px; } .plan-einst-legende span { display: inline-flex; align-items: center; gap: 6px; } .plan-einst-legende i { width: 24px; height: 14px; border-radius: 999px; box-sizing: border-box; } .plan-einst-legende i.ist-haupt { background: var(--accent); } .plan-einst-legende i.ist-neben { border: 1.5px dashed var(--accent); background: var(--accent-soft); } -.plan-einst-sperre { padding: 10px 14px; border-radius: 12px; background: var(--surface-sunk); font-size: 13px; margin-bottom: 14px; } +.plan-einst-sperre { padding: 12px 16px; border-radius: 12px; background: var(--surface-sunk); font-size: 13px; margin-bottom: 12px; } .plan-einst-besetzung { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 16px; } -.plan-einst-besetzt { display: flex; flex-direction: column; gap: 3px; min-width: 0; padding: 10px 12px; border-radius: 12px; background: var(--surface-sunk); border: 1px solid transparent; } -.plan-einst-besetzt b { font-size: 12px; font-weight: 650; color: var(--text-muted); } -.plan-einst-besetzt span { font-size: 12.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.plan-einst-besetzt { display: flex; flex-direction: column; gap: 4px; min-width: 0; padding: 12px 12px; border-radius: 12px; background: var(--surface-sunk); border: 1px solid transparent; } +.plan-einst-besetzt b { font-size: 12px; font-weight: 500; color: var(--text-muted); } +.plan-einst-besetzt span { font-size: 13px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .plan-einst-besetzt.ist-luecke { background: color-mix(in srgb, var(--amber) 10%, transparent); border: 1px dashed var(--amber); } .plan-einst-besetzt.ist-luecke b, .plan-einst-besetzt.ist-luecke span { color: var(--amber); } .plan-einst-suche { position: relative; display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; max-width: 640px; } .plan-einst-suche[hidden] { display: none; } .plan-einst-suche label { font-size: 12px; font-weight: 500; color: var(--text-muted); } -.plan-einst-suche input { height: 40px; box-sizing: border-box; font-size: 14px; } +.plan-einst-suche input { height: 40px; box-sizing: border-box; font-size: 13px; } .plan-einst-vorschlaege { position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 20; max-height: 320px; overflow: auto; padding: 6px; border-radius: 14px; background: var(--surface); border: 1px solid var(--line); box-shadow: 0 16px 40px rgba(15,40,60,.18); } html.glas .plan-einst-vorschlaege { background: var(--glas-dicht); } -.plan-einst-vorschlag-titel { font-size: 11.5px; font-weight: 650; color: var(--text-muted); padding: 8px 10px 4px; } -.plan-einst-vorschlag-leer { font-size: 13px; color: var(--text-muted); padding: 10px; } +.plan-einst-vorschlag-titel { font-size: 12px; font-weight: 500; color: var(--text-muted); padding: 8px 12px 4px; } +.plan-einst-vorschlag-leer { font-size: 13px; color: var(--text-muted); padding: 12px; } .plan-einst-vorschlag { - display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; min-height: 48px; padding: 4px 10px; + display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; min-height: 48px; padding: 4px 12px; border: 0; border-radius: 10px; background: transparent; color: var(--text); font: inherit; cursor: pointer; } .plan-einst-vorschlag:hover, .plan-einst-vorschlag:focus-visible { background: var(--surface-sunk); } .plan-einst-vorschlag > span:last-child { display: flex; flex-direction: column; min-width: 0; } -.plan-einst-vorschlag b { font-size: 13.5px; font-weight: 600; } +.plan-einst-vorschlag b { font-size: 13px; font-weight: 500; } .plan-einst-vorschlag > span:last-child > span { font-size: 12px; color: var(--text-muted); } .plan-einst-ava { width: 34px; height: 34px; flex: none; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; - font-size: 11px; font-weight: 700; background: var(--accent); color: #fff; + font-size: 11px; font-weight: 600; background: var(--accent); color: #fff; } -.plan-einst-gruppe { display: flex; align-items: center; gap: 10px; padding: 16px 0 6px; } +.plan-einst-gruppe { display: flex; align-items: center; gap: 8px; padding: 16px 0 6px; } .plan-einst-zeile { - display: grid; grid-template-columns: minmax(200px, 1fr) auto 36px; gap: 10px 14px; align-items: center; - padding: 9px 10px; margin: 0 -10px; border-radius: 12px; border-top: 1px solid var(--line-soft); + display: grid; grid-template-columns: minmax(200px, 1fr) auto 36px; gap: 8px 12px; align-items: center; + padding: 8px 12px; margin: 0 -10px; border-radius: 12px; border-top: 1px solid var(--line-soft); transition: background-color var(--dur-lg, .2s) var(--ease-out, ease); } .plan-einst-gruppe + .plan-einst-zeile { border-top-color: transparent; } .plan-einst-zeile.ist-neu { background: var(--accent-soft); } .plan-einst-person { display: flex; align-items: center; gap: 12px; min-width: 0; } -.plan-einst-person b { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.plan-einst-person b { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .plan-einst-kapseln { display: flex; flex-wrap: wrap; gap: 6px; } .plan-einst-kapsel { - min-height: 36px; padding: 0 14px; border-radius: 999px; box-sizing: border-box; white-space: nowrap; - border: 1px solid var(--line); background: transparent; color: var(--text-muted); font: inherit; font-size: 12.5px; cursor: pointer; + min-height: 36px; padding: 0 16px; border-radius: 6px; box-sizing: border-box; white-space: nowrap; + border: 1px solid var(--line); background: transparent; color: var(--text-muted); font: inherit; font-size: 13px; cursor: pointer; transition: transform var(--dur, .15s) var(--ease-out, ease), background-color var(--dur, .15s); } .plan-einst-kapsel:hover:not(:disabled) { border-color: var(--accent); color: var(--text); } .plan-einst-kapsel:active:not(:disabled) { transform: scale(var(--press, .97)); } -.plan-einst-kapsel.ist-haupt { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; } -.plan-einst-kapsel.ist-neben { border: 1.5px dashed var(--accent); background: var(--accent-soft); color: var(--text); font-weight: 600; } +.plan-einst-kapsel.ist-haupt { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 500; } +.plan-einst-kapsel.ist-neben { border: 1.5px dashed var(--accent); background: var(--accent-soft); color: var(--text); font-weight: 500; } .plan-einst-kapsel.ist-fremd { border-color: transparent; opacity: .5; text-decoration: line-through; } .plan-einst-kapsel:disabled { cursor: default; } -.plan-einst-weg { width: 36px; height: 36px; border-radius: 50%; border: 0; background: transparent; color: var(--text-muted); font-size: 18px; cursor: pointer; } +.plan-einst-weg { width: 36px; height: 36px; border-radius: 50%; border: 0; background: transparent; color: var(--text-muted); font-size: 19px; cursor: pointer; } .plan-einst-weg:hover { background: var(--surface-sunk); color: var(--red); } .plan-einst-leer { display: flex; flex-direction: column; gap: 6px; padding: 20px; border-radius: 14px; border: 1px dashed var(--line); margin-top: 8px; } -.plan-einst-leer b { font-size: 14px; font-weight: 600; } +.plan-einst-leer b { font-size: 13px; font-weight: 500; } .plan-einst-leer span { font-size: 13px; color: var(--text-muted); line-height: 1.5; } .plan-einst-toast { position: sticky; bottom: 16px; margin: 16px auto 0; width: max-content; max-width: 100%; - display: flex; align-items: center; gap: 14px; padding: 8px 8px 8px 16px; border-radius: 999px; + display: flex; align-items: center; gap: 12px; padding: 8px 8px 8px 16px; border-radius: 8px; background: var(--text); color: var(--bg); font-size: 13px; box-shadow: 0 16px 40px rgba(15,40,60,.25); } .plan-einst-toast[hidden] { display: none; } -.plan-einst-toast button { min-height: 32px; padding: 0 14px; border-radius: 999px; border: 0; background: color-mix(in srgb, var(--bg) 18%, transparent); color: inherit; font: inherit; font-weight: 600; cursor: pointer; } +.plan-einst-toast button { min-height: 32px; padding: 0 16px; border-radius: 8px; border: 0; background: color-mix(in srgb, var(--bg) 18%, transparent); color: inherit; font: inherit; font-weight: 500; cursor: pointer; } /* Dunkel ist der Akzent hell — Schrift darauf dunkel. */ @media (prefers-color-scheme: dark) { html:not([data-theme="light"]) .plan-einst-kapsel.ist-haupt, @@ -1448,7 +1446,7 @@ html[data-theme="dark"] .plan-einst-ava { color: #0b141b; } zuhalten. Jetzt: beauftragt = gefüllte Akzentkapsel und die ganze Zeile leicht getönt; nicht beauftragt = neutrale Kapsel, Zeile zurückgenommen; "läuft" gefüllt. */ -.plan-einst-phase { padding: 9px 10px; margin: 0 -10px; border-radius: 12px; } +.plan-einst-phase { padding: 8px 12px; margin: 0 -10px; border-radius: 12px; } .plan-einst-phase.ist-an { background: var(--accent-soft); border-top-color: transparent; } .plan-einst-phase.ist-an + .plan-einst-phase { border-top-color: transparent; } .plan-einst-phase .plan-einst-seg { background: var(--surface-sunk); border: 1px solid var(--line-soft); } @@ -1491,18 +1489,18 @@ html[data-theme="dark"] .modal-bg.als-panel { background: rgba(0,0,0,.32); } animation: pd-rein var(--dur-lg, .2s) var(--ease-out, ease); } @keyframes pd-rein { from { transform: translateX(32px); opacity: 0; } to { transform: none; opacity: 1; } } -.pd-kopf { padding: 18px 22px 14px; border-bottom: 1px solid var(--line-soft); display: flex; flex-direction: column; gap: 10px; } -.pd-art { display: flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 650; color: var(--text-muted); } +.pd-kopf { padding: 20px 24px 16px; border-bottom: 1px solid var(--line-soft); display: flex; flex-direction: column; gap: 8px; } +.pd-art { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 500; color: var(--text-muted); } .pd-art .modal-kbd { margin-left: auto; font-weight: 400; } -.pd-kasten { width: 11px; height: 11px; border-radius: 3px; background: var(--accent); } +.pd-kasten { width: 11px; height: 11px; border-radius: 4px; background: var(--accent); } .pd-raute { width: 10px; height: 10px; background: var(--meilenstein, #6d4bb3); transform: rotate(45deg); margin: 0 1px; } -.pd-zu { width: 34px; height: 34px; border-radius: 50%; border: 0; background: transparent; color: var(--text-muted); font-size: 20px; line-height: 1; padding: 0; cursor: pointer; } +.pd-zu { width: 34px; height: 34px; border-radius: 50%; border: 0; background: transparent; color: var(--text-muted); font-size: 19px; line-height: 1; padding: 0; cursor: pointer; } .pd-zu:hover { background: var(--surface-sunk); color: var(--text); } -.pd-kopf .pd-titel { width: 100%; box-sizing: border-box; font-size: 17px; font-weight: 600; padding: 9px 12px; } -.pd-inhalt { flex: 1; min-height: 0; overflow: auto; padding: 2px 22px 16px; } -.pd-abs { display: flex; flex-direction: column; gap: 8px; padding: 14px 0; border-bottom: 1px solid var(--line-soft); } +.pd-kopf .pd-titel { width: 100%; box-sizing: border-box; font-size: 19px; font-weight: 500; padding: 8px 12px; } +.pd-inhalt { flex: 1; min-height: 0; overflow: auto; padding: 2px 24px 16px; } +.pd-abs { display: flex; flex-direction: column; gap: 8px; padding: 16px 0; border-bottom: 1px solid var(--line-soft); } .pd-abs:last-child { border-bottom: 0; } -.pd-abs > h3 { margin: 0; font-size: 12px; font-weight: 650; color: var(--text-muted); } +.pd-abs > h3 { margin: 0; font-size: 12px; font-weight: 500; color: var(--text-muted); } .pd-abs .range-picker-display, .pd-abs select { width: 100%; box-sizing: border-box; } .pd-abs .field-inline { display: flex; align-items: center; gap: 8px; } .pd-abs .field-inline .range-picker-display { flex: 1; } @@ -1515,10 +1513,10 @@ html[data-theme="dark"] .modal-bg.als-panel { background: rgba(0,0,0,.32); } .pd-abs .fold { margin: 0; } .pd-fuss { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; - padding: 14px 22px calc(14px + env(safe-area-inset-bottom, 0px)); + padding: 16px 24px calc(16px + env(safe-area-inset-bottom, 0px)); border-top: 1px solid var(--line-soft); background: var(--surface-alt); } -.pd-loeschen { margin-right: auto; background: transparent; border: 0; color: var(--red); padding: 8px 10px; font-weight: 500; } +.pd-loeschen { margin-right: auto; background: transparent; border: 0; color: var(--red); padding: 8px 12px; font-weight: 500; } .pd-loeschen:hover { background: color-mix(in srgb, var(--red) 10%, transparent); } .pd-loeschen[hidden] { display: none; } /* Aufwand einer Aufgabe in Stunden (zählt zur Auslastung). */ @@ -1533,19 +1531,19 @@ html[data-theme="dark"] .modal-bg.als-panel { background: rgba(0,0,0,.32); } .pd-aufwand-zeile { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } .pd-stepper { display: inline-flex; align-items: center; height: 34px; border: 1px solid var(--line); - border-radius: var(--r-pill); background: var(--surface-sunk); overflow: hidden; + border-radius: 8px; background: var(--surface-sunk); overflow: hidden; transition: border-color var(--dur, 150ms), box-shadow var(--dur, 150ms); } .pd-stepper:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); } .pd-stepper .pd-stepper-knopf { all: unset; box-sizing: border-box; width: 32px; height: 100%; display: grid; place-items: center; - font-size: 16px; color: var(--text-muted); cursor: pointer; + font-size: 15px; color: var(--text-muted); cursor: pointer; } .pd-stepper .pd-stepper-knopf:hover { background: var(--seg-hover); color: var(--text); } .pd-stepper .pd-stepper-knopf:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; } .pd-stepper input { width: 52px; border: 0; background: transparent; padding: 0; text-align: right; - font: inherit; font-size: 15px; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; + font: inherit; font-size: 15px; font-weight: 500; color: var(--text); font-variant-numeric: tabular-nums; -moz-appearance: textfield; appearance: textfield; } .pd-stepper input::-webkit-outer-spin-button, .pd-stepper input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } @@ -1572,7 +1570,7 @@ html[data-theme="dark"] .modal-bg.als-panel { background: rgba(0,0,0,.32); } eine Leiste statt zwei, Menüs "Mehr" und "+ Neu", Gliederung nach Leistungsphasen mit zuklappbaren Köpfen, Filter, Hinweis "Ohne Termin". */ .tp-leiste { - gap: 10px; padding: 8px 10px; margin-bottom: 12px; border-radius: var(--r-lg); + gap: 8px; padding: 8px 12px; margin-bottom: 12px; border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft); } .tp-luecke { flex: 1; } @@ -1580,11 +1578,11 @@ html[data-theme="dark"] .modal-bg.als-panel { background: rgba(0,0,0,.32); } .tp-zeitraum { width: 200px; } .tp-menue { position: relative; } .tp-menue > summary { - list-style: none; cursor: pointer; display: inline-flex; align-items: center; min-height: 34px; padding: 0 14px; - border-radius: 999px; border: 1px solid var(--line); background: var(--surface); color: var(--text); font-size: 13px; user-select: none; + list-style: none; cursor: pointer; display: inline-flex; align-items: center; min-height: 34px; padding: 0 16px; + border-radius: 8px; border: 1px solid var(--line); background: var(--surface); color: var(--text); font-size: 13px; user-select: none; } .tp-menue > summary::-webkit-details-marker { display: none; } -.tp-neu > summary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; } +.tp-neu > summary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 500; } .tp-menue-liste { position: absolute; right: 0; top: calc(100% + 6px); z-index: 60; min-width: 250px; padding: 6px; border-radius: 14px; background: var(--surface); border: 1px solid var(--line-soft); box-shadow: 0 16px 40px rgba(15,40,60,.22); @@ -1593,13 +1591,13 @@ html[data-theme="dark"] .modal-bg.als-panel { background: rgba(0,0,0,.32); } html.glas .tp-menue-liste { background: var(--glas-dicht); } .tp-menue-liste.nach-rechts { right: auto; left: 0; } .tp-menue-liste button, .tp-menue-liste label { - display: flex; align-items: center; gap: 10px; width: 100%; min-height: 38px; padding: 0 10px; box-sizing: border-box; - border: 0; border-radius: 9px; background: transparent; color: var(--text); font: inherit; font-size: 13.5px; font-weight: 400; text-align: left; cursor: pointer; + display: flex; align-items: center; gap: 8px; width: 100%; min-height: 38px; padding: 0 12px; box-sizing: border-box; + border: 0; border-radius: 8px; background: transparent; color: var(--text); font: inherit; font-size: 13px; font-weight: 400; text-align: left; cursor: pointer; } .tp-menue-liste button:hover, .tp-menue-liste label:hover { background: var(--surface-sunk); } -.tp-menue-liste button.active { color: var(--accent); font-weight: 600; } +.tp-menue-liste button.active { color: var(--accent); font-weight: 500; } .tp-menue-liste hr { border: 0; border-top: 1px solid var(--line-soft); margin: 6px 4px; width: auto; } -.tp-sym-aufgabe { width: 10px; height: 10px; border-radius: 3px; background: var(--accent); flex: none; } +.tp-sym-aufgabe { width: 10px; height: 10px; border-radius: 4px; background: var(--accent); flex: none; } .tp-sym-ms { width: 9px; height: 9px; background: var(--meilenstein, #7a3fb8); transform: rotate(45deg); flex: none; margin: 0 1px; } @media (prefers-color-scheme: dark) { html:not([data-theme="light"]) .tp-neu > summary { color: #0b141b; } } html[data-theme="dark"] .tp-neu > summary { color: #0b141b; } @@ -1608,41 +1606,41 @@ html[data-theme="dark"] .tp-neu > summary { color: #0b141b; } #planGanttContainer .tp-projektzeile .gantt-label { font-weight: 500; color: var(--text-muted); font-size: 12px; } /* Phasenköpfe */ #planGanttContainer .gantt-row.gantt-phase { background: var(--surface-sunk); } -#planGanttContainer .gantt-row.gantt-phase .gantt-label { background: var(--surface-sunk); padding-left: 6px !important; font-weight: 650 !important; color: var(--text) !important; gap: 6px; } +#planGanttContainer .gantt-row.gantt-phase .gantt-label { background: var(--surface-sunk); padding-left: 6px !important; font-weight: 500 !important; color: var(--text) !important; gap: 6px; } #planGanttContainer .gantt-row.gantt-phase .gantt-bar.todo { top: 50%; height: 10px; margin-top: -5px; border-radius: 999px; } -.tp-klappen { width: 24px; height: 24px; flex: none; border: 0; border-radius: 6px; background: transparent; color: var(--text-muted); font-size: 10px; cursor: pointer; padding: 0; } +.tp-klappen { width: 24px; height: 24px; flex: none; border: 0; border-radius: 6px; background: transparent; color: var(--text-muted); font-size: 11px; cursor: pointer; padding: 0; } .tp-klappen:hover { background: var(--surface); color: var(--text); } -.tp-phase-info { margin-left: auto; font-size: 11.5px; font-weight: 400; color: var(--text-muted); white-space: nowrap; } -#planGanttContainer .gantt-row.tp-gruppe .gantt-label { font-weight: 650; color: var(--text-muted); font-size: 12px; background: var(--surface-sunk); } +.tp-phase-info { margin-left: auto; font-size: 12px; font-weight: 400; color: var(--text-muted); white-space: nowrap; } +#planGanttContainer .gantt-row.tp-gruppe .gantt-label { font-weight: 500; color: var(--text-muted); font-size: 12px; background: var(--surface-sunk); } #planGanttContainer .gantt-row.tp-gruppe { background: var(--surface-sunk); min-height: 30px; } /* Unter einem Phasenkopf eingerückt */ #planGanttContainer .gantt-row.gantt-todo:not(.gantt-phase) .gantt-label, -#planGanttContainer .gantt-row.gantt-milestone-row .gantt-label { padding-left: 30px !important; } +#planGanttContainer .gantt-row.gantt-milestone-row .gantt-label { padding-left: 32px !important; } #planGanttContainer .gantt-row.gantt-zu, #planGanttContainer .gantt-row.gantt-gefiltert { display: none; } #planGanttContainer .gantt-row.gantt-todo.done .gantt-todo-title { text-decoration: line-through; opacity: .7; } /* Kürzel der Zuständigen rechts in der Namensspalte */ .gantt-label .gantt-leute { margin-left: auto; display: inline-flex; flex: none; padding-left: 6px; } .gantt-label .gantt-leute span { - min-width: 20px; height: 20px; padding: 0 3px; box-sizing: border-box; border-radius: 999px; margin-left: -4px; - display: inline-flex; align-items: center; justify-content: center; font-size: 8.5px; font-weight: 700; + min-width: 20px; height: 20px; padding: 0 4px; box-sizing: border-box; border-radius: 999px; margin-left: -4px; + display: inline-flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 500; background: var(--surface-sunk); color: var(--text); border: 1.5px solid var(--surface); } .gantt-label .gantt-todo-title { overflow: hidden; text-overflow: ellipsis; min-width: 0; } .gantt-vorgaenger-warn { flex: none; width: 16px; height: 16px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; - font-size: 10px; font-weight: 800; background: color-mix(in srgb, var(--amber) 20%, transparent); color: var(--amber); + font-size: 11px; font-weight: 600; background: color-mix(in srgb, var(--amber) 20%, transparent); color: var(--amber); } /* Heute deutlicher */ #planGanttContainer .gantt-grid-today { border-left-width: 2px; opacity: 1; } /* Hinweis auf Aufgaben ohne Termin */ .tp-ohne { - display: flex; align-items: center; gap: 8px; width: 100%; margin-top: 8px; padding: 10px 14px; box-sizing: border-box; + display: flex; align-items: center; gap: 8px; width: 100%; margin-top: 8px; padding: 12px 16px; box-sizing: border-box; border: 1px dashed var(--line); border-radius: var(--r-md); background: transparent; color: var(--text-muted); font: inherit; font-size: 13px; text-align: left; cursor: pointer; } .tp-ohne:hover { border-color: var(--accent); color: var(--text); } .tp-ohne[hidden] { display: none; } -.tp-ohne-zahl { background: var(--surface-sunk); border-radius: 999px; padding: 1px 8px; font-weight: 600; color: var(--text); } +.tp-ohne-zahl { background: var(--surface-sunk); border-radius: 6px; padding: 1px 8px; font-weight: 500; color: var(--text); } .tp-ohne-hinweis { margin-left: auto; font-size: 12px; } #planGanttContainer .gantt-row.gantt-phase .gantt-todo-title { flex: 1 1 auto; min-width: 70px; } #planGanttContainer .gantt-row.gantt-phase .tp-phase-info { flex: none; } @@ -1671,17 +1669,17 @@ html.glas[data-theme="light"] #planSection-terminplan .tp-menue-liste { backgrou /* Aufgabenliste: Phasen-Kennzeichen je Aufgabe und Filter */ .plan-task-phase { - flex-shrink: 0; font-size: 11px; font-weight: 600; padding: 1px 8px; border-radius: 999px; + flex-shrink: 0; font-size: 11px; font-weight: 500; padding: 1px 8px; border-radius: 6px; background: var(--accent-soft); color: var(--accent); white-space: nowrap; } -.plan-task-filter { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: -2px 0 10px; font-size: 12px; color: var(--text-muted); } +.plan-task-filter { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: -2px 0 8px; font-size: 12px; color: var(--text-muted); } .plan-task-filter:empty { display: none; } .plan-task-filter > span { margin-right: 2px; } .plan-task-filter-btn { - min-height: 28px; padding: 0 12px; border-radius: 999px; font: inherit; font-size: 12px; + min-height: 28px; padding: 0 12px; border-radius: 8px; font: inherit; font-size: 12px; border: 1px solid var(--line); background: var(--surface); color: var(--text); cursor: pointer; } -.plan-task-filter-btn.is-active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; } +.plan-task-filter-btn.is-active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 500; } /* Leistungsphasen farblich von Aufgaben getrennt (Eriks Wunsch): Phasen- balken in Blauviolett (bewusst bläulicher als das Lila der Meilensteine), Aufgaben bleiben im Akzentblau, erledigte grün, @@ -1695,16 +1693,16 @@ html[data-theme="dark"] { --gantt-phase: #a59ef2; } /* Aufgaben-Vorlagen je Gewerk (Admin): Gewerk-Umschalter, Spaltenkopf und bearbeitbare Zeilen — gleiche Spalten wie die Zeile „+ Schritt". */ -.vorlagen-wahl { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin: 10px 0 12px; } -.vorlagen-gewerke { display: inline-flex; gap: 4px; padding: 3px; border-radius: 999px; background: var(--surface-sunk); } -.vorlagen-gewerk { border: 0; background: transparent; color: var(--text-muted); font: inherit; font-size: 13px; font-weight: 600; - padding: 6px 14px; border-radius: 999px; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; } +.vorlagen-wahl { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin: 8px 0 12px; } +.vorlagen-gewerke { display: inline-flex; gap: 4px; padding: 4px; border-radius: 8px; background: var(--surface-sunk); } +.vorlagen-gewerk { border: 0; background: transparent; color: var(--text-muted); font: inherit; font-size: 13px; font-weight: 500; + padding: 6px 16px; border-radius: 6px; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; } .vorlagen-gewerk span { font-size: 11px; font-weight: 500; opacity: .75; } .vorlagen-gewerk.is-active { background: var(--surface); color: var(--text); box-shadow: var(--sh-1); } .vorlagen-kopf, .vorlagen-zeile, .vorlagen-neu { display: grid !important; grid-template-columns: minmax(0, 1fr) 80px 90px 90px 120px; gap: 8px; align-items: center; } -.vorlagen-kopf { font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted); padding: 0 6px 4px; } +.vorlagen-kopf { font-size: 11px; letter-spacing: 0; color: var(--text-muted); padding: 0 6px 4px; } .vorlagen-zeile input { width: 100%; box-sizing: border-box; min-width: 0; } .vorlagen-neu input[type=text], .vorlagen-neu input[type=number] { width: 100%; min-width: 0; flex: none; box-sizing: border-box; } .vorlagen-aktionen { display: inline-flex; gap: 4px; justify-content: flex-end; align-items: center; } @@ -1716,7 +1714,7 @@ html[data-theme="dark"] { --gantt-phase: #a59ef2; } .template-head-grid { grid-template-columns: 1fr; } } -.vorlagen-summe { font-size: 12.5px; color: var(--text-muted); padding: 6px 6px 0; } +.vorlagen-summe { font-size: 13px; color: var(--text-muted); padding: 6px 6px 0; } .vorlagen-summe b { color: var(--text); font-variant-numeric: tabular-nums; } /* ---------- Termin aus Mail (js/plan/plan-mail-eintrag.js) ---------- */ @@ -1747,7 +1745,7 @@ html[data-theme="dark"] { --gantt-phase: #a59ef2; } font: inherit; font-size: .9em; line-height: 1.4; } .pd-mail-hinweis { - margin: 0 0 6px; padding: 6px 10px; border-radius: 8px; + margin: 0 0 6px; padding: 6px 12px; border-radius: 8px; background: color-mix(in srgb, var(--accent) 10%, transparent); color: var(--text); } .plan-task-notiz { display: inline-flex; color: var(--text-subtle); } @@ -1756,8 +1754,8 @@ html[data-theme="dark"] { --gantt-phase: #a59ef2; } .mail-auswahl { width: min(560px, calc(100vw - 32px)); } .mail-auswahl-liste { display: flex; flex-direction: column; gap: 4px; max-height: 50vh; overflow-y: auto; margin: 12px 0; } .mail-auswahl-zeile { - display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center; - padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; + display: grid; grid-template-columns: auto 1fr auto; gap: 8px; align-items: center; + padding: 8px 12px; border: 1px solid var(--line); border-radius: 8px; } .mail-auswahl-text { display: grid; gap: 2px; min-width: 0; } .mail-auswahl-titel { overflow-wrap: anywhere; } @@ -1773,7 +1771,7 @@ html[data-theme="dark"] { --gantt-phase: #a59ef2; } } .segmented.mail-auswahl-art button:hover { background: var(--seg-hover); color: var(--text); } .segmented.mail-auswahl-art button[aria-pressed="true"] { - background: var(--accent-soft); color: var(--accent); font-weight: 600; + background: var(--accent-soft); color: var(--accent); font-weight: 500; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent); } @media (max-width: 520px) { @@ -1783,8 +1781,8 @@ html[data-theme="dark"] { --gantt-phase: #a59ef2; } /* ---------- Aufgaben-Panel: „Externe Personen“ (Kollegen außerhalb des Projekts, todoExterneSetzen() in plan-modals.js) ---------- */ -.pd-externe { margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--line); display: grid; gap: 8px; } -.pd-externe-kopf { font-size: 12px; font-weight: 600; color: var(--text-muted); } +.pd-externe { margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--line); display: grid; gap: 8px; } +.pd-externe-kopf { font-size: 12px; font-weight: 500; color: var(--text-muted); } .pd-externe-kopf .hint { font-weight: 400; margin: 0 0 0 4px; } #todoEditExterne:empty { display: none; } #todoEditExterneWahl { max-width: 100%; } @@ -1799,58 +1797,62 @@ html[data-theme="dark"] { --gantt-phase: #a59ef2; } border: 1px solid var(--line); border-radius: var(--r-lg, 14px); background: var(--surface); overflow: hidden; } #planSection-notizen.notizen-zieht .notizen { outline: 2px dashed var(--accent); outline-offset: 4px; } -.notizen-liste { display: flex; flex-direction: column; gap: 8px; padding: 14px; background: var(--surface-alt); border-right: 1px solid var(--line-soft); min-width: 0; } +.notizen-liste { display: flex; flex-direction: column; gap: 8px; padding: 16px; background: var(--surface-alt); border-right: 1px solid var(--line-soft); min-width: 0; } .notizen-suchzeile { display: flex; gap: 8px; } .notizen-suche { - flex: 1; min-width: 0; padding: 7px 12px; border: 1px solid var(--line) !important; border-radius: 999px !important; - background: var(--surface) !important; color: var(--text); font: inherit; font-size: 12.5px; box-shadow: none !important; + flex: 1; min-width: 0; padding: 8px 12px; border: 1px solid var(--line) !important; border-radius: 8px; + background: var(--surface) !important; color: var(--text); font: inherit; font-size: 13px; box-shadow: none !important; } .notizen-suche:focus { outline: none; border-color: var(--accent) !important; } -button.notizen-neu { white-space: nowrap; padding: 6px 14px; font-size: 12.5px; } +button.notizen-neu { white-space: nowrap; padding: 6px 16px; font-size: 13px; } .notizen-eintraege { display: flex; flex-direction: column; gap: 2px; overflow-y: auto; max-height: 62vh; } -.notizen-gruppe { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 650; letter-spacing: .05em; text-transform: uppercase; color: var(--text-subtle); margin: 8px 4px 4px; } +.notizen-gruppe { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 500; letter-spacing: 0; color: var(--text-subtle); margin: 8px 4px 4px; } .notizen-pin-punkt { width: 7px; height: 7px; border-radius: 50%; background: var(--amber); } button.notizen-eintrag, button.notizen-eintrag:hover, button.notizen-eintrag:active { - all: unset; box-sizing: border-box; display: grid; gap: 2px; padding: 9px 11px; border-radius: 10px; cursor: pointer; width: 100%; + all: unset; box-sizing: border-box; display: grid; gap: 2px; padding: 8px 12px; border-radius: 10px; cursor: pointer; width: 100%; transition: background var(--dur, 150ms); } button.notizen-eintrag:hover { background: var(--surface-sunk); } button.notizen-eintrag:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; } button.notizen-eintrag.ist-aktiv { background: var(--surface); box-shadow: inset 3px 0 0 var(--accent), var(--sh-1, 0 1px 2px rgba(0,0,0,.06)); } -.notizen-eintrag-titel { font-weight: 600; font-size: 13px; color: var(--text); display: flex; gap: 6px; align-items: center; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.notizen-eintrag-titel { font-weight: 500; font-size: 13px; color: var(--text); display: flex; gap: 6px; align-items: center; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .notizen-eintrag-text { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .notizen-eintrag-meta { font-size: 11px; color: var(--text-subtle); } -.notizen-chip { flex: none; font-size: 10.5px; font-weight: 600; color: var(--accent); background: var(--accent-soft); border-radius: 999px; padding: 0 7px; } -.notizen-leer { font-size: 12.5px; color: var(--text-subtle); padding: 10px 4px; } +.notizen-chip { flex: none; font-size: 11px; font-weight: 500; color: var(--accent); background: var(--accent-soft); border-radius: 8px; padding: 0 8px; } +.notizen-leer { font-size: 13px; color: var(--text-subtle); padding: 12px 4px; } .notizen-leer.ist-fehler { color: var(--red); } -.notizen-ablage { margin-top: auto; border: 1.5px dashed var(--line); border-radius: 10px; padding: 9px; text-align: center; font-size: 12px; color: var(--text-subtle); } +.notizen-ablage { margin-top: auto; border: 1.5px dashed var(--line); border-radius: 10px; padding: 8px; text-align: center; font-size: 12px; color: var(--text-subtle); } .notizen-laedt { padding: 24px; color: var(--text-subtle); } -.notizen-editor { display: flex; flex-direction: column; gap: 12px; padding: 18px 22px; min-width: 0; } +.notizen-editor { display: flex; flex-direction: column; gap: 12px; padding: 20px 24px; min-width: 0; } .notizen-editor-leer { margin: auto; display: grid; gap: 6px; text-align: center; color: var(--text-muted); max-width: 320px; } .notizen-editor-kopf { display: flex; align-items: center; gap: 8px; } .notizen-titel { - flex: 1; min-width: 0; border: 0 !important; background: transparent !important; box-shadow: none !important; padding: 2px 0 !important; + /* 4 px Innenabstand, sonst saß der Cursor auf der Feldkante und war halb + verdeckt; der negative Rand hält den Titel auf seiner Linie. */ + flex: 1; min-width: 0; border: 0 !important; background: transparent !important; box-shadow: none !important; padding: 2px 4px !important; margin-left: -4px; font: 600 20px/1.3 var(--font-display, inherit); color: var(--text); } .notizen-titel:focus { outline: none; } .notizen-titel::placeholder { color: var(--text-subtle); } button.notizen-symbol, button.notizen-symbol:hover, button.notizen-symbol:active { - all: unset; box-sizing: border-box; padding: 5px 11px; border-radius: 999px; border: 1px solid var(--line); + all: unset; box-sizing: border-box; padding: 4px 12px; border-radius: 8px; border: 1px solid var(--line); font-size: 12px; color: var(--text-muted); cursor: pointer; white-space: nowrap; transition: background var(--dur, 150ms); } button.notizen-symbol:hover { background: var(--surface-sunk); color: var(--text); } button.notizen-symbol:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } -button.notizen-symbol.ist-an { color: var(--amber); border-color: color-mix(in srgb, var(--amber) 50%, var(--line)); font-weight: 600; } +button.notizen-symbol.ist-an { color: var(--amber); border-color: color-mix(in srgb, var(--amber) 50%, var(--line)); font-weight: 500; } button.notizen-symbol.ist-gefahr:hover { color: var(--red); } -button.notizen-symbol.ist-fragend { background: var(--red); color: #fff; border-color: var(--red); } +/* Auch beim Darüberfahren weiß auf Rot — sonst gewann .ist-gefahr:hover (rote Schrift) + und „Wirklich löschen?“ verschwand auf der roten Fläche. */ +button.notizen-symbol.ist-fragend, button.notizen-symbol.ist-fragend:hover { background: var(--red); color: #fff; border-color: var(--red); } .notizen-richtext { display: flex; flex-direction: column; gap: 8px; flex: 1; } .notizen-text { - flex: 1; min-height: 260px; outline: none; line-height: 1.55; font-size: 14px; color: var(--text); + flex: 1; min-height: 260px; outline: none; line-height: 1.55; font-size: 13px; color: var(--text); padding: 4px 2px; overflow-wrap: anywhere; } .notizen-text:empty::before { content: attr(data-placeholder); color: var(--text-subtle); } -.notizen-fuss { display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; border-top: 1px solid var(--line-soft); padding-top: 10px; font-size: 12px; color: var(--text-subtle); } +.notizen-fuss { display: flex; justify-content: space-between; gap: 8px; flex-wrap: wrap; border-top: 1px solid var(--line-soft); padding-top: 12px; font-size: 12px; color: var(--text-subtle); } .notizen-status.ist-ok { color: var(--green); } .notizen-status.ist-warnung { color: var(--amber); } .notizen-status.ist-fehler { color: var(--red); } @@ -1860,3 +1862,13 @@ button.notizen-link, button.notizen-link:hover { all: unset; cursor: pointer; co .notizen-liste { border-right: 0; border-bottom: 1px solid var(--line-soft); } .notizen-eintraege { max-height: 240px; } } + +/* ---------- Reiter des Projektkopfs wie die Seitenleiste (11/2026) ---------- + Eriks Meldung: das Highlight sah anders aus als im übrigen Programm. Wie + .sidebar-nav .nav-item: inaktiv normal und gedämpft, aktiv eine Flächen- + stufe mit Haarlinie und dunkler Schrift (kein Akzentblau, keine + Unterstreichung). Unter Glas: glas.css (.plan-kopf .plan-nav-item). */ +.plan-nav { padding: 8px 24px; gap: 2px; align-items: center; } +.plan-nav-item { height: 32px; padding: 0 12px; border-bottom: 0; border-radius: 8px; font-weight: 400; display: inline-flex; align-items: center; } +.plan-nav-item:hover { background: var(--surface-sunk); color: var(--text); } +.plan-nav-item.is-active { background: var(--surface-sunk); color: var(--text); font-weight: 500; border-bottom-color: transparent; box-shadow: inset 0 0 0 1px var(--line-soft); } diff --git a/public/styles.css b/public/styles.css index 547c13d..d8be91d 100644 --- a/public/styles.css +++ b/public/styles.css @@ -1,27 +1,27 @@ /* === Design-Tokens === */ :root { - --accent: #0071e3; - --accent-hover: #0077ed; - --accent-active: #006ad1; - --accent-soft: #e8f1fd; + --accent: #0f5a85; + --accent-hover: #0d5079; + --accent-active: #0a4565; + --accent-soft: #e8f0f6; - --text: #1d1d1f; - --text-muted: #6e6e73; - --text-subtle: #86868b; + --text: #16191d; + --text-muted: #4d545c; + --text-subtle: #69707a; - --bg: #f5f5f7; + --bg: #f4f5f7; --surface: #ffffff; - --surface-alt: #fafafc; - --surface-sunk: #f0f0f2; + --surface-alt: #f9fafb; + --surface-sunk: #eef0f2; - --line: #d2d2d7; - --line-soft: #e8e8ed; + --line: #dcdfe3; + --line-soft: #e9ebee; - --green: #248a3d; - --amber: #b25000; - --red: #d70015; - --red-hover: #e8112d; - --red-active: #b8000f; + --green: #1f7a3a; + --amber: #a64d00; + --red: #c4161c; + --red-hover: #d42a30; + --red-active: #a51217; /* Flächen des Anwesenheits-Kacheln im Zustand "anwesend" — eigene Tokens, weil eine feste rgba-Grünfläche im Dark Mode nicht trägt. */ @@ -31,8 +31,8 @@ /* Kopfband der Wochenbericht-Karten je Änderungsart. Das Band trägt weiße Schrift, deshalb etwas dunkler als --green (#248a3d käme nur auf Kontrast 4,4 : 1 und bliebe damit unter den 4,5 : 1 für normalen Text). */ - --band-neu: #0071e3; - --band-fortschritt: #22823a; + --band-neu: #0f5a85; + --band-fortschritt: #1f7a3a; --meilenstein: #7a3fb8; /* Gelbe Markierung neu hinzugekommener Protokoll-Punkte — bewusst eigenes @@ -58,11 +58,11 @@ --r-md: 8px; --r-lg: 12px; --r-xl: 16px; - --r-pill: 980px; + --r-pill: 8px; - --sh-1: 0 1px 2px rgba(0,0,0,.04), 0 1px 3px rgba(0,0,0,.06); - --sh-2: 0 2px 8px rgba(0,0,0,.06), 0 1px 3px rgba(0,0,0,.04); - --sh-3: 0 8px 28px rgba(0,0,0,.12), 0 2px 8px rgba(0,0,0,.06); + --sh-1: 0 1px 2px rgba(16,24,32,.05); + --sh-2: 0 2px 8px rgba(16,24,32,.06), 0 1px 2px rgba(16,24,32,.04); + --sh-3: 0 8px 24px rgba(16,24,32,.10), 0 2px 6px rgba(16,24,32,.05); --ease: cubic-bezier(.4, 0, .2, 1); @@ -87,7 +87,7 @@ praktisch null gesetzt - dort genügt es, diese Variablen zu kippen. */ --dur: 150ms; --dur-lg: 200ms; - --ease-out: cubic-bezier(.2, .8, .2, 1); + --ease-out: cubic-bezier(.22, 1, .36, 1); --row-lift: -1px; --press: .97; } @@ -105,7 +105,8 @@ body { line-height: 1.45; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - letter-spacing: -0.005em; + letter-spacing: 0; + font-variant-numeric: tabular-nums; } .container { padding: 20px 24px; } @@ -139,9 +140,9 @@ body { row-gap: 8px; gap: 12px; padding: 8px 20px; - background: rgba(255,255,255,.82); - -webkit-backdrop-filter: saturate(180%) blur(20px); - backdrop-filter: saturate(180%) blur(20px); + background: rgba(255,255,255,.86); + -webkit-backdrop-filter: blur(16px); + backdrop-filter: blur(16px); border-bottom: 1px solid var(--line-soft); } @@ -152,9 +153,9 @@ body { .topbar-logo { height: 28px; width: auto; object-fit: contain; } .topbar-title { font-size: 15px; - font-weight: 600; + font-weight: 500; margin: 0; - letter-spacing: -0.01em; + letter-spacing: 0; white-space: nowrap; } @@ -189,7 +190,7 @@ body { .header-toggle { position: relative; z-index: 10; - padding: 6px 10px; + padding: 6px 12px; min-width: 36px; display: inline-flex; align-items: center; @@ -248,7 +249,7 @@ body { } .user-menu-info { - padding: 8px 10px 10px; + padding: 8px 12px 12px; margin-bottom: 2px; border-bottom: 1px solid var(--line-soft); font-size: 12px; @@ -266,7 +267,7 @@ button.menu-item { text-align: left; background: transparent; color: var(--text); - padding: 8px 10px; + padding: 8px 12px; border: none; border-radius: var(--r-md); font-size: 13px; @@ -469,30 +470,30 @@ html[data-theme="dark"] body.wandtafel-aktiv { /* ===== Kopf: Marke "Dashboard" + Sitzung/Uhrzeit + Abwesend-Mini ===== */ .dash-kopf { flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; } -.dash-marke { font-family: 'Outfit', -apple-system, system-ui, sans-serif; font-weight: 600; font-size: 19px; color: var(--dash-ink); } -.dash-kopf-rechts { display: flex; align-items: center; gap: 14px; } -.dash-datum { font-size: 12.5px; color: var(--dash-text-muted); background: var(--dash-panel-3); padding: 4px 12px; border-radius: var(--r-pill); } +.dash-marke { font-family: 'Outfit', -apple-system, system-ui, sans-serif; font-weight: 500; font-size: 19px; color: var(--dash-ink); } +.dash-kopf-rechts { display: flex; align-items: center; gap: 12px; } +.dash-datum { font-size: 13px; color: var(--dash-text-muted); background: var(--dash-panel-3); padding: 4px 12px; border-radius: 6px; } .dash-abwesend-mini { display: flex; } .dash-abwesend-mini.ist-klickbar { cursor: pointer; border-radius: var(--r-pill); } .dash-abwesend-mini.ist-klickbar:hover { filter: brightness(.96); } .dash-avatar-mini { width: 25px; height: 25px; border-radius: 50%; background: var(--dash-panel-2); color: var(--dash-ink); - font-size: 9.5px; font-weight: 800; display: flex; align-items: center; justify-content: center; + font-size: 11px; font-weight: 600; display: flex; align-items: center; justify-content: center; margin-left: -7px; border: 2px solid var(--dash-bg); } .dash-avatar-mini:first-child { margin-left: 0; } /* ===== Kennzahlen-Reihe (4 Kacheln) ===== */ -.dash-kpi-reihe { flex-shrink: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 18px; } -.dash-kpi { border-radius: var(--r-xl); padding: 16px 18px; } +.dash-kpi-reihe { flex-shrink: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 16px; } +.dash-kpi { border-radius: var(--r-xl); padding: 16px 20px; } .dash-kpi:nth-child(1) { background: var(--dash-panel-1); } .dash-kpi:nth-child(2) { background: var(--dash-panel-2); } .dash-kpi:nth-child(3) { background: var(--dash-panel-3); } .dash-kpi:nth-child(4) { background: var(--dash-kpi-4); } .dash-kpi.ist-klickbar { cursor: pointer; } .dash-kpi.ist-klickbar:hover { filter: brightness(.96); } -.dash-kpi-label { font-size: 11px; font-weight: 700; color: var(--dash-text-muted); margin-bottom: 8px; } -.dash-kpi-wert { font-family: 'Outfit', -apple-system, system-ui, sans-serif; font-weight: 600; font-size: 32px; color: var(--dash-ink); font-variant-numeric: tabular-nums; } +.dash-kpi-label { font-size: 11px; font-weight: 600; color: var(--dash-text-muted); margin-bottom: 8px; } +.dash-kpi-wert { font-family: 'Outfit', -apple-system, system-ui, sans-serif; font-weight: 500; font-size: 32px; color: var(--dash-ink); font-variant-numeric: tabular-nums; } .dash-kpi-wert.ok { color: var(--dash-ink); } .dash-kpi-wert.info { color: var(--dash-ink-soft); } .dash-kpi-wert.warn { color: var(--dash-warn); } @@ -503,12 +504,12 @@ html[data-theme="dark"] body.wandtafel-aktiv { der Inhalt verteilt sich gleichmäßig über die volle Höhe statt oben zu kleben, damit ein dünn befülltes Panel neben einem vollen nicht leer wirkt. */ -.dash-grid { flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr 1fr 1.3fr; gap: 14px; } -.dash-panel { border-radius: var(--r-xl); padding: 18px 20px; display: flex; flex-direction: column; min-height: 0; } +.dash-grid { flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr 1fr 1.3fr; gap: 12px; } +.dash-panel { border-radius: var(--r-xl); padding: 20px 20px; display: flex; flex-direction: column; min-height: 0; } .dash-grid > .dash-panel:nth-child(1) { background: var(--dash-panel-1); } .dash-grid > .dash-panel:nth-child(2) { background: var(--dash-panel-2); } .dash-grid > .dash-panel:nth-child(3) { background: var(--dash-panel-3); } -.dash-panel-titel { flex-shrink: 0; font-size: 12px; font-weight: 700; color: var(--dash-ink); margin-bottom: 12px; } +.dash-panel-titel { flex-shrink: 0; font-size: 12px; font-weight: 600; color: var(--dash-ink); margin-bottom: 12px; } .dash-panel-body { flex: 1; min-height: 0; display: flex; flex-direction: column; justify-content: space-evenly; overflow: hidden; } /* Meter-Zeilen: Auslastung je Gewerk, Wochenbericht-Fortschritt je Gewerk — @@ -535,7 +536,7 @@ html[data-theme="dark"] body.wandtafel-aktiv { (Neu/Überfällig/Termin). Jeder Eintrag einzeln antippbar, springt direkt ins betroffene Projekt. */ .dash-feed-eintrag { - display: flex; align-items: flex-start; gap: 10px; padding: 9px 2px; border-top: 1px solid var(--dash-line); + display: flex; align-items: flex-start; gap: 8px; padding: 8px 2px; border-top: 1px solid var(--dash-line); cursor: pointer; border-radius: var(--r-md); transition: background .15s var(--ease); } .dash-feed-eintrag:first-of-type { border-top: none; padding-top: 0; } @@ -544,8 +545,8 @@ html[data-theme="dark"] body.wandtafel-aktiv { .dash-feed-punkt.neu { background: var(--dash-ink); } .dash-feed-punkt.ueberfaellig { background: var(--dash-crit); } .dash-feed-punkt.termin { background: var(--dash-warn); } -.dash-feed-text { flex: 1; font-size: 12.5px; line-height: 1.5; color: var(--dash-text); } -.dash-feed-zeit { display: block; font-size: 10.5px; color: var(--dash-text-subtle); margin-top: 2px; } +.dash-feed-text { flex: 1; font-size: 13px; line-height: 1.5; color: var(--dash-text); } +.dash-feed-zeit { display: block; font-size: 11px; color: var(--dash-text-subtle); margin-top: 2px; } /* Vollbild-Übersichten (überfällige/offene Aufgaben, Auslastung/Besprochen je Gewerk, Abwesenheiten) — ersetzen die Normalansicht vorübergehend @@ -693,7 +694,7 @@ button.active { box-shadow: none; color: var(--text); cursor: pointer; - font-size: 18px; + font-size: 19px; transition: background .2s var(--ease); } @@ -712,7 +713,7 @@ button.active { text-decoration: none; background: transparent; color: var(--text-muted); - padding: 9px 12px; + padding: 8px 12px; cursor: pointer; border: none; border-radius: var(--r-md); @@ -746,17 +747,16 @@ button.active { .nav-item.active { background: var(--accent-soft); color: var(--accent); - font-weight: 600; + font-weight: 500; } /* .sidebar-section-label: kleine Rubrik-Überschrift oberhalb einer Gruppe von Sidebar-Einträgen (z. B. "Dashboard", "Navigation"). */ .sidebar-section-label { - padding: 10px 12px 2px; + padding: 12px 12px 2px; font-size: 11px; - font-weight: 700; - letter-spacing: .04em; - text-transform: uppercase; + font-weight: 600; + letter-spacing: 0; color: var(--text-muted); } @@ -798,8 +798,8 @@ button.active { .sidebar-subitem { width: 100%; - padding-left: 34px; - font-size: 12.5px; + padding-left: 36px; + font-size: 13px; color: var(--text-muted); } .sidebar-subitem:hover { color: var(--text); } @@ -808,7 +808,7 @@ button.active { lösen Aktionen aus und kennen deshalb keinen dauerhaft aktiven Punkt. */ .sidebar-subitem.is-active { color: var(--accent); - font-weight: 600; + font-weight: 500; background: var(--accent-soft); } .sidebar-subitem.danger { color: var(--red); } @@ -818,14 +818,14 @@ button.active { button { cursor: pointer; border: none; - border-radius: var(--r-pill); - padding: 7px 16px; + border-radius: 8px; + padding: 8px 16px; font-size: 13px; font-weight: 500; font-family: inherit; background: var(--accent); color: #fff; - letter-spacing: -0.01em; + letter-spacing: 0; transition: background .2s var(--ease), transform .1s var(--ease), box-shadow .2s var(--ease); } @@ -835,7 +835,7 @@ button:active { background: var(--accent-active); transform: scale(.97); } button:focus-visible { outline: none; - box-shadow: 0 0 0 3px rgba(0,113,227,.35); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); } button.secondary { @@ -850,7 +850,7 @@ button.danger:hover { background: var(--red-hover); } button.danger:active { background: var(--red-active); } button.small { - padding: 3px 10px; + padding: 4px 12px; font-size: 11px; } @@ -858,7 +858,7 @@ select, input[type=text], input[type=email], input[type=date] { - padding: 7px 10px; + padding: 8px 12px; border: 1px solid var(--line); border-radius: var(--r-md); font-size: 13px; @@ -874,7 +874,7 @@ input[type=email]:focus, input[type=date]:focus { outline: none; border-color: var(--accent); - box-shadow: 0 0 0 3px rgba(0,113,227,.18); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); } select { @@ -898,7 +898,7 @@ select { .role-checkboxes label { display: flex; align-items: center; - gap: 5px; + gap: 4px; font-size: 12px; color: var(--text-muted); } @@ -917,7 +917,7 @@ table { th, td { border: 1px solid var(--line-soft); - padding: 5px 7px; + padding: 4px 8px; text-align: center; vertical-align: middle; } @@ -925,7 +925,7 @@ td { thead tr:nth-child(1) th { background: var(--surface-sunk); color: var(--text); - font-weight: 600; + font-weight: 500; border: 1px solid var(--line); position: sticky; top: 0; @@ -946,7 +946,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } min-height: 34px; border: 1px solid var(--line-soft); border-radius: var(--r-sm); - padding: 5px 7px; + padding: 4px 8px; font-size: 11px; font-family: inherit; line-height: 1.4; @@ -961,7 +961,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .status-edit:focus { outline: none; border-color: var(--accent); - box-shadow: 0 0 0 3px rgba(0,113,227,.18); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); } .status-edit.status-new { color: var(--green); } @@ -969,7 +969,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .status-edit p { margin: 0 0 4px; } .status-edit p:last-child { margin-bottom: 0; } .status-edit b, -.status-edit strong { font-weight: 600; } +.status-edit strong { font-weight: 500; } /* === Kommentar-Editor im Board und im Wochenbericht ====================== Ersetzt das frühere contenteditable-Feld samt execCommand-Leiste: Textfeld @@ -977,7 +977,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } scrollbaren Verlauf der früheren Sitzungen. Aufgebaut von renderCommentEditor() in js/board/board.js. */ -.comment-block { display: flex; flex-direction: column; gap: 10px; } +.comment-block { display: flex; flex-direction: column; gap: 8px; } .comment-editor { border: 1px solid var(--line); @@ -991,7 +991,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } align-items: center; gap: 8px; flex-wrap: wrap; - padding: 6px 10px; + padding: 6px 12px; font-size: 11px; color: var(--text-muted); background: var(--surface-alt); @@ -999,15 +999,15 @@ tr:nth-child(even) td { background: var(--surface-alt); } } .comment-head-line { border: 1px solid var(--line-soft); border-radius: var(--r-md); } .comment-who { display: flex; align-items: center; gap: 6px; color: var(--text); font-weight: 500; } -.comment-unknown { color: var(--text-subtle); font-weight: 400; font-style: italic; } +.comment-unknown { color: var(--text-subtle); font-weight: 400; font-style: normal; } .comment-sep { color: var(--text-subtle); } .comment-av { width: 19px; height: 19px; border-radius: 50%; background: var(--accent); color: #fff; display: flex; align-items: center; justify-content: center; - font-size: 9px; font-weight: 600; flex-shrink: 0; + font-size: 11px; font-weight: 500; flex-shrink: 0; } -.comment-kbd { margin-left: auto; font-size: 10px; color: var(--text-subtle); white-space: nowrap; } +.comment-kbd { margin-left: auto; font-size: 11px; color: var(--text-subtle); white-space: nowrap; } /* .comment-field ist seit der Umstellung auf contenteditable (Eriks Wunsch nach echter statt mit Sternchen markierter Fett-/Kursiv-/Farbschrift, @@ -1018,7 +1018,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .comment-editor .comment-field { width: 100%; display: block; - padding: 8px 10px; + padding: 8px 12px; font-family: inherit; font-size: 12px; line-height: 1.5; @@ -1044,19 +1044,19 @@ tr:nth-child(even) td { background: var(--surface-alt); } Zusammenhängen funktionieren, ohne selbst Ecken abzurunden (mal steht sie ganz oben in ihrer Karte, mal nicht). */ .richtext-toolbar { - display: flex; align-items: center; gap: 8px; padding: 5px 8px; + display: flex; align-items: center; gap: 8px; padding: 4px 8px; background: var(--surface-sunk); border-bottom: 1px solid var(--line-soft); } .richtext-btn-group { display: inline-flex; gap: 2px; } .richtext-btn { appearance: none; border: none; background: none; color: var(--text-muted); - width: 22px; height: 20px; border-radius: 4px; font-size: 11px; font-weight: 700; cursor: pointer; line-height: 1; + width: 22px; height: 20px; border-radius: 4px; font-size: 11px; font-weight: 600; cursor: pointer; line-height: 1; } .richtext-btn:hover { background: var(--surface-alt); color: var(--text); } /* "Standard": setzt die Formatierung zurück — Text statt Symbol, ein Radiergummi-Zeichen wäre missverständlich. Bleibt auch ohne Markierung voll sichtbar, weil er dann den ganzen Text zurücksetzt. */ -.richtext-btn.richtext-btn-loeschen { width: auto; padding: 0 6px; font-weight: 600; } +.richtext-btn.richtext-btn-loeschen { width: auto; padding: 0 6px; font-weight: 500; } .richtext-toolbar:not(.hat-auswahl) .richtext-btn.richtext-btn-loeschen { opacity: 1; } .richtext-divider { width: 1px; height: 14px; background: var(--line); flex-shrink: 0; } .richtext-farben { display: inline-flex; gap: 6px; } @@ -1070,28 +1070,28 @@ tr:nth-child(even) td { background: var(--surface-alt); } Solange nichts markiert ist, bleiben die Knöpfe blass und der Hinweis fordert zum Markieren auf; .hat-auswahl (von einem selectionchange- Lauscher gesetzt, siehe js/plan/plan-protokoll.js) dreht beides um. */ -.richtext-hinweis { margin-left: auto; font-size: 10px; color: var(--text-subtle); white-space: nowrap; } +.richtext-hinweis { margin-left: auto; font-size: 11px; color: var(--text-subtle); white-space: nowrap; } .richtext-toolbar:not(.hat-auswahl) .richtext-btn, .richtext-toolbar:not(.hat-auswahl) .richtext-farbe-btn { opacity: .45; } .richtext-toolbar.hat-auswahl { background: var(--accent-soft); } -.richtext-toolbar.hat-auswahl .richtext-hinweis { color: var(--accent); font-weight: 600; } +.richtext-toolbar.hat-auswahl .richtext-hinweis { color: var(--accent); font-weight: 500; } .comment-editor-foot { display: flex; align-items: center; - gap: 7px; - padding: 7px 10px; + gap: 8px; + padding: 8px 12px; border-top: 1px solid var(--line-soft); background: var(--surface-alt); } .comment-foot-spacer { margin-left: auto; } -.comment-dirty { font-size: 10.5px; color: var(--amber); white-space: nowrap; } +.comment-dirty { font-size: 11px; color: var(--amber); white-space: nowrap; } .comment-readonly { border: 1px solid var(--line-soft); border-radius: var(--r-md); - padding: 7px 9px; - font-size: 11.5px; + padding: 8px 8px; + font-size: 12px; line-height: 1.45; background: var(--surface); } @@ -1109,8 +1109,8 @@ tr:nth-child(even) td { background: var(--surface-alt); } display: flex; align-items: center; gap: 8px; - padding: 7px 10px; - font-size: 11.5px; + padding: 8px 12px; + font-size: 12px; color: var(--text); user-select: none; } @@ -1118,22 +1118,22 @@ tr:nth-child(even) td { background: var(--surface-alt); } .comment-history > summary:hover { background: var(--surface-alt); } .comment-history-caret { color: var(--text-subtle); - font-size: 9px; + font-size: 11px; transition: transform .18s var(--ease); } .comment-history[open] > summary .comment-history-caret { transform: rotate(90deg); } .comment-history-count { margin-left: auto; - font-size: 10.5px; - font-weight: 600; + font-size: 11px; + font-weight: 500; background: var(--accent-soft); color: var(--accent); - border-radius: var(--r-pill); + border-radius: 6px; padding: 1px 8px; font-variant-numeric: tabular-nums; } .comment-history-count.zero { background: var(--surface-sunk); color: var(--text-subtle); } -.comment-history-body { border-top: 1px solid var(--line-soft); padding: 4px 10px 8px; } +.comment-history-body { border-top: 1px solid var(--line-soft); padding: 4px 12px 8px; } .comment-history-list { max-height: 220px; @@ -1146,25 +1146,25 @@ tr:nth-child(even) td { background: var(--surface-alt); } display: flex; align-items: center; gap: 8px; - margin-bottom: 3px; - font-size: 10.5px; + margin-bottom: 4px; + font-size: 11px; } .comment-history-week { - font-weight: 600; + font-weight: 500; color: var(--text); white-space: nowrap; font-variant-numeric: tabular-nums; } .comment-history-meta { color: var(--text-subtle); } -.comment-history-text { font-size: 11.5px; line-height: 1.45; color: var(--text-muted); } +.comment-history-text { font-size: 12px; line-height: 1.45; color: var(--text-muted); } .comment-history-text b, -.comment-history-text strong { font-weight: 600; color: var(--text); } +.comment-history-text strong { font-weight: 500; color: var(--text); } .comment-take { margin-left: auto; - padding: 2px 9px; - font-size: 10px; - border-radius: var(--r-pill); + padding: 2px 8px; + font-size: 11px; + border-radius: 8px; background: transparent; color: var(--text-muted); border: 1px solid var(--line); @@ -1183,7 +1183,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } backdrop-filter: saturate(180%) blur(16px); border: 1px solid var(--line-soft); border-radius: var(--r-md); - padding: 3px; + padding: 4px; gap: 2px; box-shadow: var(--sh-2); z-index: 10; @@ -1192,7 +1192,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .status:focus-within .status-toolbar { display: flex; } .status-toolbar button { - padding: 3px 7px; + padding: 4px 8px; font-size: 11px; line-height: 1.2; min-width: 24px; @@ -1210,7 +1210,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .status-toolbar button.color-blue { color: var(--accent); } .status-toolbar button.color-black { color: var(--text); - font-weight: 600; + font-weight: 500; } .locked-cell { @@ -1263,7 +1263,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .board-row-main { display: flex; align-items: center; - gap: 14px; + gap: 12px; padding: 12px 16px; cursor: pointer; transition: background .15s var(--ease); @@ -1281,21 +1281,21 @@ tr:nth-child(even) td { background: var(--surface-alt); } .board-nr { flex-shrink: 0; width: 64px; - font-size: 11.5px; + font-size: 12px; color: var(--text-muted); font-family: ui-monospace, 'SF Mono', monospace; } .board-name-wrap { flex: 1 1 260px; min-width: 0; } .board-name { - font-weight: 600; - letter-spacing: -0.01em; + font-weight: 500; + letter-spacing: 0; cursor: pointer; } .board-name:hover { color: var(--accent); text-decoration: underline; } .board-status-line { - margin-top: 3px; + margin-top: 4px; font-size: 12px; color: var(--text-muted); display: flex; @@ -1330,9 +1330,9 @@ tr:nth-child(even) td { background: var(--surface-alt); } display: inline-flex; align-items: center; justify-content: center; - font-size: 10px; - font-weight: 700; - letter-spacing: -0.02em; + font-size: 11px; + font-weight: 600; + letter-spacing: 0; color: var(--text-muted); background: var(--surface-sunk); border: 1px solid var(--line-soft); @@ -1352,10 +1352,10 @@ tr:nth-child(even) td { background: var(--surface-alt); } .phase-pill { flex-shrink: 0; font-size: 11px; - font-weight: 600; + font-weight: 500; font-family: ui-monospace, 'SF Mono', monospace; - padding: 4px 10px; - border-radius: var(--r-pill); + padding: 4px 12px; + border-radius: 6px; background: var(--accent-soft); color: var(--accent); white-space: nowrap; @@ -1364,7 +1364,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } /* --- Detailpanel (.board-drawer) --- */ .board-drawer { - padding: 18px 24px 22px; + padding: 20px 24px 24px; background: var(--surface-alt); border-top: 1px solid var(--line-soft); } @@ -1372,9 +1372,8 @@ tr:nth-child(even) td { background: var(--surface-alt); } .board-drawer h4 { margin: 0 0 8px; font-size: 11px; - font-weight: 700; - text-transform: uppercase; - letter-spacing: .05em; + font-weight: 600; + letter-spacing: 0; color: var(--text-muted); } @@ -1391,7 +1390,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } grid-template-columns: 1fr; grid-template-areas: "kommentar" "lph" "beteiligte"; align-content: start; - gap: 18px; + gap: 16px; } .drawer-col-comment { grid-area: kommentar; } .drawer-col-lph { grid-area: lph; } @@ -1404,7 +1403,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .beauftragte-lp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); - gap: 4px 10px; + gap: 4px 8px; } .beauftragte-lp-item { display: flex; @@ -1422,7 +1421,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .report-list { display: flex; flex-direction: column; - gap: 10px; + gap: 8px; } .report-card { background: var(--surface); @@ -1439,9 +1438,9 @@ tr:nth-child(even) td { background: var(--surface-alt); } .report-card-head { display: flex; align-items: center; - gap: 10px; + gap: 8px; flex-wrap: wrap; - padding: 9px 14px; + padding: 8px 16px; background: var(--surface-alt); border-bottom: 1px solid var(--line-soft); } @@ -1455,7 +1454,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } color: #fff; } .report-band .board-nr { color: rgba(255,255,255,.75); } -.report-band .board-name { color: #fff; font-weight: 600; } +.report-band .board-name { color: #fff; font-weight: 500; } .report-band .board-name:hover { text-decoration: underline; } .report-band .tag-chip { background: rgba(255,255,255,.22); @@ -1471,14 +1470,14 @@ tr:nth-child(even) td { background: var(--surface-alt); } nebeneinander, wodurch die Karte flacher wird. Dasselbe Markup wie im Projektboard, nur anders angeordnet. */ .report-card .board-drawer { - padding: 14px 16px 16px; + padding: 16px 16px 16px; border-top: none; background: var(--surface); } .report-card .board-drawer-grid { grid-template-columns: 1.7fr 1fr 1fr; grid-template-areas: "kommentar lph beteiligte"; - gap: 22px; + gap: 20px; } .report-card .board-role-label { width: 58px; } @@ -1506,26 +1505,26 @@ tr:nth-child(even) td { background: var(--surface-alt); } (.bericht-disclosure, weiter unten) — sie ist eine Sitzungs-, keine Projekt-Angabe und sitzt ohnehin außerhalb dieser Karte am Seitenfuß. */ .board-drawer-dicht { padding: 0; background: transparent; border-top: none; } -.bericht-meta-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line-soft); } +.bericht-meta-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--line-soft); } @media (max-width: 860px) { .bericht-meta-grid { grid-template-columns: 1fr; gap: 16px; } } -.bericht-meta-label { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-subtle); margin-bottom: 8px; } +.bericht-meta-label { font-size: 11px; font-weight: 600; letter-spacing: 0; color: var(--text-subtle); margin-bottom: 8px; } .bericht-disclosure { border: 1px solid var(--line-soft); border-radius: var(--r-md); - margin-top: 10px; + margin-top: 8px; overflow: hidden; background: var(--surface); } .bericht-disclosure summary { list-style: none; cursor: pointer; - padding: 10px 14px; + padding: 12px 16px; display: flex; align-items: center; gap: 8px; font-size: 12px; - font-weight: 650; + font-weight: 500; color: var(--text-muted); } .bericht-disclosure summary::-webkit-details-marker { display: none; } @@ -1544,21 +1543,21 @@ tr:nth-child(even) td { background: var(--surface-alt); } } .bericht-disclosure[open] summary .chev { transform: rotate(90deg); } .bericht-disclosure[open] summary { border-bottom: 1px solid var(--line-soft); } -.bericht-disclosure-body { padding: 10px 14px 12px; } +.bericht-disclosure-body { padding: 12px 16px 12px; } /* Der Kommentar bleibt das größte Element der dichten Fassung — etwas größere Schrift als im Projektboard, wo er eine Spalte unter mehreren teilt. Radius/Schatten wie eine freistehende Karte (Entwurf "Fokus-Modus"). */ .board-drawer-dicht .comment-editor .comment-field, -.board-drawer-dicht .comment-readonly { font-size: 14px; line-height: 1.6; min-height: 76px; } +.board-drawer-dicht .comment-readonly { font-size: 13px; line-height: 1.6; min-height: 76px; } /* .comment-editor hat bereits overflow:hidden (Basis-Regel) — ein größerer Radius hier genügt, Kopf/Fuß werden automatisch mitgerundet. */ .board-drawer-dicht .comment-editor { border-radius: var(--r-lg); box-shadow: var(--sh-1); } .board-lph-leiste { display: flex; - gap: 3px; + gap: 4px; align-items: stretch; } .board-lph-cell { @@ -1568,7 +1567,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } flex-direction: column; align-items: center; gap: 1px; - padding: 3px 2px 4px; + padding: 4px 2px 4px; border: 1px solid var(--line-soft); border-radius: var(--r-sm); background: var(--surface-sunk); @@ -1578,8 +1577,8 @@ tr:nth-child(even) td { background: var(--surface-alt); } background-repeat: no-repeat; } .board-lph-cell-label { - font-size: 10px; - font-weight: 600; + font-size: 11px; + font-weight: 500; color: var(--text-muted); line-height: 1.2; } @@ -1590,7 +1589,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } border: none; background: transparent; text-align: center; - font-size: 11.5px; + font-size: 12px; font-variant-numeric: tabular-nums; color: var(--text); font-family: inherit; @@ -1598,7 +1597,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .board-lph-cell input:focus { outline: 1.5px solid var(--accent); outline-offset: -1px; - border-radius: 3px; + border-radius: 4px; } .board-lph-cell.lp-aktiv { border-color: var(--accent); @@ -1622,7 +1621,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .board-drawer-dicht .board-role-mini .board-role-row { display: flex; align-items: flex-start; - gap: 7px; + gap: 8px; margin-bottom: 4px; } .board-drawer-dicht .board-role-mini .board-role-label { @@ -1631,10 +1630,9 @@ tr:nth-child(even) td { background: var(--surface-alt); } Versalien diese Breite — bei 88 px fehlte der letzte Buchstabe. */ width: 104px; padding-top: 4px; - font-size: 10px; + font-size: 11px; line-height: 1.25; - letter-spacing: .02em; - text-transform: uppercase; + letter-spacing: 0; } /* Schmale Fenster: Dort reicht die Breite für Label UND Kürzel nicht mehr, @@ -1652,9 +1650,9 @@ tr:nth-child(even) td { background: var(--surface-alt); } .report-reason-badge { margin-left: auto; font-size: 11px; - font-weight: 600; - padding: 3px 10px; - border-radius: var(--r-pill); + font-weight: 500; + padding: 4px 12px; + border-radius: 6px; background: var(--accent-soft); color: var(--accent); white-space: nowrap; @@ -1676,15 +1674,15 @@ tr:nth-child(even) td { background: var(--surface-alt); } .board-lph-list { display: flex; flex-direction: column; - gap: 7px; - margin-top: 14px; + gap: 8px; + margin-top: 12px; } .board-lph-row { display: grid; grid-template-columns: 42px 1fr 50px; align-items: center; - gap: 10px; + gap: 8px; } .board-lph-row.is-ansicht{ cursor: default; } @@ -1696,7 +1694,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } color: var(--text-muted); } -.board-lph-row.lp-aktiv .board-lph-label { color: var(--accent); font-weight: 600; } +.board-lph-row.lp-aktiv .board-lph-label { color: var(--accent); font-weight: 500; } /* Der Prozentwert einer Leistungsphase an der Stelle des Eingabefeldes. Die Breite entspricht dem Feld, damit die Balken aller Zeilen gleich weit @@ -1709,22 +1707,22 @@ tr:nth-child(even) td { background: var(--surface-alt); } color: var(--text-muted); } -.board-role-mini { display: flex; flex-direction: column; gap: 10px; } -.board-role-mini .board-role-row { display: flex; align-items: center; gap: 10px; } +.board-role-mini { display: flex; flex-direction: column; gap: 8px; } +.board-role-mini .board-role-row { display: flex; align-items: center; gap: 8px; } .board-role-mini .board-role-label { width: 100px; flex-shrink: 0; - font-size: 11.5px; + font-size: 12px; color: var(--text-muted); } .board-role-mini .board-role-chips { display: flex; flex-wrap: wrap; gap: 6px; } .section-title { - font-size: 17px; - font-weight: 600; - margin: 24px 0 10px; + font-size: 19px; + font-weight: 500; + margin: 24px 0 8px; color: var(--text); - letter-spacing: -0.02em; + letter-spacing: 0; line-height: 1.2; } @@ -1756,19 +1754,18 @@ tr:nth-child(even) td { background: var(--surface-alt); } .load-rolle { width: 100%; } .load-rolle-titel { - font-size: 14px; - font-weight: 600; + font-size: 13px; + font-weight: 500; margin: 0 0 6px; color: var(--text-muted); - text-transform: uppercase; - letter-spacing: .04em; + letter-spacing: 0; } .load-zeile { display: flex; align-items: center; gap: 16px; - padding: 11px 4px; + padding: 12px 4px; border-bottom: 1px solid var(--line-soft); } .load-zeile:last-child { border-bottom: none; } @@ -1814,10 +1811,10 @@ tr:nth-child(even) td { background: var(--surface-alt); } display: flex; align-items: center; height: 100%; - padding: 0 7px; + padding: 0 8px; min-width: 3px; - font-size: 10px; - font-weight: 600; + font-size: 11px; + font-weight: 500; color: #fff; white-space: nowrap; overflow: hidden; @@ -1831,22 +1828,22 @@ tr:nth-child(even) td { background: var(--surface-alt); } .load-band-leer { font-size: 11px; color: var(--text-subtle); - padding-left: 9px; + padding-left: 8px; } .load-wert { flex: 0 0 62px; text-align: right; font-size: 19px; - font-weight: 600; - letter-spacing: -.02em; + font-weight: 500; + letter-spacing: 0; font-variant-numeric: tabular-nums; } .load-anbahnung { - font-size: 10px; - padding: 1px 7px; - border-radius: var(--r-pill); + font-size: 11px; + padding: 1px 8px; + border-radius: 6px; background: var(--surface-sunk); color: var(--text-muted); white-space: nowrap; @@ -1860,18 +1857,18 @@ tr:nth-child(even) td { background: var(--surface-alt); } align-items: center; gap: 16px; flex-wrap: wrap; - padding: 12px 14px; + padding: 12px 16px; background: var(--surface-sunk); border-radius: var(--r-lg); font-size: 13px; } .load-kopf-zahl strong { - font-size: 17px; + font-size: 19px; font-variant-numeric: tabular-nums; } .load-kopf-warnung { color: var(--red); - font-weight: 600; + font-weight: 500; } .load-kopf-warnung::before { content: ''; @@ -1879,12 +1876,12 @@ tr:nth-child(even) td { background: var(--surface-alt); } width: 7px; height: 7px; border-radius: 50%; background: var(--red); - margin-right: 7px; + margin-right: 8px; vertical-align: middle; } .load-luecken { - padding: 12px 14px; + padding: 12px 16px; border: 1px dashed var(--line); border-radius: var(--r-lg); font-size: 12px; @@ -1902,7 +1899,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } /* Summenzeile je Mensch: ein durchgehender Riegel statt der Projektsegmente. Sie beantwortet die Frage, die die Rollenzeilen nicht beantworten können — wer in drei Rollen arbeitet, hat trotzdem nur eine Arbeitswoche. */ -.load-zeile-summe .load-wer-name { font-weight: 600; } +.load-zeile-summe .load-wer-name { font-weight: 500; } .load-seg-summe { border-right: none; } /* Marke der vollen Kapazität im Band. Sie sitzt am rechten Rand, weil das @@ -1927,7 +1924,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } .load-legende-item em { font-style: normal; color: var(--text-subtle); - margin-left: 3px; + margin-left: 4px; } /* Legende der Projektfarben, nur für die tatsächlich vorkommenden Projekte. @@ -1936,7 +1933,7 @@ tr:nth-child(even) td { background: var(--surface-alt); } display: flex; flex-wrap: wrap; gap: 6px 16px; - padding-top: 14px; + padding-top: 16px; border-top: 1px solid var(--line-soft); font-size: 11px; color: var(--text-muted); @@ -1949,33 +1946,32 @@ tr:nth-child(even) td { background: var(--surface-alt); } .load-legende-item i { width: 9px; height: 9px; - border-radius: 2px; + border-radius: 4px; flex: 0 0 auto; } @media (max-width: 720px) { .load-wer { flex-basis: 128px; } - .load-zeile { gap: 10px; } - .load-wert { flex-basis: 52px; font-size: 16px; } + .load-zeile { gap: 8px; } + .load-wert { flex-basis: 52px; font-size: 15px; } } .load-row-title { grid-column: 1 / -1; width: 100%; - font-size: 14px; - font-weight: 600; + font-size: 13px; + font-weight: 500; margin: 0 0 2px 0; padding-top: 4px; color: var(--text-muted); - text-transform: uppercase; - letter-spacing: .04em; + letter-spacing: 0; } .load-card { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-xl); - padding: 20px 22px; + padding: 20px 24px; min-width: 0; width: 100%; box-shadow: var(--sh-2); @@ -1989,24 +1985,24 @@ tr:nth-child(even) td { background: var(--surface-alt); } .load-card h3 { margin: 0 0 4px; - font-size: 14px; - font-weight: 600; - letter-spacing: -0.01em; + font-size: 13px; + font-weight: 500; + letter-spacing: 0; line-height: 1.25; } .load-num { font-size: 30px; - font-weight: 600; + font-weight: 500; color: var(--text); - letter-spacing: -0.03em; + letter-spacing: 0; line-height: 1.1; } .load-detail { font-size: 11px; color: var(--text-muted); - margin-top: 10px; + margin-top: 8px; } .load-detail div { @@ -2049,17 +2045,17 @@ tr:nth-child(even) td { background: var(--surface-alt); } .modal h2 { margin-top: 0; - font-size: 20px; - font-weight: 600; - letter-spacing: -0.02em; + font-size: 19px; + font-weight: 500; + letter-spacing: 0; line-height: 1.15; } .form-row { - margin-bottom: 14px; + margin-bottom: 12px; display: flex; flex-direction: column; - gap: 5px; + gap: 4px; } .form-row label { @@ -2099,7 +2095,7 @@ select:disabled:hover { color: #fff; font-size: 13px; line-height: 1.45; - padding: 11px 15px; + padding: 12px 16px; border-radius: var(--r-md); box-shadow: var(--sh-3); } @@ -2110,13 +2106,13 @@ select:disabled:hover { .lock-notice { display: flex; align-items: center; - gap: 10px; + gap: 8px; flex-wrap: wrap; background: var(--surface-alt); border: 1px solid var(--red); color: var(--red); border-radius: var(--r-md); - padding: 9px 13px; + padding: 8px 12px; margin-bottom: 12px; font-size: 13px; } @@ -2138,17 +2134,17 @@ select:disabled:hover { } .lp-matrix th.lp-lph { font-size: 12px; - font-weight: 600; + font-weight: 500; text-align: left; padding: 6px 8px; white-space: nowrap; } .lp-matrix td { - padding: 3px 8px; + padding: 4px 8px; } .lp-matrix td input[type=text] { width: 64px; - padding: 4px 7px; + padding: 4px 8px; font-size: 13px; } .lp-matrix tbody th.lp-lph, @@ -2179,7 +2175,7 @@ select:disabled:hover { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-xl); - padding: 20px 22px; + padding: 20px 24px; box-shadow: var(--sh-2); transition: box-shadow .2s var(--ease); } @@ -2371,13 +2367,13 @@ a.secondary:hover { background: var(--surface-sunk); border-color: var(--text-su der Footer als Ganzes soll rechtsbündig sein. */ .project-card-footer button { margin-left: 0; } -.tag-input { width: 110px; font-size: 12px; padding: 3px 8px; } +.tag-input { width: 110px; font-size: 12px; padding: 4px 8px; } /* === Hinweise & Hilfsklassen === */ .legend { font-size: 11px; color: var(--text-muted); - margin: 10px 0; + margin: 8px 0; display: flex; gap: 16px; flex-wrap: wrap; @@ -2386,7 +2382,7 @@ a.secondary:hover { background: var(--surface-sunk); border-color: var(--text-su .legend span { display: inline-flex; align-items: center; - gap: 5px; + gap: 4px; } @@ -2400,13 +2396,13 @@ a.secondary:hover { background: var(--surface-sunk); border-color: var(--text-su anwesend, Tabelle attendance); der Zähler in der Kopfzeile macht sichtbar, wenn noch niemand geklickt hat. */ #weekAttendance .bericht-disclosure { margin-top: 16px; } -.attendance-actions { display: flex; gap: 8px; margin-bottom: 10px; } +.attendance-actions { display: flex; gap: 8px; margin-bottom: 8px; } .attendance-grid { display: flex; flex-wrap: wrap; gap: 8px; - padding: 12px 14px; + padding: 12px 16px; } .attendance-tile { @@ -2416,7 +2412,7 @@ a.secondary:hover { background: var(--surface-sunk); border-color: var(--text-su align-items: center; gap: 4px; width: 84px; - padding: 9px 5px 8px; + padding: 8px 4px 8px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); @@ -2435,17 +2431,17 @@ a.secondary:hover { background: var(--surface-sunk); border-color: var(--text-su background: var(--surface-sunk); color: var(--text-muted); display: flex; align-items: center; justify-content: center; - font-size: 11px; font-weight: 600; + font-size: 11px; font-weight: 500; transition: background .15s var(--ease), color .15s var(--ease); } .attendance-name { - font-size: 10.5px; + font-size: 11px; line-height: 1.25; text-align: center; word-break: break-word; } .attendance-note { - font-size: 9.5px; + font-size: 11px; color: var(--amber); line-height: 1.2; text-align: center; @@ -2456,7 +2452,7 @@ a.secondary:hover { background: var(--surface-sunk); border-color: var(--text-su position: absolute; top: 4px; right: 6px; font-size: 11px; - font-weight: 700; + font-weight: 600; color: var(--green); line-height: 1; } @@ -2496,7 +2492,7 @@ a.secondary:hover { background: var(--surface-sunk); border-color: var(--text-su /* Fehlermeldung direkt am Formularfeld (Passwort-Dialog, Aufgaben-Dialog) statt als alert() — der Fehler steht dort, wo er entstanden ist. */ -.field-error { font-size: 11.5px; color: var(--red); } +.field-error { font-size: 12px; color: var(--red); } .hint { color: var(--text-subtle); @@ -2507,7 +2503,7 @@ a.secondary:hover { background: var(--surface-sunk); border-color: var(--text-su .del-proj { color: var(--red); cursor: pointer; - font-weight: 600; + font-weight: 500; } .lock-notice button { margin-left: 12px; } @@ -2516,10 +2512,10 @@ a.secondary:hover { background: var(--surface-sunk); border-color: var(--text-su input[type=text].edit-name { border: 1px solid transparent; background: transparent; - font-weight: 600; + font-weight: 500; width: 100%; font-size: 12px; - padding: 3px 5px; + padding: 4px 4px; border-radius: var(--r-sm); transition: background .15s var(--ease), border-color .15s var(--ease), box-shadow .15s var(--ease); } @@ -2529,7 +2525,7 @@ input[type=text].edit-name:hover { background: rgba(0,0,0,.03); } input[type=text].edit-name:focus { background: var(--surface); border-color: var(--accent); - box-shadow: 0 0 0 3px rgba(0,113,227,.18); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); outline: none; } @@ -2554,102 +2550,97 @@ input[type=text].edit-name:focus { html:not([data-theme="light"]) { color-scheme: dark; } html:not([data-theme="light"]) { - /* Auf Eriks Wunsch ("das gesamte dark mode Farbschema an das der - Wandtafel anpassen") übernimmt der GESAMTE App-Dark-Mode die - Logo-Blau-Familie des Dashboards (--dash-* in body.wandtafel-aktiv - weiter oben) statt des vorherigen, generischen Apple-Blaus — alle - Komponenten der App lesen ausschließlich über diese Tokens, eine - Änderung hier genügt also für die ganze Anwendung. Rot/Gelb/Grün - bleiben als eigenständige Statusfarben bestehen (müssen unabhängig - von der Markenfarbe sofort erkennbar sein, siehe Ampel-Logik in - js/load/load.js), nur in denselben gedeckteren Tönen wie am Dashboard. */ - --accent: #7fc3dd; - --accent-hover: #96cfe3; - --accent-active: #5fa3c0; - --accent-soft: #16222c; + /* „Bauplan“ (unslop-Überarbeitung, Eriks Wahl „volle Überarbeitung“): + Flächen fast neutral (Graphit, leicht kühl), die Farbe tragen der + Akzent (Logo-Blau) und die Inhalte — Terminplan, Auslastung, Status. + Ersetzt die frühere Logo-Blau-Fläche aus der Wandtafel; die Wandtafel + selbst behält ihre eigenen dash- und wt-Tokens. */ + --accent: #86bfdf; + --accent-hover: #9dcbe5; + --accent-active: #6aa9cc; + --accent-soft: #1b2731; - --text: #e7eef3; - --text-muted: #9fb3c0; - --text-subtle: #70838f; + --text: #eceef0; + --text-muted: #a5abb2; + --text-subtle: #878d95; - --bg: #10181f; - --surface: #141c23; - --surface-alt: #16222c; - --surface-sunk: #1c2730; + --bg: #121416; + --surface: #181a1d; + --surface-alt: #1c1f22; + --surface-sunk: #23262a; - --line: #2c3e49; - --line-soft: #1f2b33; + --line: #2e3237; + --line-soft: #22262a; - --green: #4cd080; - --amber: #e8a15c; - --red: #ef6f63; - --red-hover: #f58a7f; - --red-active: #c65349; + --green: #4cc38a; + --amber: #e0a159; + --red: #e5484d; + --red-hover: #ee6a6e; + --red-active: #c23a3f; - --attend-bg: rgba(76,208,128,.14); - --attend-bg-hover: rgba(76,208,128,.22); + --attend-bg: rgba(76,195,138,.14); + --attend-bg-hover: rgba(76,195,138,.22); /* Auf Weiß gesetzt — deshalb dunkler als --band-neu/--green gebraucht (Kontrastgrund wie im Hell-Modus): --band-neu ist das dunkle Logo-Blau selbst (dasselbe #116896 wie am Dashboard). */ - --band-neu: #116896; - --band-fortschritt: #1f7a4f; - --meilenstein: #c19cf0; + --band-neu: #0f5a85; + --band-fortschritt: #1f7a3a; --meilenstein: #c19cf0; --protokoll-neu-bg: rgba(255,214,10,.14); --protokoll-neu-border: #ffd60a; - --sh-1: 0 1px 2px rgba(0,0,0,.5), 0 1px 3px rgba(0,0,0,.4); - --sh-2: 0 2px 10px rgba(0,0,0,.55), 0 1px 3px rgba(0,0,0,.4); - --sh-3: 0 12px 40px rgba(0,0,0,.7), 0 2px 10px rgba(0,0,0,.5); + --sh-1: 0 1px 2px rgba(0,0,0,.4); + --sh-2: 0 2px 8px rgba(0,0,0,.45); + --sh-3: 0 12px 32px rgba(0,0,0,.55), 0 2px 8px rgba(0,0,0,.35); } } html[data-theme="dark"] { color-scheme: dark; - --accent: #7fc3dd; - --accent-hover: #96cfe3; - --accent-active: #5fa3c0; - --accent-soft: #16222c; + --accent: #86bfdf; + --accent-hover: #9dcbe5; + --accent-active: #6aa9cc; + --accent-soft: #1b2731; - --text: #e7eef3; - --text-muted: #9fb3c0; - --text-subtle: #70838f; + --text: #eceef0; + --text-muted: #a5abb2; + --text-subtle: #878d95; - --bg: #10181f; - --surface: #141c23; - --surface-alt: #16222c; - --surface-sunk: #1c2730; + --bg: #121416; + --surface: #181a1d; + --surface-alt: #1c1f22; + --surface-sunk: #23262a; - --line: #2c3e49; - --line-soft: #1f2b33; + --line: #2e3237; + --line-soft: #22262a; - --green: #4cd080; - --amber: #e8a15c; - --red: #ef6f63; - --red-hover: #f58a7f; - --red-active: #c65349; + --green: #4cc38a; + --amber: #e0a159; + --red: #e5484d; + --red-hover: #ee6a6e; + --red-active: #c23a3f; - --attend-bg: rgba(76,208,128,.14); - --attend-bg-hover: rgba(76,208,128,.22); + --attend-bg: rgba(76,195,138,.14); + --attend-bg-hover: rgba(76,195,138,.22); - --band-neu: #116896; - --band-fortschritt: #1f7a4f; + --band-neu: #0f5a85; + --band-fortschritt: #1f7a3a; --protokoll-neu-bg: rgba(255,214,10,.14); --protokoll-neu-border: #ffd60a; - --sh-1: 0 1px 2px rgba(0,0,0,.5), 0 1px 3px rgba(0,0,0,.4); - --sh-2: 0 2px 10px rgba(0,0,0,.55), 0 1px 3px rgba(0,0,0,.4); - --sh-3: 0 12px 40px rgba(0,0,0,.7), 0 2px 10px rgba(0,0,0,.5); + --sh-1: 0 1px 2px rgba(0,0,0,.4); + --sh-2: 0 2px 8px rgba(0,0,0,.45); + --sh-3: 0 12px 32px rgba(0,0,0,.55), 0 2px 8px rgba(0,0,0,.35); } /* Gemeinsame Dark-Style-Regeln (System oder manuell) */ @media (prefers-color-scheme: dark) { html:not([data-theme="light"]) .app-topbar { - background: rgba(28,28,30,.75); + background: rgba(18,20,22,.84); border-bottom: 1px solid var(--line); } html:not([data-theme="light"]) .toolbar-divider { background: var(--line); } @@ -2685,7 +2676,7 @@ html[data-theme="dark"] { html:not([data-theme="light"]) .nav-item:hover { background: rgba(255,255,255,.08); } html:not([data-theme="light"]) .nav-item.active { background: var(--accent-soft); } - html:not([data-theme="light"]) button:focus-visible { box-shadow: 0 0 0 3px rgba(10,132,255,.45); } + html:not([data-theme="light"]) button:focus-visible { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 40%, transparent); } html:not([data-theme="light"]) button.secondary { background: rgba(255,255,255,.10); color: var(--text); } html:not([data-theme="light"]) button.secondary:hover { background: rgba(255,255,255,.15); } html:not([data-theme="light"]) button.secondary:active { background: rgba(255,255,255,.20); } @@ -2759,7 +2750,7 @@ html[data-theme="dark"] { } html[data-theme="dark"] .app-topbar { - background: rgba(28,28,30,.75); + background: rgba(18,20,22,.84); border-bottom: 1px solid var(--line); } html[data-theme="dark"] .toolbar-divider { background: var(--line); } @@ -2795,7 +2786,7 @@ html[data-theme="dark"] .topbar-logo { filter: brightness(.92); } html[data-theme="dark"] .nav-item:hover { background: rgba(255,255,255,.08); } html[data-theme="dark"] .nav-item.active { background: var(--accent-soft); } -html[data-theme="dark"] button:focus-visible { box-shadow: 0 0 0 3px rgba(10,132,255,.45); } +html[data-theme="dark"] button:focus-visible { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 40%, transparent); } html[data-theme="dark"] button.secondary { background: rgba(255,255,255,.10); color: var(--text); } html[data-theme="dark"] button.secondary:hover { background: rgba(255,255,255,.15); } html[data-theme="dark"] button.secondary:active { background: rgba(255,255,255,.20); } @@ -2985,7 +2976,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 top: 0; bottom: 0; border-right: 1px solid var(--line-soft); - font-size: 10px; + font-size: 11px; color: var(--text-muted); padding: 2px 4px; white-space: nowrap; @@ -2995,7 +2986,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .gantt-month { background: var(--surface-sunk); - font-weight: 600; + font-weight: 500; } .gantt-day { @@ -3010,7 +3001,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 } .gantt-day.gantt-week { - font-weight: 600; + font-weight: 500; color: var(--text); border-right: 1px solid var(--line); } @@ -3152,7 +3143,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 } .gantt-todo-add input[type=text], .gantt-todo-add input[type=date] { - padding: 4px 7px; + padding: 4px 8px; font-size: 12px; } .gantt-todo-add input[type=text] { @@ -3217,16 +3208,16 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .gantt-dep-path.highlight { stroke-width: 3.5px; opacity: 1; - filter: drop-shadow(0 0 3px rgba(0, 113, 227, 0.4)); + } .gantt-dep-badge { display: inline-flex; align-items: center; - gap: 3px; - font-size: 10px; + gap: 4px; + font-size: 11px; padding: 1px 6px; - border-radius: var(--r-pill); + border-radius: 6px; background: var(--accent-soft); color: var(--accent); margin-left: 6px; @@ -3235,7 +3226,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 text-overflow: ellipsis; white-space: nowrap; vertical-align: middle; - border: 1px solid rgba(0, 113, 227, 0.2); + border: 1px solid color-mix(in srgb, var(--accent) 20%, transparent); } .gantt-dep-badge.conflict { @@ -3244,8 +3235,8 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 border-color: rgba(215, 0, 21, 0.2); } .gantt-todo-actions button { - padding: 2px 7px; - font-size: 10px; + padding: 2px 8px; + font-size: 11px; } .gantt-milestone { @@ -3266,7 +3257,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 position: absolute; top: 16px; transform: translateX(-50%); - font-size: 10px; + font-size: 11px; color: var(--text-muted); white-space: nowrap; pointer-events: none; @@ -3318,7 +3309,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--sh-3); - padding: 10px; + padding: 12px; font-size: 13px; } @@ -3330,7 +3321,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 } .range-picker-title { - font-weight: 600; + font-weight: 500; font-size: 13px; } @@ -3349,7 +3340,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 /* KW-Spalte: klein und gedämpft, damit die Tage die Hauptsache bleiben. */ .range-picker-kw { display: grid; place-items: center; - font-size: 10px; font-weight: 600; color: var(--text-subtle); + font-size: 11px; font-weight: 500; color: var(--text-subtle); border-right: 1px solid var(--line-soft); font-variant-numeric: tabular-nums; } @@ -3357,15 +3348,15 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .range-picker-weekday { text-align: center; - font-size: 10px; - font-weight: 600; + font-size: 11px; + font-weight: 500; color: var(--text-muted); padding: 2px 0; } .range-picker-day { text-align: center; - padding: 5px 0; + padding: 4px 0; border-radius: var(--r-sm); cursor: pointer; user-select: none; @@ -3380,7 +3371,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .range-picker-day.sel-end { background: var(--accent); color: #fff; - font-weight: 600; + font-weight: 500; } .range-picker-footer { @@ -3417,8 +3408,8 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 gap: 6px; background: var(--surface); border: 1px solid var(--line-soft); - border-radius: var(--r-pill); - padding: 3px 10px; + border-radius: 6px; + padding: 4px 12px; font-size: 12px; } @@ -3453,7 +3444,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 gap: 4px; background: var(--surface-sunk); border: 1px solid var(--line-soft); - border-radius: var(--r-pill); + border-radius: 6px; padding: 2px 8px; font-size: 11px; font-weight: 400; @@ -3462,7 +3453,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .tag-chip .tag-remove { cursor: pointer; - font-weight: 600; + font-weight: 500; color: var(--text-subtle); line-height: 1; transition: color .15s var(--ease); @@ -3488,9 +3479,9 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 } .dash-gruss { margin: 0; - font-size: 22px; - font-weight: 600; - letter-spacing: -.02em; + font-size: 24px; + font-weight: 500; + letter-spacing: 0; } .dash-gruss em { font-style: normal; @@ -3504,9 +3495,9 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 } .dash-sitzung { font-size: 11px; - font-weight: 600; - padding: 2px 9px; - border-radius: var(--r-pill); + font-weight: 500; + padding: 2px 8px; + border-radius: 6px; background: var(--surface-sunk); color: var(--text-muted); } @@ -3520,7 +3511,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .dash-band { display: flex; align-items: center; - gap: 22px; + gap: 20px; flex-wrap: wrap; padding: 16px 20px; margin-bottom: 24px; @@ -3537,14 +3528,14 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 margin: 0; flex: 1 1 300px; min-width: 0; - font-size: 17px; + font-size: 19px; } /* Die Zahl größer als der Satz: Sie ist die Nachricht, und ab 19 px fett gilt für den Kontrast die Schwelle für große Schrift — die Ampelfarbe erreicht auf der abgesetzten Bandfläche sonst nur 4,1:1 im dunklen Thema. */ .dash-befund b { font-size: 1.15em; - font-weight: 600; + font-weight: 500; font-variant-numeric: tabular-nums; } .dash-befund b.ist-rot { color: var(--red); } @@ -3554,7 +3545,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .dash-zahl { display: flex; flex-direction: column; gap: 1px; min-width: 74px; } .dash-zahl b { font-size: 19px; - font-weight: 600; + font-weight: 500; line-height: 1.15; font-variant-numeric: tabular-nums; } @@ -3574,21 +3565,20 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .dash-abschnitt-kopf { display: flex; align-items: baseline; - gap: 10px; + gap: 8px; margin-bottom: 8px; } .dash-abschnitt-titel { margin: 0; - font-size: 11.5px; - font-weight: 600; - letter-spacing: .06em; - text-transform: uppercase; + font-size: 12px; + font-weight: 500; + letter-spacing: 0; color: var(--text-muted); } .dash-abschnitt-zahl { font-size: 11px; - padding: 1px 7px; - border-radius: var(--r-pill); + padding: 1px 8px; + border-radius: 6px; background: var(--surface-sunk); color: var(--text-muted); font-variant-numeric: tabular-nums; @@ -3606,14 +3596,14 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 box-shadow: var(--sh-1); overflow: hidden; } -.dash-leer { padding: 16px 18px; font-size: 13px; color: var(--text-subtle); } +.dash-leer { padding: 16px 20px; font-size: 13px; color: var(--text-subtle); } /* ---------- Meine Aufgaben: Zeilen statt halbseitiger Karten ---------- */ .dash-auf { display: flex; align-items: center; - gap: 14px; - padding: 11px 16px; + gap: 12px; + padding: 12px 16px; border-bottom: 1px solid var(--line-soft); text-decoration: none; color: inherit; @@ -3626,7 +3616,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .dash-auf-text { flex: 1 1 auto; min-width: 0; } .dash-auf-titel { display: block; - font-size: 13.5px; + font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; @@ -3635,14 +3625,14 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .dash-auf-meta { display: flex; align-items: center; - gap: 7px; + gap: 8px; flex-wrap: wrap; margin-top: 1px; font-size: 11px; color: var(--text-subtle); } .dash-auf-tag { - font-size: 10px; + font-size: 11px; padding: 0 6px; border-radius: var(--r-sm); background: var(--surface-sunk); @@ -3673,7 +3663,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 line-height: 1.3; font-variant-numeric: tabular-nums; } -.dash-auf-frist em { display: block; font-style: normal; font-size: 10.5px; color: var(--text-subtle); } +.dash-auf-frist em { display: block; font-style: normal; font-size: 11px; color: var(--text-subtle); } .dash-auf-frist.ist-ueberfaellig, .dash-auf-frist.ist-ueberfaellig em { color: var(--red); } .dash-auf-frist.ist-bald { color: var(--amber); } @@ -3681,8 +3671,8 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 .dash-rand-zeile { display: flex; align-items: center; - gap: 10px; - padding: 10px 14px; + gap: 8px; + padding: 12px 16px; border-bottom: 1px solid var(--line-soft); } .dash-rand-zeile:last-child { border-bottom: none; } @@ -3693,15 +3683,15 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 border-radius: 50%; display: grid; place-items: center; - font-size: 10.5px; - font-weight: 600; + font-size: 11px; + font-weight: 500; background: var(--surface-sunk); color: var(--text-muted); } .dash-rand-text { flex: 1; min-width: 0; } .dash-rand-name { display: block; - font-size: 12.5px; + font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; @@ -3709,7 +3699,7 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 } .dash-rand-meta { display: block; - font-size: 10.5px; + font-size: 11px; color: var(--text-subtle); overflow: hidden; text-overflow: ellipsis; @@ -3717,9 +3707,9 @@ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,2 } .dash-chip { flex: 0 0 auto; - font-size: 10px; - padding: 1px 7px; - border-radius: var(--r-pill); + font-size: 11px; + padding: 1px 8px; + border-radius: 6px; background: var(--surface-sunk); color: var(--text-muted); white-space: nowrap; @@ -3800,36 +3790,35 @@ html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10, background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); - padding: 16px 18px; + padding: 16px 20px; box-shadow: var(--sh-1); } .settings-card-title { - margin: 0 0 10px; - font-size: 14px; - font-weight: 600; + margin: 0 0 8px; + font-size: 13px; + font-weight: 500; display: flex; align-items: baseline; - gap: 10px; + gap: 8px; flex-wrap: wrap; } /* Reichweite einer Einstellung — „firmenweit" heißt: wirkt bei allen. */ .settings-scope { font-size: 11px; font-weight: 500; - letter-spacing: .04em; - text-transform: uppercase; + letter-spacing: 0; color: var(--text-muted); background: var(--surface-alt); - border-radius: var(--r-pill); + border-radius: 8px; padding: 2px 8px; } -.settings-kv { display: flex; flex-direction: column; gap: 2px; margin-bottom: 10px; } +.settings-kv { display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px; } .settings-kv-row { display: flex; - gap: 10px; - font-size: 12.5px; - padding: 5px 0; + gap: 8px; + font-size: 13px; + padding: 4px 0; border-bottom: 1px solid var(--line-soft); } .settings-kv-row:last-child { border-bottom: none; } @@ -3842,8 +3831,8 @@ html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10, display: flex; align-items: center; gap: 8px; - font-size: 12.5px; - margin-bottom: 10px; + font-size: 13px; + margin-bottom: 8px; } .settings-inline-field select { min-width: 120px; } @@ -3851,28 +3840,28 @@ html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10, ein umrandeter Block je Anbieter statt eines durchgehenden Feld-Rasters — ChatGPT und Claude sind zwei getrennte Zugänge, keine vier gleichrangigen Felder. Design-Entwurf mit Erik abgestimmt (Artifact d7ab2945). */ -.ai-provider { border: 1px solid var(--line-soft); border-radius: var(--r-md); padding: 14px 16px; } +.ai-provider { border: 1px solid var(--line-soft); border-radius: var(--r-md); padding: 16px 16px; } .ai-provider + .ai-provider { margin-top: 12px; } -.ai-provider-head { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; } +.ai-provider-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; } .ai-provider-info { min-width: 0; } .ai-provider-mark { - width: 26px; height: 26px; border-radius: 7px; + width: 26px; height: 26px; border-radius: 8px; display: flex; align-items: center; justify-content: center; - font-size: 12px; font-weight: 700; color: #fff; flex-shrink: 0; letter-spacing: -.02em; + font-size: 12px; font-weight: 600; color: #fff; flex-shrink: 0; letter-spacing: 0; } .ai-provider-mark.chatgpt { background: #10a37f; } .ai-provider-mark.claude { background: #c96442; } -.ai-provider-name { font-weight: 600; font-size: 13px; } -.ai-provider-sub { font-size: 11.5px; color: var(--text-subtle); } +.ai-provider-name { font-weight: 500; font-size: 13px; } +.ai-provider-sub { font-size: 12px; color: var(--text-subtle); } /* Status-Pill: derselbe Punkt-plus-Text-Aufbau wie an anderen Stellen der App (z. B. .protokoll-status-dot), hier als Pill neben dem Anbieternamen. */ .ai-status-chip { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; - font-size: 11.5px; font-weight: 500; - padding: 3px 10px 3px 8px; - border-radius: var(--r-pill); + font-size: 12px; font-weight: 500; + padding: 4px 12px 4px 8px; + border-radius: 6px; background: var(--surface-alt); color: var(--text-muted); flex-shrink: 0; @@ -3885,8 +3874,8 @@ html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10, .ai-provider-row input[type=password], .ai-provider-row input[type=text] { flex: 1; min-width: 0; - padding: 7px 10px; - font-size: 12.5px; + padding: 8px 12px; + font-size: 13px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); @@ -3924,7 +3913,7 @@ html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10, .ai-text-btn { flex-shrink: 0; border: none; background: none; - font-size: 11.5px; color: var(--text-subtle); + font-size: 12px; color: var(--text-subtle); cursor: pointer; padding: 0 2px; } .ai-text-btn:hover { color: var(--red); } @@ -3937,18 +3926,18 @@ html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10, er die Karte in echt benutzte — deshalb jetzt eine sichtbare Wahl statt eines kleinen Links, den man erst entdecken muss. */ .ai-mode-toggle { - display: inline-flex; background: var(--surface-sunk); border-radius: var(--r-pill); - padding: 3px; gap: 2px; margin-top: 12px; + display: inline-flex; background: var(--surface-sunk); border-radius: 8px; + padding: 4px; gap: 2px; margin-top: 12px; } .ai-mode-toggle button { - border: none; background: none; padding: 5px 13px; border-radius: var(--r-pill); + border: none; background: none; padding: 4px 12px; border-radius: 6px; font-size: 12px; font-weight: 500; color: var(--text-muted); cursor: pointer; font-family: inherit; } -.ai-mode-toggle button.is-active { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: var(--sh-1); } +.ai-mode-toggle button.is-active { background: var(--surface); color: var(--text); font-weight: 500; box-shadow: var(--sh-1); } .ai-url-panel { margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--line-soft); display: none; } .ai-url-panel.is-open { display: block; } -.ai-url-panel label { display: block; font-size: 11px; color: var(--text-subtle); margin-bottom: 5px; } +.ai-url-panel label { display: block; font-size: 11px; color: var(--text-subtle); margin-bottom: 4px; } .ai-url-panel .ai-provider-row { margin-bottom: 0; } /* Zweites Label-/Zeilenpaar im selben Panel (Modellname, unter der Server-Adresse): braucht Abstand nach oben, den das erste (am @@ -3977,14 +3966,14 @@ html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10, Protokoll-Import-Banner: ein Toast neben einer sich gleichzeitig ändernden Ansicht wird leicht übersehen. :empty blendet die Zeile aus, solange kein Fehler ansteht, ohne eigenes hidden-Attribut in JS. */ -.ai-test-error { font-size: 11.5px; color: var(--red); margin-top: 8px; } +.ai-test-error { font-size: 12px; color: var(--red); margin-top: 8px; } .ai-test-error:empty { display: none; } /* Bestätigung nach dem Speichern. Bewusst kein alert(): ein gelungener Speichervorgang soll den Arbeitsfluss nicht anhalten. */ .settings-note { - margin-top: 14px; - font-size: 12.5px; + margin-top: 12px; + font-size: 13px; color: var(--green); opacity: 0; transition: opacity .25s var(--ease); @@ -4004,37 +3993,37 @@ html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10, display: flex; align-items: center; justify-content: space-between; - gap: 10px; - font-size: 12.5px; + gap: 8px; + font-size: 13px; } -.settings-field input { width: 88px; padding: 4px 7px; font-size: 12.5px; text-align: right; } +.settings-field input { width: 88px; padding: 4px 8px; font-size: 13px; text-align: right; } .settings-check { display: flex; align-items: center; gap: 8px; - font-size: 12.5px; + font-size: 13px; margin: 4px 0 2px; } .settings-subtitle { margin: 16px 0 4px; - font-size: 12.5px; - font-weight: 600; + font-size: 13px; + font-weight: 500; } -.settings-matrix-wrap { overflow-x: auto; margin-bottom: 10px; } +.settings-matrix-wrap { overflow-x: auto; margin-bottom: 8px; } .settings-matrix { border-collapse: collapse; font-size: 12px; } .settings-matrix th, .settings-matrix td { - padding: 3px 6px; + padding: 4px 6px; border-bottom: 1px solid var(--line-soft); text-align: center; } .settings-matrix thead th { color: var(--text-muted); font-weight: 500; white-space: nowrap; } .settings-matrix tbody th { text-align: left; font-weight: 500; white-space: nowrap; } -.settings-matrix input { width: 62px; padding: 3px 6px; font-size: 12px; text-align: right; } +.settings-matrix input { width: 62px; padding: 4px 6px; font-size: 12px; text-align: right; } -.settings-holiday-list { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; } +.settings-holiday-list { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; } /* Abweichende Stelle im Auslastungs-Tab (js/load/load.js) — steht nur da, wenn die Person nicht voll beschäftigt ist. */ @@ -4043,8 +4032,8 @@ html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10, font-weight: 500; color: var(--text-muted); background: var(--surface-alt); - border-radius: var(--r-pill); - padding: 1px 7px; + border-radius: 6px; + padding: 1px 8px; margin-left: 6px; } @@ -4053,7 +4042,7 @@ html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10, eigenstaendigen Seite public/admin-users.html; die Regeln der dortigen Seiten-Huelle (.admin-page/.admin-header/.admin-body) sind mit ihr entfallen, weil der Abschnitt jetzt in der normalen App-Huelle liegt. */ -.admin-toolbar { margin-bottom: 14px; } +.admin-toolbar { margin-bottom: 12px; } td.actions-cell { white-space: nowrap; width: 1%; text-align: right; } /* Vor- und Nachname nebeneinander (Benutzer anlegen/bearbeiten), auf @@ -4085,7 +4074,7 @@ tr.is-menu-open { background: var(--surface-alt); } .user-menu { position: fixed; z-index: 250; min-width: 220px; max-width: 280px; background: var(--surface); border: 1px solid var(--line); - border-radius: var(--r-md); box-shadow: var(--sh-3); padding: 5px; + border-radius: var(--r-md); box-shadow: var(--sh-3); padding: 4px; transform-origin: top right; animation: user-menu-auf var(--dur) var(--ease-out); } @@ -4094,9 +4083,9 @@ tr.is-menu-open { background: var(--surface-alt); } @keyframes user-menu-auf-oben { from { opacity: 0; transform: scale(.96) translateY(4px); } to { opacity: 1; transform: none; } } .user-menu-item { all: unset; box-sizing: border-box; - display: flex; gap: 10px; align-items: flex-start; width: 100%; - padding: 7px 10px; border-radius: var(--r-sm); - color: var(--text); font-size: 13.5px; line-height: 1.35; cursor: pointer; + display: flex; gap: 8px; align-items: flex-start; width: 100%; + padding: 8px 12px; border-radius: var(--r-sm); + color: var(--text); font-size: 13px; line-height: 1.35; cursor: pointer; } .user-menu-item:hover:not([aria-disabled="true"]), .user-menu-item:focus-visible { background: var(--surface-sunk); } .user-menu-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; } @@ -4107,18 +4096,18 @@ tr.is-menu-open { background: var(--surface-alt); } .user-menu-item.is-danger:hover:not([aria-disabled="true"]), .user-menu-item.is-danger:focus-visible { background: color-mix(in srgb, var(--red) 10%, transparent); } .user-menu-item[aria-disabled="true"], .user-menu-item[aria-disabled="true"] .user-menu-ic { color: var(--text-subtle); cursor: not-allowed; } -.user-menu-trenner { border: 0; border-top: 1px solid var(--line-soft); margin: 5px 4px; } -.user-menu-confirm { padding: 10px 10px 8px; display: grid; gap: 10px; } +.user-menu-trenner { border: 0; border-top: 1px solid var(--line-soft); margin: 4px 4px; } +.user-menu-confirm { padding: 12px 12px 8px; display: grid; gap: 8px; } .user-menu-confirm p { margin: 0; font-size: 13px; line-height: 1.4; } .user-menu-confirm-row { display: flex; gap: 6px; justify-content: flex-end; } -.badge-active { color: var(--green); font-weight: 600; } +.badge-active { color: var(--green); font-weight: 500; } .badge-inactive { color: var(--text-muted); } -.badge-warn { color: var(--amber); font-weight: 600; } +.badge-warn { color: var(--amber); font-weight: 500; } /* Das einmalig angezeigte Passwort laesst sich mit einem Klick markieren. */ #generatedPasswordBox { display: none; - margin-bottom: 14px; - padding: 12px 14px; + margin-bottom: 12px; + padding: 12px 16px; border-radius: var(--r-md); background: var(--surface-alt); border: 1px solid var(--line-soft); @@ -4135,14 +4124,14 @@ tr.is-menu-open { background: var(--surface-alt); } grid-column: 1 / -1; margin-top: 12px; border-top: 1px solid var(--line-soft); - padding-top: 10px; + padding-top: 12px; } .timeline-block > summary { display: flex; align-items: center; gap: 8px; cursor: pointer; - font-size: 12.5px; + font-size: 13px; color: var(--text-muted); list-style: none; user-select: none; @@ -4155,13 +4144,13 @@ tr.is-menu-open { background: var(--surface-alt); } .timeline-block > summary:hover { color: var(--text); } .timeline-block[open] > summary .comment-history-caret { transform: rotate(90deg); } -.timeline-body { padding-top: 10px; } +.timeline-body { padding-top: 12px; } /* Die Schiene scrollt waagerecht; die Karte selbst darf dabei nicht breiter werden, deshalb min-width:0 am Elternraster (siehe .board-drawer). */ .timeline-rail { display: flex; - gap: 10px; + gap: 8px; overflow-x: auto; padding-bottom: 6px; scroll-snap-type: x proximity; @@ -4172,7 +4161,7 @@ tr.is-menu-open { background: var(--surface-alt); } display: flex; flex-direction: column; gap: 6px; - padding: 10px 11px; + padding: 12px 12px; border: 1px solid var(--line-soft); border-radius: var(--r-md); background: var(--surface-alt); @@ -4184,7 +4173,7 @@ tr.is-menu-open { background: var(--surface-alt); } justify-content: space-between; gap: 6px; } -.timeline-kw { font-weight: 600; white-space: nowrap; } +.timeline-kw { font-weight: 500; white-space: nowrap; } .timeline-datum { color: var(--text-muted); font-size: 11px; white-space: nowrap; } /* Der Kommentar wird auf sechs Zeilen begrenzt, damit alle Kacheln einer @@ -4201,11 +4190,11 @@ tr.is-menu-open { background: var(--surface-alt); } .timeline-text p { margin: 0; } /* Gewerk über dem Kommentar: Systemtext, nicht Teil des Kommentars. */ .kommentar-gewerk { - font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; + font-size: 11px; font-weight: 600; letter-spacing: 0; color: var(--text-subtle); margin-top: 4px; } .kommentar-gewerk:first-child { margin-top: 0; } -.timeline-leer { color: var(--text-muted); font-style: italic; } +.timeline-leer { color: var(--text-muted); font-style: normal; } .timeline-lph-list { display: flex; flex-direction: column; gap: 1px; } .timeline-lph { @@ -4216,12 +4205,12 @@ tr.is-menu-open { background: var(--surface-alt); } color: var(--text-muted); } .timeline-termine { display: flex; flex-direction: column; gap: 1px; } -.timeline-termin { color: var(--text-muted); font-size: 11.5px; } +.timeline-termin { color: var(--text-muted); font-size: 12px; } /* Gegenüber der Kachel DAVOR geänderte Werte. Dezent, aber auffindbar: Bei zehn Leistungsphasen findet man die eine geänderte Zahl sonst nicht. */ .timeline-lph.is-changed, -.timeline-termin.is-changed { color: var(--accent); font-weight: 600; } +.timeline-termin.is-changed { color: var(--accent); font-weight: 500; } /* "übernehmen" in der Verlaufs-Kachel: übernimmt die einzige Funktion, die der entfallene Aufklapper "Frühere Sitzungen" über das Anzeigen hinaus @@ -4231,11 +4220,11 @@ tr.is-menu-open { background: var(--surface-alt); } align-self: flex-start; padding: 1px 8px; border: 1px solid var(--line); - border-radius: var(--r-pill); + border-radius: 8px; background: transparent; color: var(--text-muted); font-family: inherit; - font-size: 10.5px; + font-size: 11px; cursor: pointer; } .timeline-take:hover { background: var(--accent); border-color: var(--accent); color: #fff; } @@ -4260,12 +4249,12 @@ tr.is-menu-open { background: var(--surface-alt); } .comment-foot-author .comment-av { margin-right: 4px; } .comment-foot-author .comment-sep { margin: 0 4px; } -.timeline-people { display: flex; flex-wrap: wrap; gap: 3px; margin-top: auto; padding-top: 2px; } +.timeline-people { display: flex; flex-wrap: wrap; gap: 4px; margin-top: auto; padding-top: 2px; } .timeline-chip { - font-size: 10.5px; - font-weight: 600; + font-size: 11px; + font-weight: 500; padding: 1px 6px; - border-radius: var(--r-pill); + border-radius: 6px; background: var(--surface-sunk); color: var(--text-muted); } @@ -4286,7 +4275,7 @@ tr.is-menu-open { background: var(--surface-alt); } Karten — genau wie im freigegebenen Entwurf: eine Kopfleiste mit eigenem Hintergrund/Trennlinie, darunter die Leiste als Spalte MIT dem Ergebnis verbunden (Trennlinie statt eigenem Rahmen). */ -.bericht-titelzeile { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; } +.bericht-titelzeile { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; } .bericht-titelzeile button { margin-left: auto; } .bericht-panel { @@ -4296,10 +4285,10 @@ tr.is-menu-open { background: var(--surface-alt); } .bericht-topbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; - padding: 10px 20px; border-bottom: 1px solid var(--line-soft); + padding: 12px 20px; border-bottom: 1px solid var(--line-soft); } .bericht-gewerk-select { - font-size: 12px; font-weight: 600; padding: 5px 10px; + font-size: 12px; font-weight: 500; padding: 4px 12px; /* background-color statt background (Kurzform): die Kurzform setzt das vom globalen select-Selektor gesetzte Pfeil-Icon (background-image/-repeat/ -position) auf die Vorgabewerte zurück, wodurch das 10x6px-Pfeilchen @@ -4313,23 +4302,23 @@ tr.is-menu-open { background: var(--surface-alt); } display: flex; align-items: center; justify-content: center; } .bericht-ring span { width: 18px; height: 18px; border-radius: 50%; background: var(--surface); display: block; } -.bericht-fortschritt-text { font-size: 11.5px; color: var(--text-muted); font-weight: 600; white-space: nowrap; } +.bericht-fortschritt-text { font-size: 12px; color: var(--text-muted); font-weight: 500; white-space: nowrap; } /* Reines Textlink, kein Knopf — im Entwurf steht an dieser Stelle nur der Fortschritt, nicht noch eine zusätzliche Schaltfläche daneben. */ .bericht-reset-link { - font-size: 11.5px; font-weight: 600; border: none; background: none; + font-size: 12px; font-weight: 500; border: none; background: none; color: var(--text-subtle); cursor: pointer; padding: 0; text-decoration: underline; text-decoration-color: var(--line); } .bericht-reset-link:hover { color: var(--text); } .bericht-search-btn { margin-left: auto; border: 1px solid var(--line); background: var(--surface-alt); - color: var(--text-subtle); font-size: 12px; padding: 5px 10px; - border-radius: var(--r-pill); cursor: pointer; + color: var(--text-subtle); font-size: 12px; padding: 4px 12px; + border-radius: 8px; cursor: pointer; } .bericht-search-btn:hover { color: var(--text); border-color: var(--text-subtle); } .bericht-suche-input { - margin-left: auto; border: 1px solid var(--line); border-radius: var(--r-pill); + margin-left: auto; border: 1px solid var(--line); border-radius: 8px; background: var(--surface-sunk); color: var(--text); font-size: 12px; padding: 6px 12px; width: 170px; } @@ -4337,34 +4326,34 @@ tr.is-menu-open { background: var(--surface-alt); } /* ---------- Planung (Terminplan-Sandbox, js/planung/planung.js) ---------- */ .planung-row { - display: flex; align-items: center; gap: 14px; - padding: 13px 16px; border-radius: var(--r-md); + display: flex; align-items: center; gap: 12px; + padding: 12px 16px; border-radius: var(--r-md); background: var(--surface); border: 1px solid var(--line-soft); margin-bottom: 8px; cursor: pointer; transition: background .15s var(--ease); } .planung-row:hover { background: var(--surface-alt); } .planung-row-icon { - width: 34px; height: 34px; border-radius: 9px; flex: 0 0 auto; - display: flex; align-items: center; justify-content: center; font-size: 14px; + width: 34px; height: 34px; border-radius: 8px; flex: 0 0 auto; + display: flex; align-items: center; justify-content: center; font-size: 13px; } .planung-row-icon.honorar { background: var(--accent-soft); color: var(--accent); } .planung-row-icon.leer { background: var(--surface-sunk); color: var(--text-subtle); } .planung-row-main { flex: 1; min-width: 0; } -.planung-row-name { font-size: 14px; font-weight: 600; margin: 0; } +.planung-row-name { font-size: 13px; font-weight: 500; margin: 0; } .planung-row-meta { font-size: 12px; color: var(--text-muted); margin: 2px 0 0; } .planung-row-stat { text-align: right; font-size: 12px; color: var(--text-muted); white-space: nowrap; } .planung-row-stat b { display: block; color: var(--text); font-size: 13px; font-variant-numeric: tabular-nums; } -.planung-choice-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } +.planung-choice-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } .choice-card { - border: 1.5px solid var(--line); border-radius: var(--r-md); padding: 14px 14px 12px; + border: 1.5px solid var(--line); border-radius: var(--r-md); padding: 16px 16px 12px; cursor: pointer; background: var(--surface-alt); transition: border-color .15s ease; } .choice-card:hover { border-color: var(--accent); } .choice-card.is-gewaehlt { border-color: var(--accent); } -.choice-card-icon { font-size: 18px; margin-bottom: 8px; display: block; } -.choice-card-title { font-size: 13px; font-weight: 600; margin-bottom: 3px; } -.choice-card-desc { font-size: 11.5px; color: var(--text-muted); line-height: 1.4; } +.choice-card-icon { font-size: 19px; margin-bottom: 8px; display: block; } +.choice-card-title { font-size: 13px; font-weight: 500; margin-bottom: 4px; } +.choice-card-desc { font-size: 12px; color: var(--text-muted); line-height: 1.4; } .empty-hint { text-align: center; padding: 60px 20px; color: var(--text-subtle); font-size: 13px; } .empty-hint .big { font-size: 15px; color: var(--text-muted); margin-bottom: 6px; display: block; } @@ -4384,17 +4373,17 @@ tr.is-menu-open { background: var(--surface-alt); } .pc-drop { display: block; border: 1.5px dashed var(--line); border-radius: var(--r-md); - padding: 20px 14px; text-align: center; color: var(--text-muted); - background: var(--surface-alt); cursor: pointer; font-size: 12.5px; + padding: 20px 16px; text-align: center; color: var(--text-muted); + background: var(--surface-alt); cursor: pointer; font-size: 13px; transition: border-color .15s var(--ease), color .15s var(--ease), background .15s var(--ease); } .pc-drop:hover, .pc-drop.is-dragover { border-color: var(--accent); color: var(--text); background: var(--accent-soft); } -.pc-drop-name { font-weight: 650; color: var(--text); margin-top: 4px; font-size: 13px; word-break: break-word; } +.pc-drop-name { font-weight: 500; color: var(--text); margin-top: 4px; font-size: 13px; word-break: break-word; } -.pc-section { margin-top: 18px; } -.pc-label { display: block; font-size: 11.5px; font-weight: 650; color: var(--text-muted); margin-bottom: 5px; } +.pc-section { margin-top: 16px; } +.pc-label { display: block; font-size: 12px; font-weight: 500; color: var(--text-muted); margin-bottom: 4px; } -.pc-merkmal-chip { font-size: 12.5px; padding: 5px 2px; color: var(--text-muted); } +.pc-merkmal-chip { font-size: 13px; padding: 4px 2px; color: var(--text-muted); } .pc-zusatz { margin-top: 8px; } .pc-zusatz .pc-input { width: 100%; } @@ -4406,13 +4395,13 @@ tr.is-menu-open { background: var(--surface-alt); } Pfeil-Muster, das als "komisch" auffiel, war genau das. */ .pc-select, .pc-input { border: 1px solid var(--line); border-radius: var(--r-md); background-color: var(--surface); - color: var(--text); font-size: 13px; font-family: inherit; padding: 8px 10px; + color: var(--text); font-size: 13px; font-family: inherit; padding: 8px 12px; } .pc-select:focus, .pc-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent); } .pc-btn { border: 1px solid var(--line); background: var(--surface); color: var(--text); - font-size: 13px; font-weight: 600; padding: 9px 16px; border-radius: var(--r-md); cursor: pointer; + font-size: 13px; font-weight: 500; padding: 8px 16px; border-radius: var(--r-md); cursor: pointer; } .pc-btn:hover { background: var(--surface-alt); } .pc-btn:disabled { opacity: .6; cursor: default; } @@ -4422,21 +4411,21 @@ tr.is-menu-open { background: var(--surface-alt); } .pc-verdict { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; - width: 20px; height: 20px; border-radius: 50%; font-size: 12px; font-weight: 700; color: #fff; + width: 20px; height: 20px; border-radius: 50%; font-size: 12px; font-weight: 600; color: #fff; } .pc-verdict.ok { background: var(--green); } .pc-verdict.fail { background: var(--red); } .pc-results { min-height: 420px; display: flex; flex-direction: column; } .pc-results-empty { margin: auto; text-align: center; color: var(--text-subtle); padding: 40px 20px; } -.pc-results-empty .big { font-size: 14px; color: var(--text-muted); margin-bottom: 4px; display: block; } -.pc-result-head { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; padding-bottom: 14px; border-bottom: 1px solid var(--line-soft); flex-wrap: wrap; } -.pc-result-head .filename { font-weight: 650; } +.pc-results-empty .big { font-size: 13px; color: var(--text-muted); margin-bottom: 4px; display: block; } +.pc-result-head { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; padding-bottom: 16px; border-bottom: 1px solid var(--line-soft); flex-wrap: wrap; } +.pc-result-head .filename { font-weight: 500; } .pc-result-head .meta { color: var(--text-subtle); font-size: 12px; margin-left: auto; } .pc-result-row { display: flex; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line-soft); } .pc-result-row:last-child { border-bottom: none; } -.pc-result-row .titel { font-weight: 650; margin-bottom: 2px; font-size: 13px; } -.pc-result-row .begruendung { color: var(--text-muted); font-size: 12.5px; } +.pc-result-row .titel { font-weight: 500; margin-bottom: 2px; font-size: 13px; } +.pc-result-row .begruendung { color: var(--text-muted); font-size: 13px; } .pc-result-text { flex: 1 1 auto; min-width: 0; } /* pc-result-shot: Screenshot des Planausschnitts, den die KI für das Merkmal als Beleg gewählt hat (server.js, pruefePlanMitKI(), bildIndex) — nur @@ -4462,22 +4451,22 @@ tr.is-menu-open { background: var(--surface-alt); } .bericht-rail { background: var(--surface-alt); border-right: 1px solid var(--line-soft); - padding: 10px 8px; display: flex; flex-direction: column; gap: 2px; + padding: 12px 8px; display: flex; flex-direction: column; gap: 2px; position: sticky; top: 64px; max-height: calc(100vh - 64px); overflow-y: auto; } .bericht-rail-gruppe { - font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; - color: var(--text-subtle); padding: 12px 8px 5px; + font-size: 11px; font-weight: 600; letter-spacing: 0; + color: var(--text-subtle); padding: 12px 8px 4px; } .bericht-rail-gruppe:first-child { padding-top: 2px; } .bericht-rail-item { position: relative; display: flex; align-items: center; gap: 8px; - padding: 6px 8px; border-radius: var(--r-sm); cursor: pointer; color: var(--text); font-size: 12.5px; + padding: 6px 8px; border-radius: var(--r-sm); cursor: pointer; color: var(--text); font-size: 13px; } .bericht-rail-item:hover { background: var(--surface-sunk); } .bericht-rail-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; } .bericht-rail-item.is-aktiv { background: var(--accent-soft); } -.bericht-rail-item.is-aktiv .bericht-rail-name { color: var(--accent); font-weight: 650; } +.bericht-rail-item.is-aktiv .bericht-rail-name { color: var(--accent); font-weight: 500; } /* Abgehakt: zurückgenommen, aber erkennbar — man muss im Meeting noch sehen können, was man schon besprochen hat. */ .bericht-rail-item.is-ab { opacity: .55; } @@ -4492,19 +4481,19 @@ tr.is-menu-open { background: var(--surface-alt); } neben der Leiste (Eriks Wunsch). Früher hielt max-width: 640px sie als schmale Lesespalte — auf breiten Monitoren blieb dabei die halbe Fläche leer. */ -.bericht-main { padding: 26px 36px 30px; min-width: 0; } +.bericht-main { padding: 28px 36px 32px; min-width: 0; } -.bericht-head-line { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; } +.bericht-head-line { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; } .bericht-head-nr { - font-family: ui-monospace, 'SF Mono', monospace; font-size: 11.5px; + font-family: ui-monospace, 'SF Mono', monospace; font-size: 12px; color: var(--text-subtle); } .bericht-change-pill { - font-size: 10.5px; font-weight: 700; color: #fff; padding: 2px 9px; border-radius: var(--r-pill); + font-size: 11px; font-weight: 600; color: #fff; padding: 2px 8px; border-radius: 6px; } .bericht-change-pill.is-new, .bericht-change-pill.is-status { background: var(--band-neu); } .bericht-change-pill.is-progress { background: var(--band-fortschritt); } -.bericht-h1 { font-size: 21px; font-weight: 650; letter-spacing: -0.012em; margin: 0 0 3px; } +.bericht-h1 { font-size: 19px; font-weight: 500; letter-spacing: 0; margin: 0 0 4px; } .bericht-sub { color: var(--text-subtle); font-size: 12px; margin-bottom: 16px; } .bericht-abwesend-hinweis { @@ -4519,30 +4508,30 @@ tr.is-menu-open { background: var(--surface-alt); } Bildsprache wie der Verlauf im Projekt-Dashboard (.plan-verlauf-*). */ .bericht-zuletzt { background: var(--surface-sunk); border-radius: var(--r-md); - padding: 8px 12px; margin-bottom: 14px; font-size: 12.5px; line-height: 1.5; color: var(--text-muted); + padding: 8px 12px; margin-bottom: 12px; font-size: 13px; line-height: 1.5; color: var(--text-muted); } -.bericht-zuletzt-kw { display: block; font-size: 11px; font-weight: 650; color: var(--text); margin-bottom: 2px; } +.bericht-zuletzt-kw { display: block; font-size: 11px; font-weight: 500; color: var(--text); margin-bottom: 2px; } /* Lange Kommentare nicht endlos: höchstens fünf Zeilen, der Rest steht im Verlauf. */ .bericht-zuletzt-text { max-height: calc(1.5em * 5); overflow: hidden; overflow-wrap: anywhere; } .bericht-zuletzt-text p { margin: 0; } .bericht-verlauf { margin-top: 24px; padding-top: 16px; border-top: 1px solid var(--line-soft); } .bv-kopf { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; } -.bv-titel { font-size: 15px; font-weight: 650; margin: 0; color: var(--text); } +.bv-titel { font-size: 15px; font-weight: 500; margin: 0; color: var(--text); } .bv-anzahl { font-size: 12px; color: var(--text-subtle); } .bv-mehr, .bv-uebernehmen { - border: 0; background: transparent; font: inherit; font-size: 12px; font-weight: 600; + border: 0; background: transparent; font: inherit; font-size: 12px; font-weight: 500; color: var(--accent); cursor: pointer; padding: 4px 8px; border-radius: var(--r-md); } .bv-mehr:hover, .bv-uebernehmen:hover { background: var(--surface-alt); } .bv-liste { list-style: none; margin: 0; padding: 0; } .bv-zeile { display: grid; grid-template-columns: 120px 14px minmax(0, 1fr) minmax(0, 220px) auto; - column-gap: 14px; align-items: start; padding: 10px 0; + column-gap: 12px; align-items: start; padding: 12px 0; } .bv-kw { display: flex; flex-direction: column; gap: 1px; min-width: 0; } .bv-kw b { font-size: 13px; color: var(--text); } -.bv-kw span { font-size: 11.5px; color: var(--text-subtle); } +.bv-kw span { font-size: 12px; color: var(--text-subtle); } /* Punkt und Linie: die Linie läuft von Punkt zu Punkt über den Zeilenabstand */ .bv-punkt { position: relative; align-self: stretch; } .bv-punkt::before { @@ -4554,13 +4543,13 @@ tr.is-menu-open { background: var(--surface-alt); } content: ""; position: absolute; left: 6px; top: 16px; bottom: -14px; width: 2px; background: var(--line); } .bv-zeile:last-child .bv-punkt::after { display: none; } -.bv-inhalt { display: flex; flex-direction: column; gap: 3px; min-width: 0; } -.bv-text { font-size: 13.5px; line-height: 1.5; color: var(--text); overflow-wrap: anywhere; } +.bv-inhalt { display: flex; flex-direction: column; gap: 4px; min-width: 0; } +.bv-text { font-size: 13px; line-height: 1.5; color: var(--text); overflow-wrap: anywhere; } .bv-text p { margin: 0; } -.bv-ruhe { font-size: 11.5px; color: var(--text-subtle); } +.bv-ruhe { font-size: 12px; color: var(--text-subtle); } .bv-chips { display: flex; flex-wrap: wrap; gap: 4px; } .bv-chip { - font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px; white-space: nowrap; + font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: 6px; white-space: nowrap; background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--accent); } .bv-uebernehmen { justify-self: end; } @@ -4571,10 +4560,10 @@ tr.is-menu-open { background: var(--surface-alt); } .bv-chips:empty { display: none; } } -.bericht-detail-fuss { display: flex; align-items: center; gap: 14px; margin-top: 20px; } +.bericht-detail-fuss { display: flex; align-items: center; gap: 12px; margin-top: 20px; } .bericht-fuss-spacer { flex: 1; } -.person-chip-label { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; } +.person-chip-label { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; } .protokoll-text { width: 100%; font-family: ui-monospace, 'SF Mono', monospace; font-size: 12px; line-height: 1.5; resize: vertical; @@ -4592,7 +4581,7 @@ tr.is-menu-open { background: var(--surface-alt); } .leistung-kpis { display: flex; flex-wrap: wrap; - gap: 10px; + gap: 8px; margin-bottom: 12px; } .leistung-kpi { @@ -4601,7 +4590,7 @@ tr.is-menu-open { background: var(--surface-alt); } gap: 2px; flex: 1 1 160px; min-width: 150px; - padding: 10px 12px; + padding: 12px 12px; background: var(--surface-alt); border: 1px solid var(--line-soft); border-radius: var(--r-md); @@ -4610,18 +4599,17 @@ tr.is-menu-open { background: var(--surface-alt); } font-size: 11px; font-weight: 500; color: var(--text-muted); - text-transform: uppercase; - letter-spacing: .03em; + letter-spacing: 0; } .leistung-kpi-value { font-size: 19px; - font-weight: 600; + font-weight: 500; font-variant-numeric: tabular-nums; line-height: 1.2; } .leistung-kpi-value.accent { color: var(--accent); } .leistung-kpi-sub { - font-size: 11.5px; + font-size: 12px; color: var(--text-subtle); font-variant-numeric: tabular-nums; } @@ -4634,7 +4622,7 @@ tr.is-menu-open { background: var(--surface-alt); } border-radius: var(--r-pill); background: var(--surface-sunk); overflow: hidden; - margin: 0 0 14px; + margin: 0 0 12px; } .leistung-balken > span { display: block; @@ -4644,15 +4632,15 @@ tr.is-menu-open { background: var(--surface-alt); } transition: width .25s var(--ease); } -.leistung-table { font-size: 12.5px; } +.leistung-table { font-size: 13px; } .leistung-table th.num, .leistung-table td.num { text-align: right; font-variant-numeric: tabular-nums; } -.leistung-table td.strong { font-weight: 600; } +.leistung-table td.strong { font-weight: 500; } .leistung-table tfoot th, .leistung-table tfoot td { border-top: 1px solid var(--line); padding: 6px 8px; - font-weight: 600; + font-weight: 500; background: var(--surface-alt); } @@ -4660,9 +4648,9 @@ tr.is-menu-open { background: var(--surface-alt); } beauftragte Phase, keine Anteile). Bewusst als Text und nicht als "0 EUR": unbekannt ist nicht dasselbe wie nichts erbracht. */ .leistung-leer { - font-size: 12.5px; + font-size: 13px; color: var(--text-muted); - padding: 10px 12px; + padding: 12px 12px; background: var(--surface-alt); border-left: 2px solid var(--amber); border-radius: 0 var(--r-sm) var(--r-sm) 0; @@ -4678,7 +4666,7 @@ tr.is-menu-open { background: var(--surface-alt); } .auftrag-chip { display: inline-flex; align-items: center; - border-radius: var(--r-pill); + border-radius: 6px; padding: 1px 8px; font-size: 11px; font-weight: 500; @@ -4720,7 +4708,7 @@ tr.is-menu-open { background: var(--surface-alt); } .sitzung-chip { display: inline-flex; align-items: center; - border-radius: var(--r-pill); + border-radius: 6px; padding: 1px 8px; font-size: 11px; font-weight: 500; @@ -4778,16 +4766,16 @@ tr.is-menu-open { background: var(--surface-alt); } display: flex; flex-wrap: wrap; align-items: center; - gap: 10px; + gap: 8px; padding: 8px 2px 2px; } .plan-verweis{ background: none; border: 1px solid var(--line); - border-radius: var(--r-pill); - padding: 3px 12px; + border-radius: 8px; + padding: 4px 12px; font-size: 12px; - font-weight: 600; + font-weight: 500; color: var(--accent); cursor: pointer; } @@ -4831,7 +4819,7 @@ tr.is-menu-open { background: var(--surface-alt); } .plan-verweis-row{ display: flex; justify-content: flex-end; - padding-top: 10px; + padding-top: 12px; } .plan-verweis-row:empty{ display: none; } @@ -4859,19 +4847,18 @@ tr.is-menu-open { background: var(--surface-alt); } .fristen-gruppe-titel { display: flex; align-items: center; - gap: 9px; - padding: 9px 16px 6px; + gap: 8px; + padding: 8px 16px 6px; background: var(--surface-alt); - font-size: 10.5px; - font-weight: 600; - letter-spacing: .06em; - text-transform: uppercase; + font-size: 11px; + font-weight: 500; + letter-spacing: 0; color: var(--text-muted); } .fristen-gruppe-titel span { - font-size: 10px; - padding: 1px 7px; - border-radius: var(--r-pill); + font-size: 11px; + padding: 1px 8px; + border-radius: 6px; background: var(--surface-sunk); color: var(--text-muted); letter-spacing: 0; @@ -4889,8 +4876,8 @@ tr.is-menu-open { background: var(--surface-alt); } .fristen-zeile { display: flex; align-items: center; - gap: 14px; - padding: 9px 16px; + gap: 12px; + padding: 8px 16px; border-bottom: 1px solid var(--line-soft); text-decoration: none; color: inherit; @@ -4910,7 +4897,7 @@ tr.is-menu-open { background: var(--surface-alt); } line-height: 1.25; font-variant-numeric: tabular-nums; } -.fristen-datum b { font-size: 13px; font-weight: 600; } +.fristen-datum b { font-size: 13px; font-weight: 500; } .fristen-datum em { font-style: normal; font-size: 11px; @@ -4922,10 +4909,10 @@ tr.is-menu-open { background: var(--surface-alt); } .fristen-art { flex: 0 0 auto; - font-size: 10px; - font-weight: 600; + font-size: 11px; + font-weight: 500; padding: 2px 8px; - border-radius: var(--r-pill); + border-radius: 6px; background: var(--surface-sunk); color: var(--text-muted); white-space: nowrap; @@ -4938,7 +4925,7 @@ tr.is-menu-open { background: var(--surface-alt); } .fristen-titel { flex: 1 1 auto; min-width: 0; - font-size: 13.5px; + font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; @@ -4997,14 +4984,14 @@ tr.is-menu-open { background: var(--surface-alt); } display: flex; align-items: center; gap: 12px; - padding: 18px 24px 14px; + padding: 20px 24px 16px; border-bottom: 1px solid var(--line-soft); } .wiz-kopf h2 { margin: 0; flex: 1; } .wiz-schliessen { - font-size: 20px; + font-size: 19px; line-height: 1; - padding: 2px 9px; + padding: 2px 8px; background: none; border: none; color: var(--text-subtle); @@ -5033,12 +5020,12 @@ tr.is-menu-open { background: var(--surface-alt); } display: grid; place-items: center; font-size: 11px; - font-weight: 600; + font-weight: 500; background: var(--surface-sunk); color: var(--text-muted); font-variant-numeric: tabular-nums; } -.wiz-stufe.ist-aktiv { color: var(--text); font-weight: 600; } +.wiz-stufe.ist-aktiv { color: var(--text); font-weight: 500; } .wiz-stufe.ist-aktiv b { background: var(--accent); color: #fff; } .wiz-stufe.ist-fertig b { background: var(--green); color: #fff; } .wiz-strich { @@ -5050,12 +5037,12 @@ tr.is-menu-open { background: var(--surface-alt); } } .wiz-inhalt { - padding: 20px 24px 22px; + padding: 20px 24px 24px; min-height: 300px; max-height: 58vh; overflow-y: auto; } -.wiz-titel { margin: 0 0 3px; font-size: 19px; font-weight: 600; letter-spacing: -.02em; } +.wiz-titel { margin: 0 0 4px; font-size: 19px; font-weight: 500; letter-spacing: 0; } .wiz-unter { margin: 0 0 20px; font-size: 13px; color: var(--text-muted); } .wiz-zeile { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } .wiz-pflicht { color: var(--red); } @@ -5067,7 +5054,7 @@ tr.is-menu-open { background: var(--surface-alt); } display: flex; align-items: center; gap: 12px; - padding: 14px 24px; + padding: 16px 24px; border-top: 1px solid var(--line-soft); background: var(--surface-alt); } @@ -5080,38 +5067,38 @@ tr.is-menu-open { background: var(--surface-alt); } flex-wrap: wrap; justify-content: flex-end; } -.wiz-fehlt { font-size: 11.5px; color: var(--amber); text-align: right; } +.wiz-fehlt { font-size: 12px; color: var(--amber); text-align: right; } /* Auswahl-Chips (Gewerke, Phasen, Schlagwörter, Grundlage) */ .wiz-chips { display: flex; flex-wrap: wrap; gap: 6px; } .wiz-chip { font: inherit; font-size: 12px; - padding: 5px 11px; + padding: 4px 12px; cursor: pointer; border: 1px solid var(--line); - border-radius: var(--r-pill); + border-radius: 6px; background: var(--surface); color: var(--text-muted); } .wiz-chip:hover { border-color: var(--accent); background: var(--surface); } .wiz-chip[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; } -.wiz-chip-gewerk { font-weight: 600; letter-spacing: .02em; padding: 6px 14px; } +.wiz-chip-gewerk { font-weight: 500; letter-spacing: .02em; padding: 6px 16px; } /* Beteiligte je Rolle */ .wiz-rollen { display: flex; flex-direction: column; gap: 12px; } .wiz-rolle { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; } .wiz-rolle-name { flex: 0 0 116px; - font-size: 11.5px; - font-weight: 600; - padding-top: 7px; + font-size: 12px; + font-weight: 500; + padding-top: 8px; color: var(--text-muted); } .wiz-person { font: inherit; font-size: 11px; - font-weight: 600; + font-weight: 500; cursor: pointer; width: 34px; height: 34px; border-radius: 50%; @@ -5130,20 +5117,20 @@ tr.is-menu-open { background: var(--surface-alt); } .wiz-fremd { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line-soft); } .wiz-fremd label { display: block; - font-size: 11.5px; - font-weight: 600; + font-size: 12px; + font-weight: 500; margin-bottom: 6px; color: var(--text-muted); } .wiz-fremd select { width: 100%; max-width: 420px; } -.wiz-fremd-liste { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; } +.wiz-fremd-liste { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } .wiz-fremd-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; - padding: 3px 6px 3px 10px; - border-radius: var(--r-pill); + padding: 4px 6px 4px 12px; + border-radius: 6px; border: 1px dashed var(--line); color: var(--text-muted); } @@ -5161,16 +5148,16 @@ tr.is-menu-open { background: var(--surface-alt); } /* Hinweis anstelle eines Schritts, der gerade nicht möglich ist */ .wiz-sperre { - padding: 18px 20px; + padding: 20px 20px; border: 1px dashed var(--line); border-radius: var(--r-lg); background: var(--surface-alt); } -.wiz-sperre b { display: block; font-size: 14px; margin-bottom: 6px; } +.wiz-sperre b { display: block; font-size: 13px; margin-bottom: 6px; } .wiz-sperre p { margin: 0 0 8px; font-size: 13px; color: var(--text-muted); max-width: 58ch; } .wiz-sperre p:last-child { margin-bottom: 0; } -.wiz-schalter { display: flex; align-items: center; gap: 9px; font-size: 13.5px; cursor: pointer; } +.wiz-schalter { display: flex; align-items: center; gap: 8px; font-size: 13px; cursor: pointer; } .wiz-schalter input { width: 16px; height: 16px; accent-color: var(--accent); } /* Terminplan-Tabelle */ @@ -5183,9 +5170,9 @@ tr.is-menu-open { background: var(--surface-alt); } .wiz-plan-zeile { display: grid; grid-template-columns: 78px 62px 1fr 64px 170px; - gap: 10px; - padding: 7px 12px; - font-size: 12.5px; + gap: 8px; + padding: 8px 12px; + font-size: 13px; border-bottom: 1px solid var(--line-soft); font-variant-numeric: tabular-nums; } @@ -5195,27 +5182,26 @@ tr.is-menu-open { background: var(--surface-alt); } .wiz-plan-zeile span:nth-child(4) { text-align: right; } .wiz-plan-kopf { background: var(--surface-alt); - font-size: 10.5px; - font-weight: 600; - letter-spacing: .05em; - text-transform: uppercase; + font-size: 11px; + font-weight: 500; + letter-spacing: 0; color: var(--text-subtle); } -.wiz-plan-summe { background: var(--surface-alt); font-weight: 600; } +.wiz-plan-summe { background: var(--surface-alt); font-weight: 500; } /* Zusammenfassung */ -.wiz-pruef { font-size: 13.5px; } +.wiz-pruef { font-size: 13px; } .wiz-pruef-zeile { display: flex; justify-content: space-between; - gap: 18px; - padding: 7px 0; + gap: 16px; + padding: 8px 0; border-bottom: 1px solid var(--line-soft); } .wiz-pruef-zeile:last-child { border-bottom: none; } .wiz-pruef-zeile span { color: var(--text-muted); flex: 0 0 auto; } .wiz-pruef-zeile b { font-weight: 500; text-align: right; min-width: 0; overflow-wrap: anywhere; } -.wiz-pruef-zeile b.fehlt { color: var(--text-subtle); font-weight: 400; font-style: italic; } +.wiz-pruef-zeile b.fehlt { color: var(--text-subtle); font-weight: 400; font-style: normal; } /* Abschluss */ .wiz-fertig { text-align: center; padding: 44px 24px; } @@ -5229,8 +5215,8 @@ tr.is-menu-open { background: var(--surface-alt); } background: var(--green); color: #fff; } -.wiz-fertig h3 { margin: 0 0 8px; font-size: 20px; font-weight: 600; } -.wiz-fertig p { margin: 0 auto 20px; color: var(--text-muted); max-width: 46ch; font-size: 13.5px; } +.wiz-fertig h3 { margin: 0 0 8px; font-size: 19px; font-weight: 500; } +.wiz-fertig p { margin: 0 auto 20px; color: var(--text-muted); max-width: 46ch; font-size: 13px; } @media (max-width: 760px) { .wiz-zeile { grid-template-columns: 1fr; } @@ -5406,17 +5392,17 @@ html[data-theme="dark"] .login-seite { --login-zahl: #4f7695; --login-jahr: var( position: relative; z-index: 1; width: 100%; max-width: 1180px; min-height: 100%; margin: 0 auto; display: grid; grid-template-columns: minmax(0, 400px) minmax(0, 1fr); - gap: clamp(32px, 7vw, 110px); align-items: center; + gap: clamp(32px, 7vw, 108px); align-items: center; padding-block: calc(48px + env(safe-area-inset-top, 0px)) calc(48px + env(safe-area-inset-bottom, 0px)); } .login-titel { margin: 0 0 6px; font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-weight: 500; font-size: 30px; letter-spacing: -.01em; } -.login-unter { margin: 0 0 30px; color: var(--text-muted); } +.login-unter { margin: 0 0 28px; color: var(--text-muted); } -.login-form { display: grid; gap: 18px; } -.login-feld { display: grid; gap: 7px; } -.login-feld label { font-size: 13.5px; font-weight: 600; color: var(--text); } +.login-form { display: grid; gap: 16px; } +.login-feld { display: grid; gap: 8px; } +.login-feld label { font-size: 13.5px; font-weight: 500; color: var(--text); } .login-feld input { - width: 100%; box-sizing: border-box; min-height: 46px; padding: 11px 13px; + width: 100%; box-sizing: border-box; min-height: 46px; padding: 12px 12px; font: inherit; font-size: 15px; color: var(--text); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); transition: border-color var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out); @@ -5428,18 +5414,18 @@ html[data-theme="dark"] .login-seite { --login-zahl: #4f7695; --login-jahr: var( .login-pw input { padding-right: 96px; } .login-pw-toggle { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); - font: inherit; font-size: 12.5px; font-weight: 600; color: var(--accent); - background: transparent; border: 0; border-radius: var(--r-md); padding: 7px 10px; cursor: pointer; + font: inherit; font-size: 12.5px; font-weight: 500; color: var(--accent); + background: transparent; border: 0; border-radius: var(--r-md); padding: 8px 12px; cursor: pointer; } .login-pw-toggle:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); } .login-pw-toggle:focus-visible, .login-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } -.login-caps { margin: 0; font-size: 12.5px; font-weight: 600; color: var(--amber); } +.login-caps { margin: 0; font-size: 12.5px; font-weight: 500; color: var(--amber); } .login-fehler { - margin: 0; padding: 10px 12px; border-radius: var(--r-lg); font-size: 13.5px; line-height: 1.45; + margin: 0; padding: 12px 12px; border-radius: var(--r-lg); font-size: 13.5px; line-height: 1.45; color: var(--red); background: color-mix(in srgb, var(--red) 10%, transparent); } .login-btn { - display: inline-flex; align-items: center; justify-content: center; gap: 10px; + display: inline-flex; align-items: center; justify-content: center; gap: 8px; width: 100%; min-height: 48px; margin-top: 4px; font: inherit; font-size: 15px; font-weight: 650; color: #fff; background: var(--accent); border: 0; border-radius: var(--r-lg); cursor: pointer; @@ -5457,7 +5443,7 @@ html[data-theme="dark"] .login-btn { color: #0b1c26; } } .login-btn.laedt .login-spinner { display: block; } @keyframes login-dreh { to { transform: rotate(360deg); } } -.login-hilfe { margin: 18px 0 0; font-size: 13px; color: var(--text-muted); } +.login-hilfe { margin: 16px 0 0; font-size: 13px; color: var(--text-muted); } .login-woche { justify-self: end; text-align: right; animation: login-auf .7s var(--ease-out) both; } @keyframes login-auf { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } } @@ -5465,21 +5451,21 @@ html[data-theme="dark"] .login-btn { color: #0b1c26; } .login-kw-label { display: block; font-weight: 500; font-size: 22px; color: var(--text-muted); letter-spacing: .02em; } .login-kw-zahl { display: block; font-weight: 300; font-size: clamp(150px, 21vw, 300px); line-height: .86; - letter-spacing: -.05em; color: var(--login-zahl); font-variant-numeric: tabular-nums; + letter-spacing: 0; color: var(--login-zahl); font-variant-numeric: tabular-nums; } .login-kw-jahr { display: block; font-weight: 500; font-size: 20px; color: var(--login-jahr); } -.login-tage { list-style: none; margin: 30px 0 0; padding: 0; display: flex; gap: 8px; justify-content: flex-end; } +.login-tage { list-style: none; margin: 28px 0 0; padding: 0; display: flex; gap: 8px; justify-content: flex-end; } .login-tage li { - display: grid; justify-items: center; gap: 2px; width: 58px; padding: 10px 0 9px; + display: grid; justify-items: center; gap: 2px; width: 58px; padding: 12px 0 8px; border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line); } -.login-tage li span { font-size: 12px; font-weight: 600; color: var(--text-muted); } +.login-tage li span { font-size: 12px; font-weight: 500; color: var(--text-muted); } .login-tage li b { font-weight: 500; font-size: 20px; font-variant-numeric: tabular-nums; } .login-tage li.ist-heute { background: var(--accent); border-color: var(--accent); } .login-tage li.ist-heute span, .login-tage li.ist-heute b { color: #fff; } @media (prefers-color-scheme: dark) { html:not([data-theme="light"]) .login-tage li.ist-heute span, html:not([data-theme="light"]) .login-tage li.ist-heute b { color: #0b1c26; } } html[data-theme="dark"] .login-tage li.ist-heute span, html[data-theme="dark"] .login-tage li.ist-heute b { color: #0b1c26; } -.login-datum { margin: 18px 0 0; color: var(--text-muted); font-size: 15px; } +.login-datum { margin: 16px 0 0; color: var(--text-muted); font-size: 15px; } @media (max-width: 880px) { .login-raster { grid-template-columns: 1fr; gap: 28px; padding-block: calc(28px + env(safe-area-inset-top, 0px)) 48px; align-content: start; } @@ -5493,13 +5479,13 @@ html[data-theme="dark"] .login-tage li.ist-heute span, html[data-theme="dark"] . /* ---------- Dashboard: Meine Projekte + Monatskalender (Entwurf B) ---------- */ .dash-zonen { grid-template-columns: minmax(0, 1fr) 340px; } -.dash-proj { margin-bottom: 10px; } -.dash-proj-kopf { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; flex-wrap: wrap; padding: 12px 16px 4px; } -.dash-proj-kopf { align-items: center; padding-bottom: 10px; } -.dash-proj.ist-zu .dash-proj-kopf { padding-top: 10px; } +.dash-proj { margin-bottom: 8px; } +.dash-proj-kopf { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; flex-wrap: wrap; padding: 12px 16px 4px; } +.dash-proj-kopf { align-items: center; padding-bottom: 12px; } +.dash-proj.ist-zu .dash-proj-kopf { padding-top: 12px; } .dash-proj-toggle { flex: 1 1 260px; min-width: 0; display: flex; align-items: baseline; gap: 0; padding: 0; border: 0; background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer; } .dash-proj-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-sm); } -.dash-proj-titel { font-weight: 650; font-size: 14px; } +.dash-proj-titel { font-weight: 500; font-size: 13px; } /* Die allgemeine Knopfregel (button:hover → Akzentfläche, :active → Stauchen) ist spezifischer als eine einzelne Klasse und färbte den Projektkopf beim Zeigen blau ein — der Titel verschwand darin. Diese @@ -5517,51 +5503,53 @@ button.dash-kal-nav:active, button.dash-kal-tag:active { transform: none; } .dash-proj-toggle:hover .dash-proj-titel, .dash-proj-toggle:hover .dash-proj-chev { color: var(--accent); } button.dash-proj-alle:hover { text-decoration: underline; } -.dash-proj-chev { display: inline-block; width: 16px; margin-right: 6px; font-size: 17px; line-height: 1; text-align: center; color: var(--text-subtle); transform: rotate(90deg); transition: transform var(--dur, 150ms) var(--ease-out, ease); } +.dash-proj-chev { display: inline-block; width: 16px; margin-right: 6px; font-size: 19px; line-height: 1; text-align: center; color: var(--text-subtle); transform: rotate(90deg); transition: transform var(--dur, 150ms) var(--ease-out, ease); } .dash-proj.ist-zu .dash-proj-chev { transform: rotate(0deg); } .dash-proj.ist-zu .dash-proj-inhalt { display: none; } .dash-proj-kurz { display: none; gap: 6px; } .dash-proj.ist-zu .dash-proj-kurz { display: flex; } -.dash-proj-zahl { font-size: 10.5px; padding: 1px 7px; border-radius: var(--r-pill); background: var(--surface-sunk); color: var(--text-muted); white-space: nowrap; } -.dash-proj-zahl.ist-rot { background: color-mix(in srgb, var(--red) 12%, transparent); color: var(--red); font-weight: 600; } -.dash-proj-oeffnen { font-size: 11.5px; color: var(--accent); text-decoration: none; } +.dash-proj-zahl { font-size: 11px; padding: 1px 8px; border-radius: 6px; background: var(--surface-sunk); color: var(--text-muted); white-space: nowrap; } +.dash-proj-zahl.ist-rot { background: color-mix(in srgb, var(--red) 12%, transparent); color: var(--red); font-weight: 500; } +/* Offene Aufgaben im Akzentblau (Eriks Wunsch); „0 offen“ bleibt grau. */ +.dash-proj-zahl.ist-offen { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); font-weight: 500; } +.dash-proj-oeffnen { font-size: 12px; color: var(--accent); text-decoration: none; } .dash-proj-oeffnen:hover { text-decoration: underline; } -.dash-proj-alle { margin-left: auto; padding: 2px 4px; border: 0; background: none; color: var(--accent); font: inherit; font-size: 11.5px; cursor: pointer; } +.dash-proj-alle { margin-left: auto; padding: 2px 4px; border: 0; background: none; color: var(--accent); font: inherit; font-size: 12px; cursor: pointer; } @media (prefers-reduced-motion: reduce) { .dash-proj-chev { transition: none; } } .dash-proj-nr { font-family: ui-monospace, 'SF Mono', monospace; font-size: 11px; color: var(--text-subtle); font-weight: 500; margin-right: 8px; } .dash-rollen { display: flex; gap: 4px; flex-wrap: wrap; } -.dash-rolle { font-size: 10.5px; font-weight: 600; padding: 1px 8px; border-radius: var(--r-pill); background: var(--accent-soft); color: var(--accent); } +.dash-rolle { font-size: 11px; font-weight: 500; padding: 1px 8px; border-radius: 6px; background: var(--accent-soft); color: var(--accent); } .dash-rolle.ist-neben { background: transparent; border: 1px dashed var(--line); color: var(--text-muted); } .dash-proj-sub { padding: 2px 16px 8px; } -.dash-proj-phase { display: flex; align-items: center; gap: 8px; font-size: 11.5px; color: var(--text-muted); max-width: 320px; } +.dash-proj-phase { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-muted); max-width: 320px; } .dash-proj-phase .dash-auf-bar i { background: var(--green); } .dash-proj-phase.is-leer { color: var(--text-subtle); } .dash-proj-termine { border-top: 1px solid var(--line-soft); } -.dash-proj-mehr { display: block; padding: 8px 16px; font-size: 11.5px; color: var(--accent); text-decoration: none; border-top: 1px solid var(--line-soft); } -.dash-termin { display: flex; align-items: center; gap: 10px; padding: 8px 16px; border-bottom: 1px solid var(--line-soft); color: inherit; text-decoration: none; } +.dash-proj-mehr { display: block; padding: 8px 16px; font-size: 12px; color: var(--accent); text-decoration: none; border-top: 1px solid var(--line-soft); } +.dash-termin { display: flex; align-items: center; gap: 8px; padding: 8px 16px; border-bottom: 1px solid var(--line-soft); color: inherit; text-decoration: none; } .dash-termin:last-child { border-bottom: none; } a.dash-termin:hover { background: var(--surface-sunk); } -.dash-termin-art { flex: 0 0 22px; height: 22px; border-radius: 6px; display: grid; place-items: center; font-size: 11px; font-weight: 700; background: var(--surface-sunk); color: var(--text-muted); } +.dash-termin-art { flex: 0 0 22px; height: 22px; border-radius: 6px; display: grid; place-items: center; font-size: 11px; font-weight: 600; background: var(--surface-sunk); color: var(--text-muted); } .dash-termin-art.ist-meins { background: var(--accent-soft); color: var(--accent); } .dash-termin-art.ist-ms { background: color-mix(in srgb, var(--meilenstein) 14%, transparent); color: var(--meilenstein); } .dash-termin-text { flex: 1; min-width: 0; } .dash-termin-titel { display: block; font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .dash-termin-meta { display: block; font-size: 11px; color: var(--text-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .dash-termin-datum { flex: 0 0 auto; text-align: right; font-size: 12px; font-variant-numeric: tabular-nums; } -.dash-termin-datum em { display: block; font-style: normal; font-size: 10.5px; color: var(--text-subtle); } +.dash-termin-datum em { display: block; font-style: normal; font-size: 11px; color: var(--text-subtle); } .dash-termin-datum.ist-ueberfaellig, .dash-termin-datum.ist-ueberfaellig em { color: var(--red); } .dash-termin-datum.ist-bald { color: var(--amber); } -.dash-kal { padding: 12px 14px 10px; } +.dash-kal { padding: 12px 16px 12px; } .dash-kal-kopf { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; } -.dash-kal-kopf b { font-size: 13.5px; } +.dash-kal-kopf b { font-size: 13px; } .dash-kal-nav { width: 26px; height: 26px; padding: 0; border: 1px solid var(--line); background: var(--surface); color: var(--text); border-radius: var(--r-sm); cursor: pointer; } .dash-kal-raster { display: grid; grid-template-columns: 26px repeat(7, 1fr); gap: 2px; font-variant-numeric: tabular-nums; } -.dash-kal-wt { font-size: 10.5px; color: var(--text-subtle); text-align: center; padding-bottom: 4px; } -.dash-kal-kw { font-size: 10px; color: var(--text-subtle); display: grid; place-items: center; } -.dash-kal-tag { position: relative; aspect-ratio: 1; padding: 0; border: 0; border-radius: 7px; background: transparent; color: var(--text); font: inherit; font-size: 12.5px; cursor: pointer; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; } +.dash-kal-wt { font-size: 11px; color: var(--text-subtle); text-align: center; padding-bottom: 4px; } +.dash-kal-kw { font-size: 11px; color: var(--text-subtle); display: grid; place-items: center; } +.dash-kal-tag { position: relative; aspect-ratio: 1; padding: 0; border: 0; border-radius: 8px; background: transparent; color: var(--text); font: inherit; font-size: 13px; cursor: pointer; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; } .dash-kal-tag:hover { background: var(--surface-sunk); } .dash-kal-tag.ist-fremd, .dash-kal-tag.ist-frei { color: var(--text-subtle); } -.dash-kal-tag.ist-heute { color: var(--accent); font-weight: 700; box-shadow: inset 0 0 0 1.5px var(--accent); } +.dash-kal-tag.ist-heute { color: var(--accent); font-weight: 600; box-shadow: inset 0 0 0 1.5px var(--accent); } .dash-kal-tag.ist-gewaehlt { background: var(--accent); color: var(--surface); } .dash-kal-tag:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; } .dash-kal-punkte { display: flex; gap: 2px; height: 5px; } @@ -5572,12 +5560,12 @@ i.ist-ms { background: var(--meilenstein); } i.ist-rot { background: var(--red); } i.ist-ab { background: var(--text-subtle); } .dash-kal-tag.ist-gewaehlt .dash-kal-punkte i { background: currentColor; } -.dash-kal-legende { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 8px; font-size: 10.5px; color: var(--text-muted); } -.dash-kal-legende span { display: flex; align-items: center; gap: 5px; } +.dash-kal-legende { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 8px; font-size: 11px; color: var(--text-muted); } +.dash-kal-legende span { display: flex; align-items: center; gap: 4px; } .dash-kal-liste { border-top: 1px solid var(--line-soft); } -.dash-kal-liste-titel { padding: 10px 16px 4px; font-size: 11.5px; font-weight: 600; color: var(--text-muted); } -.dash-kal-hinweis { padding: 2px 16px 6px; font-size: 11.5px; color: var(--amber); } -.dash-kal-liste .dash-termin { padding: 7px 16px; } +.dash-kal-liste-titel { padding: 12px 16px 4px; font-size: 12px; font-weight: 500; color: var(--text-muted); } +.dash-kal-hinweis { padding: 2px 16px 6px; font-size: 12px; color: var(--amber); } +.dash-kal-liste .dash-termin { padding: 8px 16px; } /* Griff zum Ändern der Spaltenbreite im GANTT (js/gantt.js). Ein breiter, unsichtbarer Greifbereich über der Spaltengrenze; sichtbar wird er erst @@ -5588,7 +5576,7 @@ i.ist-ab { background: var(--text-subtle); } } .gantt-spalten-griff::after { content: ""; position: absolute; top: 3px; bottom: 3px; left: 3px; width: 3px; - border-radius: 2px; background: var(--accent); opacity: 0; transition: opacity .15s; + border-radius: 4px; background: var(--accent); opacity: 0; transition: opacity .15s; } .gantt-spalten-griff:hover::after, .gantt-spalte-zieht .gantt-spalten-griff::after { opacity: .7; } @@ -5600,7 +5588,7 @@ i.ist-ab { background: var(--text-subtle); } #glockeBtn.hat-neue { color: var(--accent); } .glocke-zahl { position: absolute; top: -3px; right: -3px; min-width: 17px; height: 17px; padding: 0 4px; - border-radius: 999px; background: var(--red); color: #fff; font-size: 10px; font-weight: 700; + border-radius: 999px; background: var(--red); color: #fff; font-size: 11px; font-weight: 600; line-height: 17px; text-align: center; box-shadow: 0 0 0 2px var(--bg); } .glocke-menue { @@ -5609,23 +5597,23 @@ i.ist-ab { background: var(--text-subtle); } background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); box-shadow: var(--sh-3); } -.glocke-kopf { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 12px 14px 8px; position: sticky; top: 0; background: inherit; } +.glocke-kopf { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 12px 16px 8px; position: sticky; top: 0; background: inherit; } .glocke-kopf b { font-size: 13px; } -.glocke-alle { padding: 2px 4px; border: 0; background: none !important; color: var(--accent); font: inherit; font-size: 11.5px; cursor: pointer; box-shadow: none !important; } +.glocke-alle { padding: 2px 4px; border: 0; background: none !important; color: var(--accent); font: inherit; font-size: 12px; cursor: pointer; box-shadow: none !important; } .glocke-alle:hover { text-decoration: underline; } -.glocke-leer { padding: 10px 14px 16px; font-size: 12.5px; color: var(--text-subtle); line-height: 1.5; } +.glocke-leer { padding: 12px 16px 16px; font-size: 13px; color: var(--text-subtle); line-height: 1.5; } .glocke-eintrag { - display: flex; align-items: flex-start; gap: 10px; width: 100%; padding: 10px 14px; + display: flex; align-items: flex-start; gap: 8px; width: 100%; padding: 12px 16px; border: 0; border-top: 1px solid var(--line-soft); border-radius: 0; background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer; box-shadow: none; } .glocke-eintrag:hover { background: var(--surface-sunk); } .glocke-eintrag:active { transform: none; } -.glocke-punkt { flex: 0 0 8px; height: 8px; margin-top: 5px; border-radius: 50%; background: transparent; } +.glocke-punkt { flex: 0 0 8px; height: 8px; margin-top: 4px; border-radius: 50%; background: transparent; } .glocke-eintrag.ist-neu .glocke-punkt { background: var(--accent); } .glocke-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; } .glocke-titel { font-size: 13px; font-weight: 500; } -.glocke-eintrag.ist-neu .glocke-titel { font-weight: 650; } +.glocke-eintrag.ist-neu .glocke-titel { font-weight: 500; } .glocke-meta { font-size: 11px; color: var(--text-subtle); } .dash-neu .glocke-eintrag:first-child { border-top: 0; } #dashNeu:empty { display: none; } @@ -5636,7 +5624,7 @@ i.ist-ab { background: var(--text-subtle); } .glocke-aktionen { display: flex; gap: 6px; } .glocke-loeschen { flex: 0 0 34px; padding: 0; border: 0; border-radius: 0; background: none !important; box-shadow: none !important; - color: var(--text-subtle); font-size: 18px; line-height: 1; cursor: pointer; opacity: .55; + color: var(--text-subtle); font-size: 19px; line-height: 1; cursor: pointer; opacity: .55; } .glocke-zeile:hover .glocke-loeschen, .glocke-loeschen:focus-visible { opacity: 1; } .glocke-loeschen:hover { color: var(--red); } @@ -5901,47 +5889,47 @@ font[color="#b25000" i] { color: var(--rt-orange) !important; } renderLoad() in js/load/load.js). Je Person: Projektanzahl, Wert dieser Woche, zwölf Wochensäulen mit gestrichelter 100-%-Linie, Hinweis auf die Spitze und die größten Projekte. */ -.load-erklaerung { margin: 4px 0 14px; max-width: 900px; line-height: 1.5; } -.load-karten { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 14px; } +.load-erklaerung { margin: 4px 0 12px; max-width: 900px; line-height: 1.5; } +.load-karten { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 12px; } .load-karte { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); - padding: 16px 18px; display: flex; flex-direction: column; gap: 10px; min-width: 0; + padding: 16px 20px; display: flex; flex-direction: column; gap: 8px; min-width: 0; } .load-karte.ist-ohne { opacity: .75; } .load-karte-kopf { display: flex; align-items: center; gap: 12px; } .load-ava { width: 36px; height: 36px; flex: none; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; - font-size: 11.5px; font-weight: 700; background: var(--accent); color: #fff; + font-size: 12px; font-weight: 600; background: var(--accent); color: #fff; } .load-karte-wer { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; } -.load-karte-wer b { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.load-karte-wer b { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .load-karte-wer > span { font-size: 12px; color: var(--text-muted); } .load-karte-wer .load-capacity { align-self: flex-start; margin: 2px 0 0; } .load-jetzt { display: flex; flex-direction: column; align-items: flex-end; text-align: right; flex: none; } -.load-jetzt b { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.1; } +.load-jetzt b { font-size: 24px; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.1; } .load-jetzt span { font-size: 11px; color: var(--text-muted); } .load-saeulen { position: relative; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 4px; align-items: end; height: 86px; padding-top: 4px; } -.load-saeule { display: block; border-radius: 4px 4px 2px 2px; opacity: .85; min-height: 0; } +.load-saeule { display: block; border-radius: 4px 4px 4px 4px; opacity: .85; min-height: 0; } .load-saeule.ist-jetzt { opacity: 1; } .load-saeule.ist-teil { background-image: repeating-linear-gradient(135deg, transparent 0 4px, rgba(255,255,255,.35) 4px 7px); } .load-saeule.ist-abwesend { height: 100%; opacity: 1; background: repeating-linear-gradient(135deg, var(--surface-sunk) 0 5px, var(--line) 5px 10px); } .load-linie { position: absolute; left: 0; right: 0; border-top: 1.5px dashed var(--text-muted); opacity: .55; pointer-events: none; } -.load-kws { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 4px; font-size: 10px; color: var(--text-muted); text-align: center; font-variant-numeric: tabular-nums; } -.load-kws .ist-jetzt { color: var(--accent); font-weight: 700; } -.load-hinweis { font-size: 12.5px; padding: 8px 10px; border-radius: 10px; line-height: 1.4; } +.load-kws { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 4px; font-size: 11px; color: var(--text-muted); text-align: center; font-variant-numeric: tabular-nums; } +.load-kws .ist-jetzt { color: var(--accent); font-weight: 600; } +.load-hinweis { font-size: 13px; padding: 8px 12px; border-radius: 10px; line-height: 1.4; } .load-hinweis.ist-rot { background: color-mix(in srgb, var(--red) 12%, transparent); color: var(--red); } .load-hinweis.ist-gelb { background: color-mix(in srgb, var(--amber) 12%, transparent); color: var(--amber); } .load-hinweis.ist-ok { background: color-mix(in srgb, var(--green) 10%, transparent); color: var(--green); } .load-hinweis.ist-leer { background: var(--surface-sunk); color: var(--text-muted); } .load-chips { display: flex; flex-wrap: wrap; gap: 6px; } .load-chip { - display: inline-flex; align-items: center; min-height: 24px; max-width: 100%; padding: 0 9px; border-radius: 999px; - background: var(--surface-sunk); font-size: 11.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + display: inline-flex; align-items: center; min-height: 24px; max-width: 100%; padding: 0 8px; border-radius: 6px; + background: var(--surface-sunk); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.load-chip.ist-mehr { color: var(--text-muted); border: 0; font: inherit; font-size: 11.5px; cursor: pointer; } +.load-chip.ist-mehr { color: var(--text-muted); border: 0; font: inherit; font-size: 12px; cursor: pointer; } .load-chip.ist-mehr:hover { color: var(--accent); } .load-chips:not(.ist-offen) .load-chip.ist-weitere { display: none; } @media (prefers-color-scheme: dark) { html:not([data-theme="light"]) .load-ava { color: #0b141b; } } @@ -5958,41 +5946,41 @@ html[data-theme="dark"] .load-ava { color: #0b141b; } .rr-rolle { display: flex; flex-direction: column; gap: 2px; text-align: left; width: 100%; border: 1px solid var(--line); background: var(--surface); color: var(--text); - border-radius: 12px; padding: 10px 12px; font: inherit; cursor: pointer; + border-radius: 12px; padding: 12px 12px; font: inherit; cursor: pointer; } .rr-rolle:hover { border-color: var(--accent); } .rr-rolle.ist-aktiv { border-color: var(--accent); background: var(--accent-soft); } -.rr-rolle b { font-weight: 600; } +.rr-rolle b { font-weight: 500; } .rr-rolle small { color: var(--text-muted); font-size: 12px; } -.rr-balken { display: block; height: 4px; border-radius: 2px; background: var(--surface-sunk); overflow: hidden; margin-top: 4px; } +.rr-balken { display: block; height: 4px; border-radius: 4px; background: var(--surface-sunk); overflow: hidden; margin-top: 4px; } .rr-balken i { display: block; height: 100%; background: var(--accent); } .rr-plus { border: 1.5px dashed var(--line) !important; background: transparent; color: var(--accent); - border-radius: 12px; padding: 10px 12px; text-align: left; font: inherit; font-weight: 600; cursor: pointer; width: 100%; + border-radius: 12px; padding: 12px 12px; text-align: left; font: inherit; font-weight: 500; cursor: pointer; width: 100%; } .rr-plus:hover { border-color: var(--accent) !important; background: var(--accent-soft); } -.rr-neu { border: 1.5px solid var(--accent); border-radius: 12px; padding: 10px; display: flex; flex-direction: column; gap: 8px; background: var(--surface); } +.rr-neu { border: 1.5px solid var(--accent); border-radius: 12px; padding: 12px; display: flex; flex-direction: column; gap: 8px; background: var(--surface); } .rr-neu input, .rr-neu select { width: 100%; box-sizing: border-box; } .rr-neu label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--text-muted); } .rr-neu-knoepfe { display: flex; gap: 6px; } -.rr-detail { border: 1px solid var(--line); border-radius: 14px; padding: 16px; display: flex; flex-direction: column; gap: 14px; min-width: 0; } -.rr-detail-kopf { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } +.rr-detail { border: 1px solid var(--line); border-radius: 14px; padding: 16px; display: flex; flex-direction: column; gap: 12px; min-width: 0; } +.rr-detail-kopf { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .rr-titel { - font: inherit; font-size: 18px; font-weight: 600; flex: 1 1 180px; min-width: 0; + font: inherit; font-size: 19px; font-weight: 500; flex: 1 1 180px; min-width: 0; border: 1px solid transparent !important; background: transparent !important; color: var(--text); border-radius: 8px; padding: 4px 8px; } .rr-titel:hover:not(:disabled), .rr-titel:focus { border-color: var(--line) !important; background: var(--surface-sunk) !important; } .rr-titel:disabled { color: var(--text); opacity: 1; } -.rr-vergleich-wahl { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-muted); } -.rr-meldung { font-size: 12.5px; color: var(--text-muted); min-width: 80px; } +.rr-vergleich-wahl { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-muted); } +.rr-meldung { font-size: 13px; color: var(--text-muted); min-width: 80px; } .rr-gruppen { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; align-items: start; } .rr-gruppe { background: var(--surface-sunk); border-radius: 12px; padding: 12px; display: flex; flex-direction: column; gap: 4px; } .rr-gruppe-kopf { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; } .rr-gruppe-kopf small { color: var(--text-muted); } .rr-luecke { flex: 1; } -.rr-zeile { display: flex; align-items: center; gap: 10px; padding: 4px 0; } +.rr-zeile { display: flex; align-items: center; gap: 8px; padding: 4px 0; } .rr-name { flex: 1; min-width: 0; } -.rr-name small { display: block; color: var(--text-muted); font-size: 11.5px; } +.rr-name small { display: block; color: var(--text-muted); font-size: 12px; } .rr-schalter { width: 36px; height: 20px; border-radius: 999px; border: 0 !important; padding: 0; flex: none; position: relative; cursor: pointer; background: color-mix(in srgb, var(--text) 22%, transparent); transition: background var(--dur, 150ms); @@ -6006,7 +5994,7 @@ html[data-theme="dark"] .load-ava { color: #0b141b; } .rr-schalter:disabled { opacity: .55; cursor: not-allowed; } .rr-schalter:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } .rr-vergleich { font-size: 11px; color: var(--text-muted); min-width: 34px; text-align: right; } -.rr-vergleich.ist-anders { color: var(--accent); font-weight: 700; } +.rr-vergleich.ist-anders { color: var(--accent); font-weight: 600; } /* ========================================================================= RUNDGANG (js/einfuehrung.js) — abgedunkelte Ebene mit Aussparung um das @@ -6024,26 +6012,26 @@ html[data-theme="dark"] .load-ava { color: #0b141b; } .tour.ohne-ziel .tour-loch { display: none; } .tour-blase { position: fixed; width: min(360px, calc(100vw - 24px)); box-sizing: border-box; - background: var(--surface); color: var(--text); border-radius: 16px; padding: 16px 18px; + background: var(--surface); color: var(--text); border-radius: 16px; padding: 16px 20px; box-shadow: var(--sh-3); display: flex; flex-direction: column; gap: 8px; outline: none; transition: left .25s var(--ease-out, ease), top .25s var(--ease-out, ease); } html.glas .tour-blase { background: var(--glas-dicht, var(--surface)); -webkit-backdrop-filter: blur(24px) saturate(160%); backdrop-filter: blur(24px) saturate(160%); } .tour-blase.ist-unten { left: 12px !important; right: 12px; width: auto; top: auto !important; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); } .tour-kopf { display: flex; align-items: center; justify-content: space-between; } -.tour-schritt { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); font-weight: 600; } -.tour-x { border: 0 !important; background: transparent; color: var(--text-muted); font-size: 20px; line-height: 1; padding: 0 4px; cursor: pointer; } +.tour-schritt { font-size: 11px; letter-spacing: 0; color: var(--text-muted); font-weight: 500; } +.tour-x { border: 0 !important; background: transparent; color: var(--text-muted); font-size: 19px; line-height: 1; padding: 0 4px; cursor: pointer; } .tour-x:hover { color: var(--text); } -.tour-blase h3 { margin: 0; font-size: 17px; font-weight: 650; text-wrap: balance; } -.tour-text { font-size: 13.5px; line-height: 1.55; color: var(--text); } -.tour-hinweise { margin: 8px 0 0; padding-left: 18px; color: var(--text-muted); } +.tour-blase h3 { margin: 0; font-size: 19px; font-weight: 500; text-wrap: balance; } +.tour-text { font-size: 13px; line-height: 1.55; color: var(--text); } +.tour-hinweise { margin: 8px 0 0; padding-left: 20px; color: var(--text-muted); } .tour-punkte { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 2px; } .tour-punkte i { width: 6px; height: 6px; border-radius: 50%; background: var(--line); } .tour-punkte i.ist-erledigt { background: color-mix(in srgb, var(--accent) 45%, transparent); } -.tour-punkte i.ist-aktiv { background: var(--accent); width: 16px; border-radius: 3px; } +.tour-punkte i.ist-aktiv { background: var(--accent); width: 16px; border-radius: 4px; } .tour-knoepfe { display: flex; align-items: center; gap: 6px; margin-top: 4px; } .tour-luecke { flex: 1; } -.tour-skip { border: 0 !important; background: transparent; color: var(--text-muted); font: inherit; font-size: 12.5px; padding: 4px 0; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; } +.tour-skip { border: 0 !important; background: transparent; color: var(--text-muted); font: inherit; font-size: 13px; padding: 4px 0; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; } .tour-skip:hover { color: var(--text); } @media (prefers-reduced-motion: reduce) { .tour-loch, .tour-blase { transition: none; } } @@ -6063,7 +6051,7 @@ html.glas .tour-blase { background: var(--glas-dicht, var(--surface)); -webkit-b --abw-verdeckt: #8d9aa6; } /* showTab() setzt display:block inline — Abstände deshalb über Geschwister. */ -#abwesenheit > * + * { margin-top: 14px; } +#abwesenheit > * + * { margin-top: 12px; } #abwesenheit .legend { margin: 6px 0 0; } .abw-u { --abw-c: var(--abw-urlaub); } .abw-k { --abw-c: var(--abw-krank); } @@ -6080,62 +6068,62 @@ html.glas .tour-blase { background: var(--glas-dicht, var(--surface)); -webkit-b Kachel. Die Liste rechts bestimmt die Höhe nicht mit (height 0 + min-height 100 %), sie scrollt innen, wenn die Erfassung kürzer ist. */ .abw-zwei { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; align-items: stretch; } -.abw-spalte { display: flex; flex-direction: column; gap: 10px; min-width: 0; } +.abw-spalte { display: flex; flex-direction: column; gap: 8px; min-width: 0; } .abw-spalte > .board-list { flex: 1; } .abw-karten-titel { margin: 0 !important; } .abw-listen-karte { height: 0; min-height: 100%; } -.abw-listen-kopf { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; padding: 16px 16px 12px; border-bottom: 1px solid var(--line-soft); } +.abw-listen-kopf { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; padding: 16px 16px 12px; border-bottom: 1px solid var(--line-soft); } .abw-listen-zeilen { flex: 1; min-height: 0; overflow-y: auto; } .abw-karte { padding: 16px; gap: 12px; } -.abw-fuer { display: flex; align-items: center; gap: 10px; font-size: 13px; flex-wrap: wrap; } +.abw-fuer { display: flex; align-items: center; gap: 8px; font-size: 13px; flex-wrap: wrap; } .abw-kreis { cursor: default; } -.abw-fuer-wahl { margin-left: auto; border-radius: var(--r-pill); font-size: 12.5px; padding: 4px 10px; max-width: 220px; } -.abw-datumzeile { display: grid; grid-template-columns: 1fr auto 1fr; gap: 10px; align-items: center; } +.abw-fuer-wahl { margin-left: auto; border-radius: 8px; font-size: 13px; padding: 4px 12px; max-width: 220px; } +.abw-datumzeile { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: center; } .abw-datum { - display: grid; text-align: left; gap: 0; padding: 10px 13px; cursor: pointer; + display: grid; text-align: left; gap: 0; padding: 12px 12px; cursor: pointer; border: 1px solid var(--line-soft); border-radius: 14px; background: var(--surface-alt); color: var(--text); font: inherit; } .abw-datum:hover { background: var(--surface-sunk); } -.abw-datum small { font-size: 10.5px; color: var(--text-subtle); text-transform: uppercase; letter-spacing: .08em; font-weight: 600; } -.abw-datum b { font-size: 21px; font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-weight: 600; letter-spacing: -.01em; } +.abw-datum small { font-size: 11px; color: var(--text-subtle); letter-spacing: 0; font-weight: 500; } +.abw-datum b { font-size: 19px; font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-weight: 500; letter-spacing: 0; } .abw-datum span { font-size: 12px; color: var(--text-muted); } .abw-pfeil { color: var(--text-subtle); } .abw-arten { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; } .abw-arten button { - display: grid; justify-items: center; gap: 5px; padding: 8px 6px; cursor: pointer; font: inherit; font-size: 12.5px; + display: grid; justify-items: center; gap: 4px; padding: 8px 6px; cursor: pointer; font: inherit; font-size: 13px; border: 1px solid var(--line-soft); border-radius: 12px; background: var(--surface-alt); color: var(--text); } -.abw-arten button i { width: 18px; height: 6px; border-radius: 3px; background: var(--abw-c); } -.abw-arten button.ist-an { background: color-mix(in srgb, var(--abw-c) 18%, transparent); border-color: var(--abw-c); font-weight: 600; } +.abw-arten button i { width: 18px; height: 6px; border-radius: 4px; background: var(--abw-c); } +.abw-arten button.ist-an { background: color-mix(in srgb, var(--abw-c) 18%, transparent); border-color: var(--abw-c); font-weight: 500; } .abw-unten { display: flex; gap: 8px; align-items: center; } -.abw-notiz { flex: 1; min-width: 0; border-radius: var(--r-pill); } -.abw-fehler { font-size: 12.5px; color: var(--red); } -.abw-warnung { display: flex; gap: 9px; align-items: flex-start; font-size: 12.5px; border-radius: 12px; padding: 8px 12px; background: color-mix(in srgb, var(--amber) 15%, transparent); } +.abw-notiz { flex: 1; min-width: 0; border-radius: 8px; } +.abw-fehler { font-size: 13px; color: var(--red); } +.abw-warnung { display: flex; gap: 8px; align-items: flex-start; font-size: 13px; border-radius: 12px; padding: 8px 12px; background: color-mix(in srgb, var(--amber) 15%, transparent); } .abw-warnung::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--amber); margin-top: 6px; } /* Liste: Zeilen der Projektliste, mit Punkt in Artfarbe und Kapsel */ .abw-zeile.ist-aktiv .board-row-main { background: var(--accent-soft); } .abw-zeile-name { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; } .abw-punkt { width: 9px; height: 9px; border-radius: 50%; background: var(--abw-c); flex: none; } -.abw-tag { font-size: 11px; font-weight: 500; padding: 1px 8px; border-radius: var(--r-pill); border: 1px solid var(--line); color: var(--text-muted); } +.abw-tag { font-size: 11px; font-weight: 500; padding: 1px 8px; border-radius: 6px; border: 1px solid var(--line); color: var(--text-muted); } .board-row-actions.abw-fragt { opacity: 1; } -.abw-leer { padding: 14px 16px; font-size: 12.5px; color: var(--text-muted); } -.abw-reiter { display: inline-flex; gap: 2px; padding: 3px; border-radius: var(--r-pill); background: var(--surface-sunk); } -.abw-reiter button { border: 0; background: none; padding: 3px 11px; border-radius: var(--r-pill); font: inherit; font-size: 12px; color: var(--text-muted); cursor: pointer; } -.abw-reiter button.ist-an { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: 0 1px 3px rgba(0,0,0,.12); } +.abw-leer { padding: 16px 16px; font-size: 13px; color: var(--text-muted); } +.abw-reiter { display: inline-flex; gap: 2px; padding: 4px; border-radius: 8px; background: var(--surface-sunk); } +.abw-reiter button { border: 0; background: none; padding: 4px 12px; border-radius: 6px; font: inherit; font-size: 12px; color: var(--text-muted); cursor: pointer; } +.abw-reiter button.ist-an { background: var(--surface); color: var(--text); font-weight: 500; box-shadow: 0 1px 3px rgba(0,0,0,.12); } /* Team je Gewerk */ .abw-team-kopf { - margin-top: 26px !important; flex-wrap: wrap; gap: 10px; + margin-top: 24px !important; flex-wrap: wrap; gap: 8px; /* Hinterlegt wie die Karten darunter (.board-list) */ background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-xl); box-shadow: var(--sh-2); - padding: 12px 16px; margin-bottom: 14px; + padding: 12px 16px; margin-bottom: 12px; } .abw-team-steuer { display: inline-flex; align-items: center; gap: 12px; flex-wrap: wrap; } .abw-monat { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; } -.abw-monat strong { min-width: 120px; text-align: center; font-weight: 600; } +.abw-monat strong { min-width: 120px; text-align: center; font-weight: 500; } .abw-rund { width: 28px; height: 28px; border-radius: 50%; border: 1px solid var(--line); background: var(--surface); color: var(--text); cursor: pointer; display: grid; place-items: center; padding: 0; flex: none; } /* Eigener Hover: sonst färbt die allgemeine button:hover-Regel den Kreis akzentblau. Pfeile als Symbol (icon()) statt der Schriftzeichen ‹ ›, die im @@ -6144,8 +6132,8 @@ html.glas .tour-blase { background: var(--glas-dicht, var(--surface)); -webkit-b .abw-rund:active { background: var(--surface-sunk); } .abw-rund .icon { display: grid; place-items: center; } .abw-rund svg { width: 16px; height: 16px; display: block; } -.abw-gewerk-kopf { display: flex; align-items: baseline; gap: 10px; } -.abw-gewerk-kopf small { color: var(--text-muted); font-size: 12.5px; } +.abw-gewerk-kopf { display: flex; align-items: baseline; gap: 8px; } +.abw-gewerk-kopf small { color: var(--text-muted); font-size: 13px; } #abwesenheit .abw-gewerk-kopf + .abw-tl-karte { margin-top: 8px; } .abw-tl-karte { overflow-x: auto; } .abw-tl { display: grid; min-width: 880px; font-size: 11px; } @@ -6153,10 +6141,10 @@ html.glas .tour-blase { background: var(--glas-dicht, var(--surface)); -webkit-b .abw-tl { margin-bottom: -1px; } .abw-tl-tag, .abw-tl-kopf { height: 36px !important; } .abw-tl-tag { display: grid; align-content: center; justify-items: center; line-height: 1.1; color: var(--text-subtle); font-variant-numeric: tabular-nums; } -.abw-tl-tag small { font-size: 9px; text-transform: uppercase; letter-spacing: .04em; } -.abw-tl-tag b { font-size: 11.5px; color: var(--text-muted); font-weight: 600; } -.abw-tl-tag.ist-heute b { background: var(--red); color: #fff; border-radius: var(--r-pill); padding: 0 5px; } -.abw-tl-wer { position: sticky; left: 0; z-index: 3; display: flex; align-items: center; gap: 10px; padding: 0 14px; background: var(--surface); } +.abw-tl-tag small { font-size: 11px; letter-spacing: 0; } +.abw-tl-tag b { font-size: 12px; color: var(--text-muted); font-weight: 500; } +.abw-tl-tag.ist-heute b { background: var(--red); color: #fff; border-radius: 6px; padding: 0 4px; } +.abw-tl-wer { position: sticky; left: 0; z-index: 3; display: flex; align-items: center; gap: 8px; padding: 0 16px; background: var(--surface); } html.glas .abw-tl-wer { background: var(--glas-deckend, var(--surface)); } .abw-tl-kopf { color: var(--text-subtle); font-size: 11px; } .abw-tl-wer.ist-gewaehlt { box-shadow: inset 3px 0 0 var(--accent); } @@ -6165,16 +6153,16 @@ html.glas .abw-tl-wer { background: var(--glas-deckend, var(--surface)); } .abw-tl-wer.ist-klickbar:hover .abw-tl-wer-name { color: var(--accent); } .abw-tl-wer.ist-klickbar:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; } .abw-tl-wer-text { display: flex; flex-direction: column; min-width: 0; } -.abw-tl-wer-name { font-weight: 600; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.abw-tl-wer-meta { font-size: 11.5px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.abw-tl-wer-name { font-weight: 500; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.abw-tl-wer-meta { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .abw-tl .ist-frei { background: color-mix(in srgb, var(--text-subtle) 7%, transparent); } .abw-tl-zelle.ist-heute::after { content: ""; position: absolute; top: 0; bottom: 0; left: 50%; width: 2px; background: var(--red); opacity: .5; z-index: 1; } .abw-tl-zelle.ist-klickbar { cursor: pointer; } .abw-tl-zelle.ist-klickbar:hover { background: var(--surface-sunk); } .abw-balken { position: absolute; top: 14px; bottom: 14px; left: 2px; z-index: 2; cursor: pointer; - display: flex; align-items: center; padding: 0 10px; white-space: nowrap; overflow: hidden; - border-radius: var(--r-pill); font-size: 11px; font-weight: 600; color: var(--text); + display: flex; align-items: center; padding: 0 12px; white-space: nowrap; overflow: hidden; + border-radius: var(--r-pill); font-size: 11px; font-weight: 500; color: var(--text); background: color-mix(in srgb, var(--abw-c) 20%, transparent); box-shadow: inset 0 0 0 1px var(--abw-c); } .abw-balken::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--abw-c); margin-right: 6px; } @@ -6200,7 +6188,7 @@ html.glas .abw-tl-wer { background: var(--glas-deckend, var(--surface)); } .dash-proj-griff:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } .dash-proj-griff svg { width: 14px; height: 14px; } .dash-proj.ist-gezogen { opacity: .5; } -#dashReihenfolgeReset:not([hidden]) + #dashAlleKnopf { margin-left: 10px; } +#dashReihenfolgeReset:not([hidden]) + #dashAlleKnopf { margin-left: 8px; } /* Kürzel-Kreis einer Person mit mehreren Rollen (beteiligtenAvatarHtml(), js/utils.js): Segmente in den Rollenfarben, weiße Schrift mit Schatten. */ @@ -6217,18 +6205,18 @@ html.glas .abw-tl-wer { background: var(--glas-deckend, var(--surface)); } /* „Weitere laden“ im Verlauf (weitereLadenKnopf(), js/store.js): holt je fünf ältere Sitzungen nach — beim Start sind nur die jüngsten geladen. */ -.verlauf-weitere-zeile, .plan-verlauf-mehr-zeile { display: flex; justify-content: center; margin-top: 10px; } +.verlauf-weitere-zeile, .plan-verlauf-mehr-zeile { display: flex; justify-content: center; margin-top: 8px; } button.verlauf-weitere { white-space: nowrap; } /* ---------- Einstellungen: Kalender in Outlook ---------- */ -.kalender-adresse { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 10px 0 6px; } +.kalender-adresse { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 8px 0 6px; } .kalender-adresse input { flex: 1; min-width: 220px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; } .kalender-adresse .button-link { - display: inline-flex; align-items: center; padding: 7px 16px; border-radius: var(--r-pill); + display: inline-flex; align-items: center; padding: 8px 16px; border-radius: 8px; background: var(--accent); color: #fff; font-size: 13px; font-weight: 500; text-decoration: none; white-space: nowrap; } .kalender-adresse .button-link:hover { background: var(--accent-hover); } -.kalender-anleitung { margin: 6px 0 10px; font-size: 13px; } +.kalender-anleitung { margin: 6px 0 8px; font-size: 13px; } .kalender-anleitung summary { cursor: pointer; color: var(--accent); } .kalender-anleitung ol { margin: 8px 0; padding-left: 20px; display: grid; gap: 6px; } .kalender-aktionen { display: flex; gap: 8px; } @@ -6236,18 +6224,18 @@ button.verlauf-weitere { white-space: nowrap; } /* ---------- Admin → Teams (loadAdminTeams(), js/admin/admin.js) ---------- Eigene Klassen statt .settings-field: das Adressfeld ist lang (≈ 300 Zeichen) und braucht eine breite, mehrzeilige Fläche. */ -#adminTeamsInhalt { display: grid; gap: 14px; margin: 12px 0 6px; } +#adminTeamsInhalt { display: grid; gap: 12px; margin: 12px 0 6px; } .teams-status { - display: flex; align-items: center; gap: 12px; padding: 12px 14px; + display: flex; align-items: center; gap: 12px; padding: 12px 16px; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface-sunk); } .teams-punkt { width: 10px; height: 10px; border-radius: 50%; background: var(--text-subtle); flex: none; } .teams-status.ist-an .teams-punkt { background: var(--green); box-shadow: 0 0 0 4px color-mix(in srgb, var(--green) 20%, transparent); } .teams-status-text { display: grid; gap: 2px; flex: 1; min-width: 0; } -.teams-status-text b { font-size: 13.5px; } +.teams-status-text b { font-size: 13px; } .teams-status-text span { font-size: 12px; color: var(--text-muted); overflow-wrap: anywhere; } button.teams-text-knopf, button.teams-text-knopf:hover, button.teams-text-knopf:active { - all: unset; cursor: pointer; font-size: 12.5px; color: var(--accent); white-space: nowrap; padding: 4px 2px; + all: unset; cursor: pointer; font-size: 13px; color: var(--accent); white-space: nowrap; padding: 4px 2px; } button.teams-text-knopf:hover { text-decoration: underline; } button.teams-text-knopf:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; } @@ -6255,10 +6243,10 @@ button.teams-text-knopf.ist-gefahr { color: var(--red); } .teams-feld[hidden] { display: none; } .teams-feld { display: grid; gap: 6px; } -.teams-feld label { font-size: 12px; font-weight: 600; color: var(--text-muted); } +.teams-feld label { font-size: 12px; font-weight: 500; color: var(--text-muted); } .teams-feld textarea { width: 100%; box-sizing: border-box; resize: vertical; min-height: 64px; - padding: 10px 12px; border: 1px solid var(--line) !important; border-radius: var(--r-md) !important; + padding: 12px 12px; border: 1px solid var(--line) !important; border-radius: var(--r-md) !important; background: var(--surface) !important; color: var(--text); box-shadow: none !important; font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; word-break: break-all; } @@ -6271,7 +6259,7 @@ button.teams-text-knopf.ist-gefahr { color: var(--red); } .teams-schalter { display: flex; align-items: center; gap: 12px; cursor: pointer; } .teams-schalter input { position: absolute; opacity: 0; width: 1px; height: 1px; } .teams-schalter-bahn { - flex: none; width: 38px; height: 22px; border-radius: 11px; background: var(--line); position: relative; + flex: none; width: 38px; height: 22px; border-radius: 12px; background: var(--line); position: relative; transition: background var(--dur, 150ms); } .teams-schalter-bahn::after { @@ -6284,8 +6272,213 @@ button.teams-text-knopf.ist-gefahr { color: var(--red); } .teams-schalter input:disabled + .teams-schalter-bahn { opacity: .45; } .teams-schalter:has(input:disabled) { cursor: default; } .teams-schalter-text { display: grid; gap: 2px; } -.teams-schalter-text b { font-size: 13px; font-weight: 600; } +.teams-schalter-text b { font-size: 13px; font-weight: 500; } .teams-schalter-text span { font-size: 12px; color: var(--text-muted); } .teams-schalter:has(input:disabled) .teams-schalter-text { opacity: .55; } -.teams-aktionen { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; } +.teams-aktionen { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; } + +/* =========================================================================== + BAUPLAN — unslop-Überarbeitung (Eriks Wahl „volle Überarbeitung“, 11/2026) + --------------------------------------------------------------------------- + Richtung: Planköpfe und Raster eines Bauplans. Flächen fast neutral + (Graphit, leicht kühl), ein Akzent (Logo-Blau), Farbe nur in den + Inhalten (Terminplan, Auslastung, Status). Schriftskala 11/12/13/15/19/24, + Gewichte 400/500 (600 selten), keine gesperrten Großbuchstaben, Abstände + im 4px-Raster, Rundungen 4–8 (Bedienelemente) / 12–16 (Karten). + Kennzeichen: Kalenderwochen, Maße und Kennzahlen in gleich breiten + Monospace-Ziffern — überall dieselbe „KW 44“-Marke. + Die Durchgänge wurden auf styles.css/plan-styles.css/glas.css angewandt; + die Wandtafel (body.wandtafel-aktiv mit ihren dash- und wt-Tokens) ist ausgenommen. + Methode nach „unslop“ von Damir Sokolovsky (@heydamir), CC BY 4.0. + =========================================================================== */ +:root { --font-mono: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace; } + +/* Kennzeichen: KW-Marke */ +.gantt-day.gantt-week span, +.range-picker-kw, .range-picker-kw-kopf, +.dash-kal-kw, .bv-kw, .timeline-kw, .plan-verlauf-kw, .bericht-zuletzt-kw, .load-kws { + font-family: var(--font-mono); + font-variant-numeric: tabular-nums; + font-weight: 400; + letter-spacing: 0; +} +.gantt-day.gantt-week span { font-size: 11px; color: var(--text-muted); } +.range-picker-kw, .dash-kal-kw { color: var(--text-subtle); font-size: 11px; } + +/* Kennzahlen und Maße in denselben Ziffern */ +.board-nr, .plan-header .projnr, .dash-proj-nr, .dash-auf-pct, .dash-termin-datum, +.gantt-dates, .plan-task-date, .load-zahl, .load-num, .kpi-value, .plan-kpi-tile .kpi-value, +.dash-band-zahl { + font-variant-numeric: tabular-nums; +} +.board-nr, .dash-proj-nr { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0; color: var(--text-muted); } + +/* Navigation: ruhige Auswahl — Flächenstufe statt Akzentfläche */ +.nav-item.active { background: var(--surface-sunk); color: var(--text); box-shadow: inset 0 0 0 1px var(--line-soft); } +.nav-item.active .nav-icon { color: var(--accent); } +.nav-item { min-height: 32px; } +.sidebar-section-label { padding: 16px 12px 4px; color: var(--text-subtle); font-weight: 500; } + +/* Dunkel: Hauptknöpfe in einem tieferen Logo-Blau, damit die weiße Schrift + trägt (auf dem hellen Akzent #86bfdf käme sie nur auf ~2:1). Der helle + Akzent bleibt für Auswahl, Links und Kennzahlen. */ +@media (prefers-color-scheme: dark) { + html:not([data-theme="light"]) { --knopf: #276f9c; --knopf-hover: #2f7aa8; --knopf-aktiv: #22628a; } +} +html[data-theme="dark"] { --knopf: #276f9c; --knopf-hover: #2f7aa8; --knopf-aktiv: #22628a; } +button { background: var(--knopf, var(--accent)); } +button:hover { background: var(--knopf-hover, var(--accent-hover)); } +button:active { background: var(--knopf-aktiv, var(--accent-active)); } + +/* Bewegung: nur Farbe/Fläche/Transform, eine Kurve */ +button { transition: background-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out), + transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out); } + +/* =========================================================================== + MEINE AUFGABEN — Entwurf „Bauplan“ (Eriks Wahl, 11/2026) + --------------------------------------------------------------------------- + Kopf mit Kalenderwoche statt Begrüßung, Band mit vier Kennzahlen, das Band + „Diese Woche“ (Mo–Fr) und je Projekt die Zeile „Meine Rolle | Team | + Notizen“. Der Monatskalender (.dash-kal-*) bleibt ausdrücklich unverändert. + =========================================================================== */ +.dash-kopf { align-items: flex-end; margin-bottom: 16px; } +.dash-kopf-links { display: flex; flex-direction: column; gap: 4px; } +.dash-kopf-kw { font-family: var(--font-mono); font-size: 12px; color: var(--text-subtle); font-variant-numeric: tabular-nums; } +.dash-titel { margin: 0; font-size: 24px; line-height: 32px; font-weight: 500; letter-spacing: 0; } +.dash-kopf-rechts { align-items: center; gap: 8px; } +.dash-kopf-label { font-size: 12px; color: var(--text-subtle); } +.dash-sitzung { font-family: var(--font-mono); font-size: 12px; font-weight: 400; padding: 2px 8px; border: 1px solid var(--line-soft); background: var(--surface); color: var(--text); } + +.dash-band { padding: 20px 24px; gap: 24px; background: var(--surface); border: 1px solid var(--line-soft); box-shadow: var(--sh-1); } +.dash-band.ist-ruhig { background: var(--surface); } +.dash-befund { font-size: 15px; line-height: 24px; color: var(--text-muted); } +.dash-befund b { font-size: 1em; } +.dash-band-zahlen { gap: 32px; } +.dash-zahl { gap: 2px; min-width: 88px; } +.dash-zahl span { font-size: 12px; } +.dash-zahl b { font-size: 24px; line-height: 32px; } +.dash-zahl.ist-rot b { color: var(--red); } + +/* Diese Woche */ +.dash-woche { padding: 16px 20px 16px; overflow: visible; } +.dash-woche-rahmen { overflow-x: auto; } +.dash-woche-raster { display: grid; grid-template-columns: repeat(5, minmax(140px, 1fr)); min-width: 700px; + border: 1px solid var(--line-soft); border-radius: var(--r-md); overflow: hidden; } +.dash-woche-tag { display: flex; flex-direction: column; min-width: 0; } +.dash-woche-tag + .dash-woche-tag { border-left: 1px solid var(--line-soft); } +.dash-woche-tag.ist-heute { background: color-mix(in srgb, var(--accent) 5%, transparent); } +.dash-woche-kopf { display: flex; justify-content: space-between; align-items: baseline; padding: 8px 12px; border-bottom: 1px solid var(--line-soft); font-weight: 500; } +.dash-woche-tag.ist-heute .dash-woche-kopf > span:first-child { color: var(--accent); } +.dash-woche-datum { font-family: var(--font-mono); font-size: 12px; font-weight: 400; color: var(--text-subtle); } +.dash-woche-liste { display: flex; flex-direction: column; gap: 8px; padding: 12px; min-height: 120px; } +.dash-woche-eintrag { display: flex; flex-direction: column; gap: 2px; padding: 8px 12px; border-radius: 6px; text-decoration: none; color: var(--text); + background: var(--surface-sunk); border: 1px solid var(--line-soft); min-width: 0; + transition: background-color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out); } +.dash-woche-eintrag:hover { border-color: var(--line); } +.dash-woche-eintrag.ist-meins { background: color-mix(in srgb, var(--accent) 10%, var(--surface)); border-color: color-mix(in srgb, var(--accent) 22%, transparent); } +.dash-woche-eintrag.ist-ms { background: color-mix(in srgb, var(--meilenstein) 10%, var(--surface)); border-color: color-mix(in srgb, var(--meilenstein) 24%, transparent); } +.dash-woche-eintrag.ist-ueber { background: color-mix(in srgb, var(--red) 8%, var(--surface)); border-color: color-mix(in srgb, var(--red) 24%, transparent); } +.dash-woche-titel { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.dash-woche-projekt { font-size: 12px; color: var(--text-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.dash-woche-leer { font-size: 12px; color: var(--text-subtle); } +.dash-woche-mehr { font-size: 12px; color: var(--text-muted); } +.dash-woche-legende { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 12px; font-size: 12px; color: var(--text-muted); } +.dash-woche-legende span { display: inline-flex; align-items: center; gap: 8px; } +.dash-woche-legende i { width: 12px; height: 4px; border-radius: 2px; background: var(--text-subtle); } +.dash-woche-legende i.ist-meins { background: var(--accent); } +.dash-woche-legende i.ist-ms { width: 8px; height: 8px; border-radius: 1px; transform: rotate(45deg); background: var(--meilenstein); } +.dash-woche-legende i.ist-ueber { background: var(--red); } + +/* Projektblock: Meine Rolle | Team | Notizen */ +.dash-proj-kopf .dash-proj-titel { font-size: 15px; font-weight: 500; } +.dash-proj-nr { font-family: var(--font-mono); } +.dash-proj-info { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); margin: 0 16px 12px; + border: 1px solid var(--line-soft); border-radius: var(--r-md); background: var(--surface-alt); } +.dash-proj-feld { display: flex; flex-direction: column; gap: 4px; padding: 12px 16px; min-width: 0; color: var(--text); text-decoration: none; } +.dash-proj-feld + .dash-proj-feld { border-left: 1px solid var(--line-soft); } +.dash-proj-feld-titel { font-size: 12px; color: var(--text-subtle); } +.dash-proj-feld-wert { display: flex; align-items: center; gap: 8px; min-width: 0; } +.dash-proj-feld-wert .board-avatar { flex: none; } +.dash-proj-team { display: inline-flex; flex: none; } +.dash-proj-team .board-avatar + .board-avatar { margin-left: -6px; } +.dash-proj-team .board-avatar { box-shadow: 0 0 0 2px var(--glas-deckend, var(--surface)); } +.dash-proj-namen { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-muted); } +.dash-proj-notizen { transition: background-color var(--dur) var(--ease-out); } +.dash-proj-notizen:hover { background: var(--surface-sunk); } +.dash-proj-notizen .icon { color: var(--text-muted); } +.dash-proj-notizen b { font-family: var(--font-mono); font-weight: 400; } +.dash-proj-zuletzt { font-size: 12px; color: var(--text-subtle); white-space: nowrap; } +@media (max-width: 640px) { + .dash-proj-feld + .dash-proj-feld { border-left: 0; border-top: 1px solid var(--line-soft); } +} + +/* =========================================================================== + NOTIZEN (Seitenleiste, js/notizen/notizen.js) — nutzt die .notizen-*-Stile + des Projekt-Reiters (plan-styles.css), hier nur Kopf, Filter und Zuordnung. + =========================================================================== */ +.mn-seite { display: flex; flex-direction: column; gap: 16px; } +.mn-kopf { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 12px; } +.mn-kopf-links { display: flex; flex-direction: column; gap: 4px; } +.mn-kopf-unter { font-size: 12px; color: var(--text-subtle); } +.mn-titel { margin: 0; font-size: 24px; line-height: 32px; font-weight: 500; } +.mn-filter, .mn-zuordnung { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-muted); } +/* Nur background-color — die Kurzschreibweise „background:“ setzte die Wiederholung zurück, + und der Dropdown-Pfeil der globalen select-Regel erschien im Dunkelmodus als Kachelmuster. */ +.mn-filter select, .mn-zuordnung select { height: 32px; padding: 0 28px 0 8px; border: 1px solid var(--line); border-radius: 8px; background-color: var(--surface); color: var(--text); font: inherit; max-width: 360px; } +.mn-notizen { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); box-shadow: var(--sh-1); overflow: hidden; min-height: 520px; } +.mn-editor-zeile { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; } +.mn-projekt-link { font-size: 13px; color: var(--accent); text-decoration: none; } +.mn-projekt-link:hover { text-decoration: underline; } +.mn-hinweis { font-size: 12px; color: var(--text-subtle); } +.mn-projekt { color: var(--text-muted); } +.mn-projekt.ist-ohne { color: var(--text-subtle); } + +/* =========================================================================== + SEITENLEISTE — Gliederung nach Arbeitsbereich (Eriks Wahl „A“, 11/2026) + --------------------------------------------------------------------------- + Gruppen (.sidebar-gruppe) statt loser Trennlinien: Eigenes, Projekte, + Team, Studenten; Einstellungen und Admin unten (.sidebar-unten). Einträge + fest 32 px, Icon-Spalte 18 px + 8 px Abstand, Rubrik 16 px über der Gruppe + und 4 px über ihren Einträgen. Unterpunkte (geöffnetes Projekt, Admin) + Admin-Unterpunkte beginnen auf der Linie der Beschriftungen (12 + 18 + 8 = + 38 px), das geöffnete Projekt 8 px tiefer mit Führungslinie. + =========================================================================== */ +.sidebar-nav { gap: 0; padding: 12px; } +.sidebar-gruppe { display: flex; flex-direction: column; gap: 2px; } +.sidebar-gruppe + .sidebar-gruppe { margin-top: 16px; } +.sidebar-gruppe.sidebar-unten { margin-top: auto; padding-top: 12px; border-top: 1px solid var(--line-soft); } +.sidebar-gruppe > .sidebar-section-label { padding: 0 12px 4px; font-size: 12px; line-height: 16px; font-weight: 500; color: var(--text-subtle); } +.sidebar-nav .nav-item { min-height: 32px; height: 32px; padding: 0 12px; gap: 8px; font-weight: 400; color: var(--text-muted); } +.sidebar-nav .nav-item.active { font-weight: 500; color: var(--text); } +.sidebar-nav .nav-icon { width: 18px; font-size: 16px; } + +/* Geöffnetes Projekt: eingezogen unter „Projekte“, mit feiner Führungslinie */ +.nav-item.nav-unterpunkt { position: relative; padding-left: 46px; } +.nav-item.nav-unterpunkt .nav-icon { display: none; } +.nav-item.nav-unterpunkt::before { content: ""; position: absolute; left: 32px; top: 8px; bottom: 8px; width: 1px; background: var(--line); } +.nav-projnr { font-family: var(--font-mono); font-size: 12px; color: var(--text-subtle); } +.nav-item.active .nav-projnr { color: var(--accent); } + +/* Admin: Unterpunkte auf der Beschriftungslinie, in drei Gruppen */ +.sidebar-subnav { padding-left: 0; gap: 2px; } +.sidebar-subnav.open { max-height: 900px; } +/* Zwischenüberschrift: kleiner und heller als die Punkte, mit feiner Linie bis + zum Rand — hebt sich ab, ohne gesperrte Großbuchstaben. */ +.sidebar-subgruppe { display: flex; align-items: center; gap: 8px; padding: 12px 12px 4px 38px; font-size: 11px; line-height: 16px; font-weight: 500; color: var(--text-subtle); } +.sidebar-subgruppe::after { content: ""; flex: 1; height: 1px; background: var(--line-soft); } +.sidebar-subgruppe:first-child { padding-top: 4px; } +/* Mit #adminSubnav, weil button.menu-item (Knopf-Grundregel) sonst Einzug und + Schriftstärke überschreibt — die Punkte standen dann ganz links und fett, + die Zwischenüberschriften wirkten in die Mitte gerutscht. */ +#adminSubnav .sidebar-subitem { min-height: 32px; height: 32px; padding: 0 12px 0 38px; display: flex; align-items: center; border-radius: var(--r-md); + font-size: 13px; font-weight: 400; color: var(--text-muted); background: transparent; } +#adminSubnav .sidebar-subitem:hover { background: var(--surface-sunk); color: var(--text); } +#adminSubnav .sidebar-subitem.is-active { background: var(--surface-sunk); color: var(--text); font-weight: 500; box-shadow: inset 0 0 0 1px var(--line-soft); } + +@media (min-width: 769px) { + #headerMenu.side-menu.collapsed .sidebar-gruppe + .sidebar-gruppe { margin-top: 8px; } + #headerMenu.side-menu.collapsed .nav-item.nav-unterpunkt { padding-left: 0; } + #headerMenu.side-menu.collapsed .nav-item.nav-unterpunkt::before { display: none; } + #headerMenu.side-menu.collapsed .nav-item.nav-unterpunkt .nav-icon { display: inline-flex; } +} diff --git a/server.js b/server.js index 3788b63..c4c0d51 100644 --- a/server.js +++ b/server.js @@ -1020,6 +1020,30 @@ function htmlEscape(s){ .replace(/"/g, '"').replace(/'/g, '''); } +// textMaskieren: wie htmlEscape(), aber ein '&', das schon eine fertige +// Entity beginnt (&   ' …), bleibt stehen. Der Text zwischen den +// Tags kommt aus gespeichertem HTML, in dem solche Entities ganz normal +// stehen. htmlEscape() machte daraus bei JEDEM Speichern eine Stufe mehr +// (  → &nbsp; → &amp;nbsp; …) — Eriks Meldung nach dem +// Sitzungswechsel KW 45. So bleibt die Bereinigung beliebig oft wiederholbar. +function textMaskieren(s){ + return String(s) + .replace(/&(?!(?:[a-zA-Z][a-zA-Z0-9]{1,31}|#\d{1,7}|#x[0-9a-fA-F]{1,6});)/g, '&') + .replace(//g, '>'); +} + +// entitiesEntstapeln: macht gestapelte Maskierung rückgängig +// (&amp;nbsp; →  , &amp; → &). Ein „&“ vor einer +// weiteren Entity ist immer das Ergebnis des Fehlers oben, nie Absicht. +function entitiesEntstapeln(html){ + let alt, neu = String(html || ''); + do { + alt = neu; + neu = neu.replace(/&((?:[a-zA-Z][a-zA-Z0-9]{1,31}|#\d{1,7}|#x[0-9a-fA-F]{1,6});)/g, '&$1'); + } while(neu !== alt); + return neu; +} + // sicheresStyleAttribut: lässt aus einem style-Attribut nur color und // font-weight durch — identisch zur Client-Regel. Rückgabe: bereinigter // Wert oder '' (dann wird das Attribut ganz weggelassen). @@ -1108,7 +1132,7 @@ function sanitizeFormatHtml(html){ if(c !== '<'){ const naechstes = quelle.indexOf('<', i); const text = quelle.slice(i, naechstes === -1 ? quelle.length : naechstes); - if(!verwerfenBis) aus += htmlEscape(text); + if(!verwerfenBis) aus += textMaskieren(text); i += text.length; continue; } @@ -2611,6 +2635,30 @@ function kommentareVorsatzUmstellen(){ if(n) console.log('Gewerke-Vorsatz aus ' + n + ' Kommentaren entfernt.'); } +// entitiesReparieren: führt gestapelte Maskierung (&amp;nbsp; …) in +// allen Sitzungskommentaren und Protokoll-Punkten auf das ursprüngliche +// Zeichen zurück — Folge des Fehlers in sanitizeFormatHtml() vor +// textMaskieren(). Läuft bei jedem Start und nach /import, idempotent. +function entitiesReparieren(){ + const teile = [ + ['project_kommentare', 'status', 'week_label, project_id, gewerk', 'week_label = ? AND project_id = ? AND gewerk = ?', r => [r.week_label, r.project_id, r.gewerk]], + ['protokoll_punkte', 'text', 'id', 'id = ?', r => [r.id]] + ]; + let n = 0; + db.exec('BEGIN'); + try { + teile.forEach(([tab, feld, schluessel, wo, werte]) => { + const upd = db.prepare('UPDATE ' + tab + ' SET ' + feld + ' = ? WHERE ' + wo); + db.prepare('SELECT ' + schluessel + ', ' + feld + " AS wert FROM " + tab + " WHERE " + feld + " LIKE '%&%'").all().forEach(r => { + const neu = entitiesEntstapeln(r.wert); + if(neu !== r.wert){ upd.run(neu, ...werte(r)); n++; } + }); + }); + db.exec('COMMIT'); + } catch(e){ db.exec('ROLLBACK'); throw e; } + if(n) console.log('Doppelt maskierte Zeichen in ' + n + ' Kommentaren/Protokoll-Punkten repariert.'); +} + function kommentareSpiegelstricheUmstellen(){ const zeilen = db.prepare("SELECT week_label, project_id, gewerk, status FROM project_kommentare WHERE status != ''").all(); const upd = db.prepare('UPDATE project_kommentare SET status = ? WHERE week_label = ? AND project_id = ? AND gewerk = ?'); @@ -3558,6 +3606,7 @@ einmaligeUmstellung('siemon-anteile-2021', siemon2021Umstellen); // Idempotent (ein bereits entfernter Vorsatz ist weg) — läuft deshalb bei // jedem Start und nach /import, damit ältere Backups ihn nicht zurückbringen. kommentareVorsatzUmstellen(); +entitiesReparieren(); ensureSandboxWeek(); ensureUserPersonIdUniqueIndex(); migrateRetirePeopleTablesIntoUsers(); @@ -7362,6 +7411,68 @@ function notizAnlegen(req, uid, titel, html, quelle){ return notizLesen(id); } +// GET /projekt-notizen/anzahl — je Projekt (project_uid) Anzahl und zuletzt +// geändert, für die Projektblöcke auf „Meine Aufgaben“. Nur Zählung, kein Inhalt. +app.get('/projekt-notizen/anzahl', requireAuth, (req, res) => { + try { + const anzahl = {}; + db.prepare("SELECT project_uid AS uid, COUNT(*) AS n, MAX(geaendert_am) AS zuletzt FROM projekt_notizen WHERE project_uid != '' GROUP BY project_uid") + .all().forEach(r => { anzahl[r.uid] = { anzahl: r.n, zuletzt: r.zuletzt || '' }; }); + res.json({ ok: true, anzahl }); + } catch(err){ + console.error('Notizen zählen fehlgeschlagen:', err); + res.status(500).json({ ok: false, error: String(err) }); + } +}); + +// ---------- Seitenleiste „Notizen“: alle Notizen meiner Projekte ---------- +// +// Eriks Wunsch: ein eigener Bereich, in dem jedes Konto die Notizen ALLER +// seiner Projekte sieht und auch projektunabhängige Notizen anlegt, die sich +// später einem Projekt zuordnen lassen. Eine projektunabhängige Notiz ist eine +// Zeile mit project_uid = '' und gehört allein ihrem Verfasser (sonst sieht +// und ändert sie niemand). „Meine Projekte“ = in der jüngsten echten Sitzung +// zugeordnet (assign > 0) oder mit eigener Aufgabe — dieselbe Regel wie das +// Dashboard (dashDaten()). +function meineProjektUids(user){ + const ich = user && user.personId; + const uids = new Set(); + if(!ich) return uids; + const label = echteSitzungenSortiert().map(w => w.label).pop(); + const w = label ? loadWeeks(label)[0] : null; + ((w && w.projects) || []).forEach(p => { + const zugeordnet = Object.keys(p.assign || {}).some(k => k.split('|')[0] === ich && Number(p.assign[k]) > 0); + const eigene = ((p.plan && p.plan.todos) || []).some(t => Array.isArray(t.assignees) && t.assignees.includes(ich)); + if((zugeordnet || eigene) && p.projectUid) uids.add(String(p.projectUid)); + }); + return uids; +} +const NOTIZ_SELECT = `SELECT n.*, COALESCE(u1.display_name, 'Gelöschter Benutzer') AS erstellt_name, + COALESCE(u2.display_name, 'Gelöschter Benutzer') AS geaendert_name + FROM projekt_notizen n LEFT JOIN users u1 ON u1.id = n.erstellt_von LEFT JOIN users u2 ON u2.id = n.geaendert_von`; + +// GET /meine-notizen — {notizen, meineProjekte:[uid]}: die Notizen meiner +// Projekte plus meine projektunabhängigen. +app.get('/meine-notizen', requireAuth, (req, res) => { + try { + const uids = Array.from(meineProjektUids(req.user)); + const rows = db.prepare(NOTIZ_SELECT + ` WHERE (n.project_uid = '' AND n.erstellt_von = ?)` + + (uids.length ? ' OR n.project_uid IN (' + uids.map(() => '?').join(',') + ')' : '') + + ' ORDER BY n.angeheftet DESC, n.geaendert_am DESC').all(req.user.id, ...uids); + res.json({ ok: true, notizen: rows.map(notizZeile), meineProjekte: uids }); + } catch(err){ + console.error('Meine Notizen laden fehlgeschlagen:', err); + res.status(500).json({ ok: false, error: String(err) }); + } +}); + +// notizDarf: Schreibrecht auf eine Notiz bzw. ein Ziel. Projektunabhängig +// (uid '') nur der Verfasser; an einem Projekt das Recht proj.plan. +function notizDarf(user, uid, erstelltVonId){ + if(!uid) return erstelltVonId === undefined || erstelltVonId === user.id; + return hatRecht(user, 'proj.plan'); +} + app.get('/projekt-notizen', requireAuth, (req, res) => { try { const uid = String(req.query.uid || ''); @@ -7377,11 +7488,11 @@ app.get('/projekt-notizen', requireAuth, (req, res) => { } }); -app.post('/projekt-notizen', requireAuth, requireRecht('proj.plan'), (req, res) => { +app.post('/projekt-notizen', requireAuth, (req, res) => { try { const b = req.body || {}; const uid = String(b.uid || ''); - if(!uid) return res.status(400).json({ ok: false, error: 'uid fehlt.' }); + if(!notizDarf(req.user, uid)) return res.status(403).json({ ok: false, recht: 'proj.plan', error: 'Keine Berechtigung, Notizen in Projekten anzulegen.' }); res.json({ ok: true, notiz: notizAnlegen(req, uid, b.titel, b.html, '') }); } catch(err){ console.error('Notiz anlegen fehlgeschlagen:', err); @@ -7392,11 +7503,20 @@ app.post('/projekt-notizen', requireAuth, requireRecht('proj.plan'), (req, res) // PUT {titel?, html?, angeheftet?, basis?} — basis = geaendertAm des Stands, // auf dem die Änderung beruht; weicht der gespeicherte ab, 409 mit dem // aktuellen Stand (jemand anderes hat inzwischen gespeichert). -app.put('/projekt-notizen/:id', requireAuth, requireRecht('proj.plan'), (req, res) => { +// uid (optional): einem Projekt zuordnen bzw. mit '' wieder projektunabhängig +// machen (das nur der Verfasser) — aus der Seitenleiste „Notizen“. +app.put('/projekt-notizen/:id', requireAuth, (req, res) => { try { const alt = notizLesen(req.params.id); if(!alt) return res.status(404).json({ ok: false, error: 'Die Notiz gibt es nicht mehr.' }); + if(!alt.uid && alt.erstelltVonId !== req.user.id) return res.status(404).json({ ok: false, error: 'Die Notiz gibt es nicht mehr.' }); + if(!notizDarf(req.user, alt.uid, alt.erstelltVonId)) return res.status(403).json({ ok: false, recht: 'proj.plan', error: 'Keine Berechtigung, Notizen zu ändern.' }); const b = req.body || {}; + const neueUid = typeof b.uid === 'string' ? b.uid : alt.uid; + if(neueUid !== alt.uid){ + if(!neueUid && alt.erstelltVonId !== req.user.id) return res.status(403).json({ ok: false, error: 'Nur wer die Notiz angelegt hat, kann sie vom Projekt lösen.' }); + if(!notizDarf(req.user, neueUid, alt.erstelltVonId)) return res.status(403).json({ ok: false, recht: 'proj.plan', error: 'Keine Berechtigung, Notizen in Projekten anzulegen.' }); + } if(typeof b.basis === 'string' && b.basis && b.basis !== alt.geaendertAm){ return res.status(409).json({ ok: false, konflikt: true, notiz: alt, error: alt.geaendertVon + ' hat diese Notiz inzwischen geändert.' }); @@ -7408,10 +7528,11 @@ app.put('/projekt-notizen/:id', requireAuth, requireRecht('proj.plan'), (req, re // Bearbeiter bleiben, damit die Sortierung „zuletzt geändert“ stimmt. const nurPin = typeof b.titel !== 'string' && typeof b.html !== 'string'; const jetzt = nurPin ? alt.geaendertAm : new Date().toISOString(); - db.prepare(`UPDATE projekt_notizen SET titel = ?, html = ?, angeheftet = ?, geaendert_am = ? + db.prepare(`UPDATE projekt_notizen SET titel = ?, html = ?, angeheftet = ?, geaendert_am = ?, project_uid = ? ${nurPin ? '' : ', geaendert_von = ' + Number(req.user.id)} WHERE id = ?`) - .run(titel, html, angeheftet, jetzt, alt.id); + .run(titel, html, angeheftet, jetzt, neueUid, alt.id); ereignisSenden({ typ: 'notizen', uid: alt.uid }, req); + if(neueUid !== alt.uid) ereignisSenden({ typ: 'notizen', uid: neueUid }, req); res.json({ ok: true, notiz: notizLesen(alt.id) }); } catch(err){ console.error('Notiz speichern fehlgeschlagen:', err); @@ -7419,10 +7540,11 @@ app.put('/projekt-notizen/:id', requireAuth, requireRecht('proj.plan'), (req, re } }); -app.delete('/projekt-notizen/:id', requireAuth, requireRecht('proj.plan'), (req, res) => { +app.delete('/projekt-notizen/:id', requireAuth, (req, res) => { try { const alt = notizLesen(req.params.id); if(!alt) return res.json({ ok: true }); + if(!notizDarf(req.user, alt.uid, alt.erstelltVonId)) return res.status(403).json({ ok: false, recht: 'proj.plan', error: 'Keine Berechtigung, Notizen zu löschen.' }); if(alt.erstelltVonId !== req.user.id && !istAdministrator(req.user)){ return res.status(403).json({ ok: false, error: 'Löschen darf nur, wer die Notiz angelegt hat, oder ein Administrator.' }); } @@ -7438,11 +7560,11 @@ app.delete('/projekt-notizen/:id', requireAuth, requireRecht('proj.plan'), (req, // POST /projekt-notizen/aus-mail {uid, text|eml} — Mail als neue Notiz, OHNE // KI: Titel = Betreff (sonst erste Zeile), oben Absender und Datum, darunter // der Text (zitierte Vorgänger-Mails abgeschnitten, wie bei „Termin aus Mail“). -app.post('/projekt-notizen/aus-mail', requireAuth, requireRecht('proj.plan'), (req, res) => { +app.post('/projekt-notizen/aus-mail', requireAuth, (req, res) => { try { const b = req.body || {}; const uid = String(b.uid || ''); - if(!uid) return res.status(400).json({ ok: false, error: 'uid fehlt.' }); + if(!notizDarf(req.user, uid)) return res.status(403).json({ ok: false, recht: 'proj.plan', error: 'Keine Berechtigung, Notizen in Projekten anzulegen.' }); const mail = (typeof b.eml === 'string' && b.eml.trim()) ? leseEml(b.eml) : { betreff: '', absender: '', datum: '', text: String(b.text || '') }; const text = mailZitateAbschneiden(mail.text).slice(0, 50000); @@ -9262,6 +9384,7 @@ app.post('/import', requireRecht('a.import'), express.raw({ type: '*/*', limit: // Ältere Backups tragen Kommentare noch gewerkübergreifend in projects. migrateKommentareJeGewerk(); kommentareVorsatzUmstellen(); + entitiesReparieren(); // Ältere Backups kennen das Feld leistungsphase noch nicht. phasenbalkenAusTitel(); console.log('Datenbank aus Backup wiederhergestellt (' + buf.length + ' Bytes)'); @@ -9292,7 +9415,7 @@ app.get('/', (req,res)=>{ // Projektliste aufgegangen ist: Weitergegebene Links sollen nicht mit 404 // enden. Die Oberfläche leitet den Abschnitt auf die Projektliste um // (TAB_BY_SLUG in public/js/globals.js) und erzeugt ihn selbst nicht mehr. -const VALID_TAB_SLUGS = new Set(['Projektübersicht','Wochenbericht','Auslastung','Abwesenheiten','Projekte','Projektbeteiligte','Planung','PlanChecker','MeineAufgaben','Wandtafel','Einstellungen','Admin']); +const VALID_TAB_SLUGS = new Set(['Projektübersicht','Wochenbericht','Auslastung','Abwesenheiten','Notizen','Projekte','Projektbeteiligte','Planung','PlanChecker','MeineAufgaben','Wandtafel','Einstellungen','Admin']); // Slug der Projektplan-Seite (muss zu PLAN_SLUG in js/globals.js passen) const PLAN_SLUG = 'Projektplan';