Files
projektuebersicht/public/plan-styles.css
T
erikandClaude Opus 5 93505e0e48 Beteiligte in die Projekteinstellungen, TODOs aus Protokoll, Bewegung
Beteiligten-Zuordnung verlagert: p.assign ist jetzt ein Stammdatum und
nur noch in den Projekteinstellungen editierbar (planCycleAssign()).
Wochenbericht und Projektboard zeigen sie nur noch an, mit Verweis
dorthin (springZuEinstellungen()). cycleAssign() ist damit entfallen.

Neu "TODOs aus Protokoll": ein externes Besprechungsprotokoll als PDF
wird per KI eingelesen und daraus in einem zweiten KI-Schritt Aufgaben
abgeleitet. Eigener Bereich in der Aufgaben-/GANTT-Leiste, bewusst
unabhaengig von den gespeicherten Protokollen - nichts davon wird
abgelegt. Drei Schritte in einem Dialog mit fester Fusszeile; die
Vorschlagsliste als kompakte, aufklappbare Zeilen, weil ein echter
Import leicht 20 Vorschlaege liefert.

Sichtbarkeit je Aufgabe im GANTT: neue Spalte plan_todos.show_in_gantt
(Vorgabe 1, idempotente Migration) und eine Checkbox im Aufgaben-Dialog.
Eine terminierte Aufgabe kann damit gezielt aus dem Terminplan
herausgehalten werden, bleibt sonst aber eine vollwertige Aufgabe.
plan-build-gantt.js und plan-drag.js pruefen dieselbe Bedingung, damit
Zeilenzahl und Umsortierung nicht auseinanderlaufen.

KI-Timeout dritte Stufe: ein abweichender, aber entfernter Endpunkt
(Drittanbieter-Proxy) bekommt 2 Minuten statt der 45 Sekunden der
echten Anbieter-API. Gemessen: die Punkte-Erkennung eines realen
Protokolls brauchte dort 39 Sekunden, lag also stets knapp unter dem
alten Limit und brach bei jeder Schwankung ab.

Bewegung: Hover- und Klick-Rueckmeldung als Token-Satz in :root,
angewandt auf die anklickbaren Zeilen, Schalter und Dialoge. Die
Akzentleiste ist ein inset-Schatten statt eines positionierten
Elements, damit Drag-and-Drop unberuehrt bleibt; prefers-reduced-motion
war bisher gar nicht vorhanden und kippt jetzt einfach die Tokens.

Plan Checker: optionaler Projektabgleich des Plankopfs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-17 15:14:26 +02:00

1118 lines
51 KiB
CSS

/* ===========================================================================
Projektbereich — Stile des Projektplan-Bereichs
---------------------------------------------------------------------------
Diese Regeln standen früher als <style>-Block in der eigenständigen Seite
public/project-plan.html. Seit der Projektbereich ein normaler Bereich der
Hauptseite ist (Test.html, Bereich #plan — er wird wie jeder andere über
showTab() eingeblendet), liegen sie in einer eigenen Datei, die Test.html
zusaetzlich zu styles.css laedt. Die Klassennamen sind unveraendert
(.plan-page, .plan-nav, .plan-section, .plan-kpi-*, .gantt-*, …), damit die
Module unter public/js/plan/ nichts davon wissen muessen.
=========================================================================== */
.plan-page { display: flex; flex-direction: column; }
.plan-header {
display: flex; align-items: center; gap: 14px; 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 .plan-id {
font-family: ui-monospace, 'SF Mono', monospace; font-size: 12.5px; color: var(--text-muted); white-space: nowrap;
}
.plan-header .subtitle { color: var(--text-muted); font-size: 12.5px; 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;
}
.plan-main-content { flex: 1; padding: 20px 20px 20px; min-width: 0; }
.todo-row:last-child { margin-bottom: 0; }
/* .plan-avatar-stack: leicht überlappende Avatar-Kreise der Beteiligten in
der kompakten Titelzeile (siehe .board-avatar in styles.css für die
Kreis-/Farb-Definitionen selbst). */
.plan-avatar-stack { display: flex; flex-shrink: 0; }
.plan-avatar-stack .board-avatar { margin-left: -7px; border: 2px solid var(--surface); }
.plan-avatar-stack .board-avatar:first-child { margin-left: 0; }
.todo-row-item.done { opacity: .55; text-decoration: line-through; }
/* Farben aus den Theme-Variablen: `background: var(--text)` mit fester
weißer Schrift ergab im Dunkelmodus weiß auf weiß. */
/* Die Regeln der früheren TODO-Liste (.todo-item, .todo-list-main, .milestone-row …)
sind entfallen: Der Bereich "Aufgaben" rendert seit dem Umbau .plan-task-*
(siehe weiter unten und js/plan/plan-tasks.js). */
.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);
font-size: 13px; opacity: 0; pointer-events: none; transition: opacity .25s, transform .25s;
z-index: 1000; box-shadow: var(--sh-3);
}
.plan-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.plan-resource-grid {
display: grid !important;
grid-template-columns: repeat(auto-fill, minmax(140px, max-content)) !important;
gap: 10px !important;
justify-content: start !important;
}
.plan-resource-card {
padding: 8px 10px !important;
min-height: 0 !important;
width: 140px !important;
max-width: 140px !important;
}
.plan-resource-card h3 {
font-size: 12px !important;
margin-bottom: 2px !important;
}
.plan-resource-clickable { cursor: pointer; transition: box-shadow .15s, transform .15s; }
.plan-resource-clickable:hover { box-shadow: var(--sh-2); transform: translateY(-1px); }
.todo-depends-list {
display: flex;
flex-direction: column;
gap: 4px;
max-height: 180px;
overflow-y: auto;
border: 1px solid var(--line-soft);
border-radius: var(--r-md);
padding: 8px;
background: var(--surface-alt);
}
.todo-depends-item {
display: flex;
align-items: center;
gap: 8px;
padding: 5px 6px;
border-radius: var(--r-sm);
cursor: pointer;
font-size: 12px;
transition: background .15s;
}
.todo-depends-item:hover { background: var(--surface-sunk); }
.todo-depends-item input { flex-shrink: 0; }
.todo-depends-group {
font-size: 11px;
color: var(--text-muted);
margin-top: 6px;
margin-bottom: 2px;
text-transform: uppercase;
letter-spacing: .03em;
}
.todo-depends-group:first-child { margin-top: 0; }
/* Im eingeklappten Bereich trägt bereits das <details> den Rahmen */
.todo-depends-list.flat {
border: none;
background: transparent;
padding: 0;
max-height: 168px;
}
/* Vorgänger, die einen Zirkelbezug erzeugen würden (siehe
cyclicDependencyIds() in js/plan/plan-modals.js) */
.todo-depends-item.is-blocked { color: var(--text-subtle); cursor: not-allowed; opacity: .6; }
.todo-depends-item.is-blocked:hover { background: transparent; }
.todo-depends-note {
margin-left: auto;
font-size: 10.5px;
color: var(--amber);
white-space: nowrap;
}
/* === TODO-Modal (Stufe B) =================================================
Kopfzeile mit Tastaturhinweis, Fehlermeldung am Feld, Dauer-Badge,
Zuständige als Personen-Chips, Status-Segment und eingeklappte
Abhängigkeiten. Befüllt von openTodoModal() in js/plan/plan-modals.js. */
.modal-head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
margin-bottom: 18px;
}
.modal-head h2 { margin: 0; }
.modal-kbd { font-size: 11px; color: var(--text-subtle); white-space: nowrap; }
/* Etwas breiter als die 500 px der Standard-Maske, damit die vier
Schaltflächen der Fußzeile in eine Zeile passen (gleiche Ausnahme wie
#lpModal/#newProjModal in styles.css). */
#todoModal .modal { max-width: 560px; }
/* Fußzeile bleibt stehen, wenn die Abhängigkeiten aufgeklappt sind */
.modal-footer {
position: sticky;
bottom: -28px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
flex-wrap: wrap;
margin: 20px -28px -28px;
padding: 16px 28px;
border-top: 1px solid var(--line-soft);
background: var(--surface-alt);
border-radius: 0 0 var(--r-xl) var(--r-xl);
}
/* Validierungshinweis direkt am Feld statt im alert() */
/* .field-error steht in styles.css: der Passwort-Dialog (js/auth.js) nutzt
sie auch ausserhalb des Projektbereichs. */
.modal input.is-error,
.modal textarea.is-error {
border-color: var(--red);
box-shadow: 0 0 0 3px rgba(215,0,21,.15);
}
.field-inline { display: flex; align-items: center; gap: 8px; }
.field-inline .range-picker-display { flex: 1; }
.field-badge {
font-size: 11px;
font-weight: 500;
color: var(--text-muted);
background: var(--surface-sunk);
border-radius: var(--r-pill);
padding: 3px 9px;
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
/* Zuständige: Kürzel + Name, gleiche Lesart wie die Board-Spalten */
.person-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.person-chip {
display: inline-flex;
align-items: center;
gap: 7px;
background: var(--surface);
color: var(--text-muted);
border: 1px solid var(--line);
border-radius: var(--r-pill);
padding: 4px 12px 4px 4px;
font-size: 12.5px;
font-weight: 500;
transition: border-color .15s var(--ease), background .15s var(--ease), color .15s var(--ease);
}
.person-chip:hover { background: var(--surface); border-color: var(--text-subtle); }
.person-chip-ini {
width: 21px;
height: 21px;
border-radius: 50%;
background: var(--surface-sunk);
color: var(--text-muted);
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 600;
}
.person-chip[aria-pressed="true"] {
background: var(--accent-soft);
border-color: var(--accent);
color: var(--accent);
}
.person-chip[aria-pressed="true"]:hover { background: var(--accent-soft); }
.person-chip[aria-pressed="true"] .person-chip-ini { background: var(--accent); color: #fff; }
/* Hover-Fläche im Status-Segment: eigene Abstufung, weil das Segment auf
--surface-sunk sitzt. Gleiche Drei-Zustands-Logik wie in styles.css —
:root deckt hell ab, die Media Query das System-Dunkel (außer bei
ausdrücklich hell), [data-theme="dark"] die manuelle Umschaltung. */
:root { --seg-hover: rgba(0,0,0,.06); }
@media (prefers-color-scheme: dark) {
html:not([data-theme="light"]) { --seg-hover: rgba(255,255,255,.10); }
}
html[data-theme="dark"] { --seg-hover: rgba(255,255,255,.10); }
/* Status: ersetzt das frühere Paar aus "Erledigt" und Fortschrittsregler */
.segmented {
display: inline-flex;
background: var(--surface-sunk);
border-radius: var(--r-pill);
padding: 2px;
gap: 2px;
width: fit-content;
}
.segmented button {
background: transparent;
color: var(--text-muted);
padding: 5px 14px;
font-size: 12.5px;
border-radius: var(--r-pill);
display: flex;
align-items: center;
gap: 6px;
}
.segmented button:hover { background: var(--seg-hover); }
.segmented button[aria-pressed="true"] {
background: var(--surface);
color: var(--text);
font-weight: 600;
box-shadow: var(--sh-1);
}
.segmented-dot {
width: 7px; height: 7px; border-radius: 50%;
background: currentColor; opacity: .45;
}
.segmented button[aria-pressed="true"] .segmented-dot { opacity: 1; }
.segmented button[data-status="offen"][aria-pressed="true"] .segmented-dot { background: var(--text-subtle); }
.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[hidden] { display: none; }
.progress-row input[type=range] { flex: 1; accent-color: var(--accent); }
.progress-row output {
font-variant-numeric: tabular-nums;
font-size: 12px;
color: var(--text-muted);
min-width: 42px;
text-align: right;
}
/* Abhängigkeiten: selten gebraucht, daher eingeklappt mit Anzahl im Kopf */
.fold {
border: 1px solid var(--line);
border-radius: var(--r-md);
overflow: hidden;
background: var(--surface);
}
.fold > summary {
cursor: pointer;
list-style: none;
padding: 9px 11px;
display: flex;
align-items: center;
gap: 9px;
font-size: 12.5px;
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;
transition: transform .18s var(--ease);
}
.fold[open] > summary .fold-caret { transform: rotate(90deg); }
.fold-count {
margin-left: auto;
font-size: 11px;
font-weight: 600;
background: var(--accent-soft);
color: var(--accent);
border-radius: var(--r-pill);
padding: 1px 9px;
font-variant-numeric: tabular-nums;
}
.fold-count.zero { background: var(--surface-sunk); color: var(--text-subtle); }
.fold-body {
padding: 9px 11px 11px;
border-top: 1px solid var(--line-soft);
display: flex;
flex-direction: column;
gap: 7px;
}
.fold-search { position: relative; }
.fold-search input { width: 100%; padding-left: 28px; }
.fold-search-icon {
position: absolute;
left: 9px;
top: 50%;
transform: translateY(-50%);
color: var(--text-subtle);
font-size: 13px;
pointer-events: none;
}
/* Drag-Handle für TODO- und Meilenstein-Zeilen direkt im GANTT */
.gantt-row.gantt-todo,
.gantt-row.gantt-milestone-row { cursor: default; }
.gantt-row.gantt-todo .gantt-label,
.gantt-row.gantt-milestone-row .gantt-label { display: flex; align-items: center; gap: 8px; }
.gantt-todo-drag {
color: var(--text-subtle); cursor: grab; font-size: 13px; line-height: 1;
user-select: none; flex-shrink: 0;
}
.gantt-row.gantt-todo.dragging,
.gantt-row.gantt-milestone-row.dragging { opacity: .5; }
.gantt-todo-drag:active { cursor: grabbing; }
.gantt-row.gantt-milestone-row .gantt-todo-drag { color: var(--text-subtle); }
/* Cockpit: KPI-Kacheln über dem GANTT (Gesamtfortschritt, offene Aufgaben,
nächster Meilenstein, Team-Auslastung) — siehe renderPlanKpis() in
js/plan/plan-gantt.js. */
.plan-kpi-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
margin-bottom: 16px;
}
.plan-kpi-tile {
background: var(--surface);
border: 1px solid var(--line-soft);
border-radius: var(--r-lg);
padding: 12px 16px;
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;
}
.plan-kpi-tile .kpi-value {
font-size: 22px; font-weight: 700; letter-spacing: -0.02em; 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.warn .kpi-value { color: var(--amber); }
/* Kompakt-Karten im Dashboard (Ressourcen-Auslastung, Dateien & Freigaben,
Verlauf) — springen in den zugehörigen Bereich bzw. öffnen den Verlauf,
siehe showPlanSection()/openHistoryModal(). */
.plan-card-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
gap: 14px;
margin-top: 18px;
}
.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;
}
.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-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;
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.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); }
@media (max-width: 760px) {
.plan-kpi-row { grid-template-columns: repeat(2, 1fr); }
}
/* --- Geister-Balken: Termine der Vorwoche (plan-build-gantt.js) ---
Bewusst ohne Füllung und ohne Zeiger-Ereignisse: sie sind reine
Referenz-Anzeige und dürfen Drag/Resize des echten Balkens darunter
nicht abfangen. */
.gantt-bar.ghost {
background: transparent;
border: 1.5px dashed var(--text-subtle);
opacity: .7;
pointer-events: none;
box-shadow: none;
}
.gantt-milestone.ghost {
background: transparent;
border: 1.5px dashed var(--text-subtle);
opacity: .7;
pointer-events: none;
}
/* --- Urlaubs-Kollision (plan-build-gantt.js) --- */
.gantt-bar.todo.conflict-absence {
outline: 2px solid var(--amber);
outline-offset: 1px;
}
.gantt-conflict-badge {
color: var(--amber);
display: inline-flex;
align-items: center;
flex-shrink: 0;
margin-left: 4px;
cursor: help;
}
/* Hinweisband über dem GANTT (renderPlanWarnings in plan-gantt.js) */
.plan-warning-band {
background: var(--surface);
border: 1px solid var(--line-soft);
border-left: 3px solid var(--amber);
border-radius: var(--r-md);
padding: 10px 14px;
margin-bottom: 12px;
}
.plan-warning-head {
display: flex; align-items: center; gap: 7px;
font-size: 12.5px; font-weight: 600; 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;
}
/* Projektübergreifende Auslastung in der Ressourcen-Karte */
.plan-resource-other {
font-size: 10px; margin-top: 4px; font-weight: 600; 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;
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;
}
.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-badge {
font-size: 10px; font-weight: 600; padding: 2px 7px; border-radius: var(--r-pill);
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 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;
}
.template-admin-list { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; }
.template-admin-row {
display: flex; align-items: center; gap: 8px;
font-size: 12.5px; padding: 4px 6px;
background: var(--surface-alt); border-radius: var(--r-sm);
}
.template-admin-title { flex: 1; min-width: 0; }
.template-add-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.template-add-row input[type=text] { flex: 1 1 200px; min-width: 140px; }
.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-plan-wrap { overflow-x: auto; margin-top: 4px; }
.honorar-table { font-size: 12.5px; }
.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 tfoot th, .honorar-table tfoot td {
border-top: 2px solid var(--line); font-weight: 600; background: var(--surface-alt);
}
.honorar-anteil-grid {
display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
gap: 8px; margin-bottom: 10px;
}
.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-sum.ok { color: var(--green); }
.honorar-sum.warn { color: var(--amber); }
/* Beauftragte Leistungsphasen im Projektinfo */
@media (max-width: 620px) {
.template-head-grid { grid-template-columns: 1fr; }
}
/* Dateien-Modal (Upload, Freigabe, Kommentare) */
/* 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 .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; }
.file-item {
border: 1px solid var(--line-soft); border-radius: var(--r-md);
background: var(--surface-alt); padding: 10px 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;
}
.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-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; }
.file-comment { font-size: 12px; background: var(--surface-sunk); border-radius: var(--r-sm); padding: 6px 8px; }
.file-comment-date { color: var(--text-subtle); font-size: 11px; margin-left: 6px; }
.file-comment-form { display: flex; gap: 6px; margin-top: 6px; }
.file-comment-form input { flex: 1; }
/* === Projektbereich: Bereichs-Navigation und Bereiche ====================
Die Seite ist der EIGENE BEREICH eines Projekts und gliedert sich in fünf
Unterbereiche (Dashboard, Terminplan, Aufgaben, Dateien, Einstellungen),
zwischen denen die Leiste .plan-nav umschaltet (showPlanSection() in
js/plan/plan-sections.js). Alle Bereiche liegen gleichzeitig im DOM und
werden nur ein-/ausgeblendet. */
.plan-nav {
display: flex;
gap: 4px;
padding: 0 24px;
background: var(--surface);
border-bottom: 1px solid var(--line-soft);
overflow-x: auto;
}
.plan-nav-item {
background: transparent;
color: var(--text-muted);
border: none;
border-bottom: 2px solid transparent;
border-radius: 0;
padding: 10px 14px;
font-size: 13px;
font-weight: 500;
white-space: nowrap;
}
.plan-nav-item:hover { color: var(--text); background: var(--surface-alt); }
.plan-nav-item.is-active {
color: var(--accent);
border-bottom-color: var(--accent);
font-weight: 600;
}
.plan-section { display: none; }
.plan-section.is-active { display: block; }
/* Kartenraster der Bereiche (Dashboard, Einstellungen) */
.plan-panel-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 14px;
margin-top: 16px;
}
.plan-panel {
background: var(--surface);
border: 1px solid var(--line-soft);
border-radius: var(--r-lg);
padding: 14px 16px;
}
.plan-panel-wide { grid-column: 1 / -1; }
.plan-panel-title {
font-size: 13px;
font-weight: 600;
margin: 0 0 10px;
display: flex;
align-items: baseline;
gap: 8px;
}
.plan-panel-count {
font-size: 11px;
font-weight: 500;
color: var(--text-subtle);
font-variant-numeric: tabular-nums;
}
.settings-static {
font-size: 13px;
color: var(--text-muted);
padding: 6px 0;
font-variant-numeric: tabular-nums;
}
/* --- Aufgaben-Bereich: Listendarstellung von TODOs und Meilensteinen
(renderPlanTasks() in js/plan/plan-tasks.js). Ein Klick auf eine Zeile
öffnet denselben Dialog wie im GANTT (openTodoModal/openMilestoneModal). */
.plan-task-list { display: flex; flex-direction: column; gap: 6px; }
.plan-task-row {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
background: var(--surface-alt);
border: 1px solid var(--line-soft);
border-radius: var(--r-md);
cursor: pointer;
transition: border-color .15s, background .15s;
}
.plan-task-row:hover { border-color: var(--accent); }
.plan-task-row.is-done .plan-task-title { text-decoration: line-through; color: var(--text-subtle); }
.plan-task-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--text-subtle); }
.plan-task-dot.arbeit { background: var(--amber); }
.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;
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-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; }
/* --- 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-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-kind {
font-size: 10px;
text-transform: uppercase;
letter-spacing: .04em;
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; }
/* === Bereich "Protokolle" (js/plan/plan-protokoll.js) ===
Listenansicht (.protokoll-row je Protokoll) und Detailansicht
(.protokoll-field-grid Kopf, Teilnehmer- und Punkte-Block). Der
Punkte-Block ist ZWEIGETEILT (.protokoll-split): links eine schmale
Liste aller Punkte nach Gruppen (.protokoll-liste), rechts der
Schreibbereich für den gerade ausgewählten (.protokoll-schreiben) —
Begründung bei .protokoll-split weiter unten. Gruppierung bleibt freier
Text, keine feste Liste, siehe CLAUDE.md "### Protokolle".
Das Neu-Kennzeichen ist seit dieser Umstellung ein schlichter Chip
(.protokoll-chip-neu, Gelb-Token --protokoll-neu-bg/-border — bewusst
nicht --band-neu, das im Wochenbericht schon blau "neu kommentiert"
bedeutet) statt einer Einfärbung ganzer Zeilen und Felder; der Status
eines Punkts erscheint als farbiger Punkt im Listeneintrag
(.protokoll-punkt-dot) und als Umschalter im Kopf des Schreibbereichs.
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-row {
display: grid;
grid-template-columns: 64px 1fr 140px 170px 100px;
align-items: center;
gap: 14px;
padding: 11px 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-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-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-back-link { display: flex; align-items: center; gap: 6px; color: var(--text-muted); font-size: 13px;
margin-bottom: 14px; 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; }
/* KI-Erkennung angefordert, aber fehlgeschlagen (kein Schlüssel, Netzwerk-
fehler, unerwartete Antwort …) — eigene, wärmere Farbe als der neutrale
Import-Hinweis darüber, damit ein echter Fehlschlag nicht im selben Ton
wie eine normale Information untergeht. Rein clientseitig für GENAU den
Import, der ihn ausgelöst hat (currentProtokoll._kiFallbackHinweis,
js/plan/plan-protokoll.js) — beim erneuten Öffnen des Protokolls vom
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; }
/* Ladehinweis im Import-Dialog (#protokollImportLoading, Test.html): ohne
ihn wirkte der Dialog während eines länger laufenden KI-Aufrufs (bis zu
KI_TIMEOUT_MS_LOKAL = 30 Minuten bei einem eigenen Server, server.js) wie
hängengeblieben — Felder und Knöpfe werden während der Anfrage zusätzlich
gesperrt (setzeProtokollImportLadezustand(), plan-protokoll.js), damit
kein zweiter Import gleichzeitig losgeschickt wird.
[hidden] MUSS hier explizit auf display:none gesetzt werden: das
HTML-Attribut hidden bewirkt das nur über eine UA-Regel niedrigster
Priorität, die eigene display:flex-Regel direkt darunter hätte sie sonst
ü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-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; }
@keyframes protokoll-import-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
/* "TODOs aus Protokoll" (js/plan/plan-protokoll-todos.js): die drei Segmente
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 .seg.done { background: var(--accent); }
/* Schritt 3 ("Aufgaben bestätigen"), Entwurfsrichtung "B — Kompakte Zeilen"
aus einem zweiten Taste-Skill-Vergleich (Eriks Wahl): eine Zeile je
Vorschlag statt einer ausführlichen Karte — ein echter Testlauf lieferte
bereits 19 Vorschläge aus einem Protokoll, als Karten wäre das nur noch
Scrollen gewesen. Termin/Zuständig stehen als Abzeichen schon in der
eingeklappten Zeile; Beschreibung und die volle Bearbeitung (Termin-Feld,
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-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; }
.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;
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;
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;
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;
transition: transform .15s; flex-shrink: 0; }
.protokoll-todo-vorschlag.open .pt-chevron { transform: rotate(90deg); }
.pt-row-detail { display: none; padding: 0 6px 12px; }
.protokoll-todo-vorschlag.open .pt-row-detail { display: block; }
.protokoll-todo-vorschlag-beschreibung { margin: 2px 0 8px 28px; }
.protokoll-todo-vorschlag-felder { margin-left: 28px; display: flex; flex-direction: column; gap: 6px; }
.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-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-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-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: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 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); }
/* ---------- Punkte: links Liste, rechts Schreibbereich ----------
Eriks Auswahl „Liste + Schreibbereich" aus dem Protokoll-schreiben-Mockup,
Ablösung der früheren durchgehenden Tabelle (eine Zeile je Punkt mit allen
Feldern nebeneinander). Begründung dort und im Kopf von
renderPunkteBlockHtml() (js/plan/plan-protokoll.js): ein Protokollpunkt ist
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-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);
}
/* Gruppen-Kopfzeile: Farbbalken links aus dem Gruppennamen gehasht
(protokollGruppeFarbe(), plan-protokoll.js — dasselbe Prinzip wie
projektFarbe() in der Auslastung), damit eine Gruppe ihre Farbe behält,
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;
background: var(--surface-sunk); border-bottom: 1px solid var(--line-soft);
border-left: 3px solid var(--protokoll-gruppe-farbe, var(--accent));
}
.protokoll-liste-gruppe + .protokoll-liste-gruppe,
.protokoll-liste-zeile + .protokoll-liste-gruppe,
.protokoll-liste-neu + .protokoll-liste-gruppe { border-top: 1px solid var(--line); }
/* Dieselbe !important-Begründung wie bei den übrigen randlosen Feldern
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;
border: none !important; background: none !important; border-radius: 4px !important;
color: var(--text) !important; padding: 2px 3px !important;
}
.protokoll-liste-gruppe input.protokoll-gruppe-heading::placeholder { color: var(--text-subtle); font-weight: 550; }
.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;
}
.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);
border-left: 3px solid transparent;
}
.protokoll-liste-zeile:hover { background: var(--surface-alt); }
.protokoll-liste-zeile.ist-aktiv { background: var(--accent-soft); border-left-color: var(--accent); }
/* Jedes Kind bekommt seinen Platz im Raster AUSDRÜCKLICH zugewiesen. Mit
bloßer Auto-Platzierung zog der Status-Punkt (der als einziger eine
grid-row trug) die erste Spalte an sich, Nummer und Titel rutschten je
eine Spalte weiter und der Titel landete rechtsbündig in der schmalen
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);
}
.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;
}
.protokoll-liste-zeile .titel.ist-leer { font-weight: 500; font-style: italic; color: var(--text-subtle); }
.protokoll-liste-zeile .sub {
grid-column: 2; grid-row: 2; font-size: 10.5px; color: var(--text-subtle);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Das Neu-Kennzeichen steht rechts unter dem Status-Punkt statt in einer
eigenen dritten Zeile — sonst wäre jeder Eintrag der Liste eine Zeile
höher, nur für einen Chip. */
.protokoll-liste-zeile .protokoll-chip-neu { grid-column: 3; grid-row: 2; justify-self: end; }
.protokoll-punkt-dot {
grid-column: 3; grid-row: 1; justify-self: end; align-self: center;
width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0;
}
.protokoll-punkt-dot[data-status="offen"] { background: var(--status-offen); }
.protokoll-punkt-dot[data-status="erledigt"] { background: var(--status-erledigt); }
.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;
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); }
/* ---------- 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 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);
}
.protokoll-schreiben-kopf .nr { font-variant-numeric: tabular-nums; font-weight: 700; font-size: 13px; }
.protokoll-schreiben-kopf .gruppe {
font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-subtle);
}
.protokoll-schreiben-kopf .rechts { margin-left: auto; display: flex; align-items: center; gap: 9px; }
.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;
}
.protokoll-schreiben-feld { padding: 13px 16px; }
.protokoll-schreiben-feld + .protokoll-schreiben-feld { border-top: 1px solid var(--line-soft); }
/* Thema und Text sitzen randlos in ihrem beschrifteten Abschnitt — der
Abschnitt selbst (Linie + Label) sagt schon, wo man schreibt, ein
zusätzlicher Feldrahmen gäbe zwei Kästen umeinander. !important wie
überall hier gegen die Dark-Mode-Fassung von input[type=text]
(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;
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);
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); }
.protokoll-schreiben-feld input.protokoll-punkt-thema:focus,
.protokoll-schreiben-feld .protokoll-punkt-text:focus { outline: none; }
.protokoll-schreiben-feld input.protokoll-punkt-thema:focus-visible,
.protokoll-schreiben-feld .protokoll-punkt-text:focus-visible { box-shadow: 0 0 0 2px var(--accent-soft) inset; }
/* ist-geaendert: NUR das geänderte Feld eines fortgeschriebenen Punkts gelb
markiert (Eriks Wunsch) — derselbe Gelb-Ton wie das Neu-Kennzeichen, hier
aber feldweise, weil der Punkt selbst ja derselbe geblieben ist, nur sein
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;
}
/* Die Formatierungsleiste sitzt zwischen Thema und Text — sie gehört zum
Textfeld darunter, nicht zum Thema darüber (Thema ist reiner Text ohne
Auszeichnung). */
.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);
}
.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;
}
.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);
font-size: 11px; color: var(--text-subtle);
}
.protokoll-schreiben-fuss .hint { font-size: 11px; }
/* ---------- 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);
}
/* 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);
}
.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
mit, die hier wie ein grauer Fleck wirkte. !important nötig: die
Dark-Mode-Fassung von button.secondary hängt ein html-Element vor den
Selektor und gewinnt sonst an Spezifität. */
.protokoll-gruppe-move button, .protokoll-punkt-move button {
padding: 1px 6px; line-height: 1.4; font-size: 11px;
background: transparent !important; color: var(--text-subtle) !important;
}
.protokoll-gruppe-move button:hover:not(:disabled),
.protokoll-punkt-move button:hover:not(:disabled) { color: var(--text) !important; }
.protokoll-gruppe-move button:disabled, .protokoll-punkt-move button:disabled { opacity: .3; cursor: default; }
/* ---------- Status-Umschalter ----------
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;
background: var(--surface-sunk); gap: 1px; width: 56px;
}
.protokoll-status-switch.ist-waagerecht { flex-direction: row; width: auto; border-radius: 980px; }
.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);
text-align: center; transition: background .12s, color .12s;
}
.protokoll-status-switch.ist-waagerecht button { padding: 3px 11px; border-radius: 980px; }
.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); }
.protokoll-status-switch button.offen.is-active { background: var(--status-offen); color: #fff; }
.protokoll-status-switch button.erledigt.is-active { background: var(--status-erledigt); color: #fff; }
.protokoll-status-switch button.info.is-active { background: var(--status-info); color: #fff; }
@media (max-width: 900px){
.protokoll-row { grid-template-columns: 1fr; gap: 4px; }
.protokoll-field-grid { grid-template-columns: 1fr; }
/* Unter 900px stehen Liste und Schreibbereich untereinander — nebeneinander
bliebe für den Text keine lesbare Zeilenlänge mehr. */
.protokoll-split { grid-template-columns: minmax(0, 1fr); }
.protokoll-schreiben-raster { grid-template-columns: 1fr; }
}
.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; }
.add-row-btn:hover { color: var(--accent-hover); }
.legend-swatch { width: 13px; height: 13px; border-radius: 4px; flex-shrink: 0; display: inline-block; }
.legend-swatch.neu { background: var(--protokoll-neu-bg); border: 1.5px solid var(--protokoll-neu-border); }
.legend-swatch.info { background: var(--status-info-bg); border: 1.5px solid var(--status-info); }
/* ============================================================
BEWEGUNG - Stufe "Spürbar", Teil Projektbereich
============================================================
Ergänzung zum gleichnamigen Block am Ende von styles.css; die
Tokens (--dur, --ease-out, --row-lift, --press) stehen dort in
:root und gelten hier mit. Erfasst die Zeilenarten, die es nur
im Projektbereich gibt.
============================================================ */
/* Anklickbare Zeilen: anheben + einfahrende Akzentleiste, exakt wie
die Projektliste. Auch hier als inset-Schatten statt ::before -
die Aufgabenzeilen des GANTT sind ziehbar (plan-drag.js), ein
Stapelkontext auf der Zeile wäre dort riskant. */
.todo-depends-item,
.pt-row-main,
.plan-task-row {
transition: background var(--dur) var(--ease-out),
box-shadow var(--dur) var(--ease-out),
transform var(--dur) var(--ease-out);
}
.todo-depends-item:hover,
.pt-row-main:hover,
.plan-task-row:hover {
transform: translateY(var(--row-lift));
box-shadow: inset 3px 0 0 0 var(--accent);
}
.todo-depends-item:active,
.pt-row-main:active,
.plan-task-row:active { transform: translateY(0); transition-duration: 60ms; }
/* Die Protokoll-Zeile ist der eine Sonderfall: sie trägt bereits einen
eigenen linken Rand (border-left: 3px solid transparent, oben), den
der aktive Punkt auf die Akzentfarbe setzt. Hier NICHT zusätzlich den
inset-Schatten verwenden - beides zusammen ergäbe 6 px Akzent statt 3.
Stattdessen wird genau dieser vorhandene Rand animiert, das Anheben
bleibt identisch zu allen anderen Zeilen. */
.protokoll-liste-zeile {
transition: background var(--dur) var(--ease-out),
border-left-color var(--dur) var(--ease-out),
transform var(--dur) var(--ease-out);
}
.protokoll-liste-zeile:hover {
transform: translateY(var(--row-lift));
border-left-color: var(--accent);
}
.protokoll-liste-zeile:active { transform: translateY(0); transition-duration: 60ms; }
/* Bereichs-Reiter des Projektbereichs: Druckpunkt wie jeder andere
Schalter. Die Unterstreichung des aktiven Reiters bleibt wie sie ist. */
.plan-nav-item { transition: color var(--dur) var(--ease-out),
border-color var(--dur) var(--ease-out),
transform var(--dur) var(--ease-out); }
.plan-nav-item:active { transform: scale(var(--press)); }
/* Aufklapp-Pfeil der Vorschlagszeile ("TODOs aus Protokoll"): dreht
sich jetzt mit derselben Dauer wie der Pfeil der Projektliste
(.board-chev), statt mit einem eigenen Wert. */
.pt-chevron { transition: transform var(--dur) var(--ease-out); }