4822 lines
139 KiB
CSS
4822 lines
139 KiB
CSS
/* === Design-Tokens === */
|
|
:root {
|
|
--accent: #0071e3;
|
|
--accent-hover: #0077ed;
|
|
--accent-active: #006ad1;
|
|
--accent-soft: #e8f1fd;
|
|
|
|
--text: #1d1d1f;
|
|
--text-muted: #6e6e73;
|
|
--text-subtle: #86868b;
|
|
|
|
--bg: #f5f5f7;
|
|
--surface: #ffffff;
|
|
--surface-alt: #fafafc;
|
|
--surface-sunk: #f0f0f2;
|
|
|
|
--line: #d2d2d7;
|
|
--line-soft: #e8e8ed;
|
|
|
|
--green: #248a3d;
|
|
--amber: #b25000;
|
|
--red: #d70015;
|
|
--red-hover: #e8112d;
|
|
--red-active: #b8000f;
|
|
|
|
/* Flächen des Anwesenheits-Kacheln im Zustand "anwesend" — eigene Tokens,
|
|
weil eine feste rgba-Grünfläche im Dark Mode nicht trägt. */
|
|
--attend-bg: rgba(36,138,61,.10);
|
|
--attend-bg-hover: rgba(36,138,61,.16);
|
|
|
|
/* 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;
|
|
|
|
/* Gelbe Markierung neu hinzugekommener Protokoll-Punkte — bewusst eigenes
|
|
Token statt --band-neu (dort blau, bedeutet "neu kommentiertes Projekt"
|
|
im Wochenbericht — eine andere Bedeutung, die hier kollidieren würde). */
|
|
--protokoll-neu-bg: #fff6db;
|
|
--protokoll-neu-border: #e6b800;
|
|
|
|
--r-sm: 6px;
|
|
--r-md: 8px;
|
|
--r-lg: 12px;
|
|
--r-xl: 16px;
|
|
--r-pill: 980px;
|
|
|
|
--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);
|
|
|
|
--ease: cubic-bezier(.4, 0, .2, 1);
|
|
}
|
|
|
|
/* === Basis & Reset === */
|
|
* { box-sizing: border-box; }
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI',
|
|
Roboto, Helvetica, Arial, sans-serif;
|
|
margin: 0;
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
font-size: 13px;
|
|
line-height: 1.45;
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
letter-spacing: -0.005em;
|
|
}
|
|
|
|
.container { padding: 20px 24px; }
|
|
|
|
/* === App-Shell: globales Menüband oben + linke Navigations-Sidebar +
|
|
Hauptbereich (OpenProject-Anordnung: ein durchgehendes globales Menüband
|
|
trägt Marke, aktuellen Kontext [Sitzung] und alle Aktionen/Konto rechts;
|
|
die Sidebar darunter ist reine Modul-Navigation, sonst nichts) === */
|
|
.app-shell { display: flex; flex-direction: column; min-height: 100vh; }
|
|
.app-body { display: flex; flex: 1; min-height: 0; }
|
|
.app-main { flex: 1; min-width: 0; }
|
|
|
|
/* Generisches Icon-System (js/icons.js): Icons skalieren wie ein Zeichen mit
|
|
der umgebenden Schriftgröße (1.1em), erben die Textfarbe über currentColor. */
|
|
.icon { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
|
.icon svg { width: 1.1em; height: 1.1em; display: block; }
|
|
|
|
/* === Globales Menüband (immer sichtbar, alle Breiten) === */
|
|
.app-topbar {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 140;
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
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);
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
|
|
.mobile-nav-toggle { display: inline-flex; }
|
|
@media (min-width: 769px) { .app-topbar .mobile-nav-toggle { display: none; } }
|
|
|
|
.topbar-brand { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
|
.topbar-logo { height: 28px; width: auto; object-fit: contain; }
|
|
.topbar-title {
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
margin: 0;
|
|
letter-spacing: -0.01em;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
|
|
.app-topbar-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
margin-left: auto;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.toolbar-group { display: flex; align-items: center; gap: 4px; }
|
|
|
|
.toolbar-divider {
|
|
width: 1px;
|
|
height: 22px;
|
|
background: var(--line-soft);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.app-topbar-actions {
|
|
order: 4;
|
|
flex: 1 1 100%;
|
|
margin-left: 0;
|
|
overflow-x: auto;
|
|
padding-bottom: 2px;
|
|
}
|
|
}
|
|
|
|
.header-toggle {
|
|
position: relative;
|
|
z-index: 10;
|
|
padding: 6px 10px;
|
|
min-width: 36px;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.theme-toggle-circle {
|
|
width: 34px;
|
|
height: 34px;
|
|
border-radius: 50%;
|
|
padding: 0;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: var(--surface-sunk);
|
|
border: 1px solid var(--line-soft);
|
|
color: var(--text);
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
transition: background .2s var(--ease), color .2s var(--ease), transform .1s var(--ease);
|
|
}
|
|
|
|
.theme-toggle-circle:hover { background: var(--line-soft); }
|
|
.theme-toggle-circle:active { transform: scale(.95); }
|
|
|
|
.icon-btn-danger:hover { background: var(--red); color: #fff; }
|
|
.icon-btn-danger:active { background: var(--red-active); }
|
|
|
|
/* Konto-Menü (Avatar-Knopf rechts im Menüband + Dropdown) */
|
|
.topbar-user { position: relative; }
|
|
|
|
.user-menu-dropdown {
|
|
position: absolute;
|
|
top: calc(100% + 8px);
|
|
right: 0;
|
|
min-width: 220px;
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-lg);
|
|
box-shadow: var(--sh-3);
|
|
padding: 8px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
z-index: 150;
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
transform: translateY(-4px);
|
|
transition: opacity .15s var(--ease), transform .15s var(--ease), visibility .15s var(--ease);
|
|
}
|
|
|
|
.user-menu-dropdown.open {
|
|
opacity: 1;
|
|
visibility: visible;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.user-menu-info {
|
|
padding: 8px 10px 10px;
|
|
margin-bottom: 2px;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* .menu-item: generischer Zeilen-Knopf/-Link (Text + optionales Icon) —
|
|
genutzt im Konto-Dropdown (dort über .user-menu-dropdown volle Breite) UND
|
|
als Basis für die Sidebar-Unterpunkte (siehe .sidebar-subitem). */
|
|
a.menu-item,
|
|
button.menu-item {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
text-align: left;
|
|
background: transparent;
|
|
color: var(--text);
|
|
padding: 8px 10px;
|
|
border: none;
|
|
border-radius: var(--r-md);
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: background .15s var(--ease);
|
|
}
|
|
|
|
a.menu-item:hover,
|
|
button.menu-item:hover { background: var(--surface-sunk); }
|
|
|
|
.user-menu-dropdown a.menu-item,
|
|
.user-menu-dropdown button.menu-item { display: flex; width: 100%; }
|
|
|
|
/* === Seiten-Navigation (links, reine Modul-Navigation) === */
|
|
.side-menu {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
width: 260px;
|
|
max-width: 80vw;
|
|
background: var(--surface);
|
|
border-right: 1px solid var(--line-soft);
|
|
box-shadow: var(--sh-3);
|
|
z-index: 200;
|
|
transform: translateX(-100%);
|
|
transition: transform .3s var(--ease);
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.side-menu.open {
|
|
transform: translateX(0);
|
|
}
|
|
|
|
.side-menu-mobile-header {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
padding: 8px 8px 0;
|
|
}
|
|
@media (min-width: 769px) { .side-menu-mobile-header { display: none; } }
|
|
|
|
.sidebar-nav {
|
|
flex: 1;
|
|
min-height: 0;
|
|
overflow-y: auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
padding: 12px;
|
|
}
|
|
|
|
.sidebar-collapse-bar {
|
|
flex-shrink: 0;
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 100%;
|
|
padding: 12px;
|
|
background: transparent;
|
|
border: none;
|
|
border-top: 1px solid var(--line-soft);
|
|
border-radius: 0;
|
|
color: var(--text-muted);
|
|
cursor: pointer;
|
|
transition: background .2s var(--ease), color .2s var(--ease);
|
|
}
|
|
.sidebar-collapse-bar:hover { background: var(--surface-sunk); color: var(--text); }
|
|
.sidebar-collapse-bar:active { transform: none; }
|
|
|
|
#sidebarCollapseIcon { transition: transform .2s var(--ease); }
|
|
|
|
/* === Show Mode === */
|
|
.show-mode-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: var(--bg);
|
|
z-index: 1000;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.show-mode-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 14px 24px;
|
|
background: var(--surface);
|
|
border-bottom: 1px solid var(--line-soft);
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
line-height: 1.2;
|
|
letter-spacing: -0.01em;
|
|
}
|
|
|
|
.show-mode-content {
|
|
flex: 1;
|
|
overflow: auto;
|
|
padding: 24px;
|
|
}
|
|
|
|
.show-mode-content .container {
|
|
padding: 0;
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.show-mode-content .section-title {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.show-mode-paused {
|
|
position: fixed;
|
|
bottom: 30px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
padding: 12px 24px;
|
|
border-radius: var(--r-pill);
|
|
box-shadow: var(--sh-3);
|
|
font-weight: 600;
|
|
z-index: 1001;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Kompakte Darstellung im Show Mode */
|
|
.show-mode-content {
|
|
font-size: 12px;
|
|
}
|
|
|
|
.show-mode-content .status {
|
|
min-width: 160px !important;
|
|
}
|
|
|
|
.show-mode-content .status-edit {
|
|
min-height: 24px !important;
|
|
padding: 3px 5px !important;
|
|
font-size: 10px !important;
|
|
}
|
|
|
|
.show-mode-content .bar {
|
|
height: 3px !important;
|
|
margin-top: 2px !important;
|
|
}
|
|
|
|
|
|
.show-mode-content .load-grid {
|
|
gap: 14px;
|
|
}
|
|
|
|
/* Im Show Mode enger: Die Auslastung wird dort auf eine Wandfläche geworfen,
|
|
auf der alle Rollen zusammen sichtbar bleiben sollen. */
|
|
.show-mode-content .load-zeile {
|
|
padding: 7px 4px !important;
|
|
}
|
|
|
|
.show-mode-content .load-wer-name {
|
|
font-size: 12px !important;
|
|
}
|
|
|
|
.show-mode-content .load-wert {
|
|
font-size: 16px !important;
|
|
}
|
|
|
|
.show-mode-loading {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100%;
|
|
font-size: 24px;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* Show Mode: Auslastungs-Steuerelemente und Überschrift ausblenden */
|
|
.show-mode-overlay .show-mode-content #load .section-title,
|
|
.show-mode-overlay .show-mode-content #load .toolbar {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Show Mode: Bearbeitung deaktivieren */
|
|
.show-mode-content .board-avatar,
|
|
.show-mode-content .board-lph-row input,
|
|
.show-mode-content .status-edit {
|
|
pointer-events: none !important;
|
|
cursor: default !important;
|
|
}
|
|
|
|
.show-mode-content .del-proj {
|
|
pointer-events: none !important;
|
|
}
|
|
|
|
.show-mode-content input[type=text].edit-name,
|
|
.show-mode-content input[type=checkbox] {
|
|
pointer-events: none !important;
|
|
}
|
|
|
|
.show-mode-content button {
|
|
pointer-events: none !important;
|
|
}
|
|
|
|
.side-menu-backdrop {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0,0,0,.35);
|
|
-webkit-backdrop-filter: blur(2px);
|
|
backdrop-filter: blur(2px);
|
|
z-index: 150;
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
transition: opacity .3s var(--ease), visibility .3s var(--ease);
|
|
}
|
|
|
|
.side-menu.open ~ .side-menu-backdrop {
|
|
opacity: 1;
|
|
visibility: visible;
|
|
}
|
|
|
|
/* Ab 769px: Sidebar dauerhaft sichtbar (kein Off-Canvas mehr nötig) */
|
|
@media (min-width: 769px) {
|
|
#headerMenu.side-menu {
|
|
position: sticky;
|
|
/* top muss der tatsächlichen Höhe von .app-topbar entsprechen (beide
|
|
sticky, gleicher Scroll-Container) — sonst zieht die Sidebar bei
|
|
Seiten, die länger als ein Bildschirm sind, beim Herunterscrollen mit
|
|
top:0 unter das Menüband statt sich direkt darunter einzureihen, und
|
|
am unteren Rand bleibt eine sidebarlose Lücke in Höhe des Menübands
|
|
übrig (height: calc(100vh - 52px) reichte dann nicht bis nach unten). */
|
|
top: 52px;
|
|
height: calc(100vh - 52px);
|
|
transform: none;
|
|
box-shadow: none;
|
|
width: 260px;
|
|
flex: 0 0 260px;
|
|
border-right: 1px solid var(--line-soft);
|
|
}
|
|
#headerMenu.side-menu .header-toggle { display: none; }
|
|
.side-menu-backdrop { display: none; }
|
|
|
|
/* Umschalt-Leiste am unteren Sidebar-Rand nur auf Desktop-Breite sichtbar
|
|
(auf Mobile bleibt es beim reinen Off-Canvas-Menü ohne Zwischenzustand) */
|
|
.sidebar-collapse-bar { display: flex; }
|
|
|
|
/* Eingeklappte Sidebar: nur noch eine schmale Icon-Rail mit den 5
|
|
Navigationspunkten, alle Beschriftungen verschwinden */
|
|
#headerMenu.side-menu.collapsed {
|
|
width: 64px;
|
|
flex: 0 0 64px;
|
|
}
|
|
|
|
#headerMenu.side-menu.collapsed .sidebar-nav {
|
|
padding-left: 8px;
|
|
padding-right: 8px;
|
|
}
|
|
|
|
#headerMenu.side-menu.collapsed .nav-item .nav-label {
|
|
display: none;
|
|
}
|
|
|
|
#headerMenu.side-menu.collapsed .nav-item {
|
|
justify-content: center;
|
|
padding-left: 0;
|
|
padding-right: 0;
|
|
}
|
|
|
|
#headerMenu.side-menu.collapsed #sidebarCollapseIcon {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
/* In der Icon-Rail ergeben aufgeklappte Unterlisten/Rubrik-Überschriften
|
|
ohne Textbeschriftung keinen Sinn — beides wird vollständig ausgeblendet. */
|
|
#headerMenu.side-menu.collapsed .nav-chevron,
|
|
#headerMenu.side-menu.collapsed .sidebar-section-label,
|
|
#headerMenu.side-menu.collapsed .sidebar-subnav {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.toolbar {
|
|
display: flex;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
}
|
|
|
|
button.active {
|
|
background: var(--accent);
|
|
color: #fff;
|
|
border-color: var(--accent);
|
|
}
|
|
|
|
/* Hamburger-Knopf im globalen Menüband (nur < 769px sichtbar, öffnet die
|
|
Sidebar als Off-Canvas-Menü, siehe .mobile-nav-toggle weiter oben). */
|
|
.menu-corner-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 40px;
|
|
height: 40px;
|
|
background: var(--surface-sunk);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-md);
|
|
box-shadow: none;
|
|
color: var(--text);
|
|
cursor: pointer;
|
|
font-size: 18px;
|
|
transition: background .2s var(--ease);
|
|
}
|
|
|
|
.menu-corner-btn:hover { background: var(--line-soft); }
|
|
.menu-corner-btn:active { transform: none; }
|
|
|
|
/* Hauptnavigation (Sidebar) — ersetzt die alte horizontale .tabs-Leiste */
|
|
.sidebar-nav { gap: 2px; }
|
|
|
|
.nav-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
width: 100%;
|
|
text-align: left;
|
|
text-decoration: none;
|
|
background: transparent;
|
|
color: var(--text-muted);
|
|
padding: 9px 12px;
|
|
cursor: pointer;
|
|
border: none;
|
|
border-radius: var(--r-md);
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
transition: background .2s var(--ease), color .2s var(--ease);
|
|
}
|
|
|
|
.nav-icon {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 18px;
|
|
flex-shrink: 0;
|
|
font-size: 15px;
|
|
}
|
|
|
|
.nav-label {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* .nav-item kann ein echter <a href>-Link sein statt eines Buttons — ohne
|
|
diese Regel würde ein bereits besuchtes Ziel (echte Browser-Historie) mit
|
|
der UA-Standardfarbe für besuchte Links abweichen. */
|
|
.nav-item:visited { color: var(--text-muted); }
|
|
.nav-item:hover,
|
|
.nav-item:visited:hover { background: var(--surface-sunk); color: var(--text); }
|
|
|
|
.nav-item.active {
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* .sidebar-section-label: kleine Rubrik-Überschrift oberhalb einer Gruppe von
|
|
Sidebar-Einträgen (z. B. "Dashboard", "Navigation"). */
|
|
.sidebar-section-label {
|
|
padding: 10px 12px 2px;
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
letter-spacing: .04em;
|
|
text-transform: uppercase;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* .nav-group-toggle: Sidebar-Eintrag, der statt eines Tabs einen
|
|
auf-/zuklappbaren Unterbereich steuert (Einstellungen/Admin, siehe
|
|
toggleSidebarAccordion() in js/ui.js). */
|
|
.nav-chevron {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 14px;
|
|
flex-shrink: 0;
|
|
margin-left: auto;
|
|
transition: transform .2s var(--ease);
|
|
}
|
|
|
|
.nav-group-toggle.expanded .nav-chevron { transform: rotate(180deg); }
|
|
|
|
/* .sidebar-subnav: Liste der Aktionen unter einem aufgeklappten
|
|
.nav-group-toggle, per max-height animiert ein-/ausgeblendet. */
|
|
.sidebar-subnav {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1px;
|
|
padding-left: 8px;
|
|
max-height: 0;
|
|
opacity: 0;
|
|
overflow: hidden;
|
|
transition: max-height .25s var(--ease), opacity .2s var(--ease);
|
|
}
|
|
|
|
.sidebar-subnav.open {
|
|
/* Reicht für die längste Gruppe („Einstellungen", sieben Punkte); die
|
|
Animation läuft über max-height, deshalb steht hier eine feste Zahl. */
|
|
max-height: 360px;
|
|
opacity: 1;
|
|
}
|
|
|
|
.sidebar-subitem {
|
|
width: 100%;
|
|
padding-left: 34px;
|
|
font-size: 12.5px;
|
|
color: var(--text-muted);
|
|
}
|
|
.sidebar-subitem:hover { color: var(--text); }
|
|
/* .is-active: der gerade gezeigte Abschnitt der Gruppe „Einstellungen"
|
|
(showSettingsSection() in js/settings/settings.js). Die übrigen Gruppen
|
|
lösen Aktionen aus und kennen deshalb keinen dauerhaft aktiven Punkt. */
|
|
.sidebar-subitem.is-active {
|
|
color: var(--accent);
|
|
font-weight: 600;
|
|
background: var(--accent-soft);
|
|
}
|
|
.sidebar-subitem.danger { color: var(--red); }
|
|
.sidebar-subitem.danger:hover { background: var(--red); color: #fff; }
|
|
|
|
/* === Buttons & Formulare === */
|
|
button {
|
|
cursor: pointer;
|
|
border: none;
|
|
border-radius: var(--r-pill);
|
|
padding: 7px 16px;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
font-family: inherit;
|
|
background: var(--accent);
|
|
color: #fff;
|
|
letter-spacing: -0.01em;
|
|
transition: background .2s var(--ease), transform .1s var(--ease),
|
|
box-shadow .2s var(--ease);
|
|
}
|
|
|
|
button:hover { background: var(--accent-hover); }
|
|
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);
|
|
}
|
|
|
|
button.secondary {
|
|
background: rgba(0,0,0,.06);
|
|
color: var(--text);
|
|
}
|
|
button.secondary:hover { background: rgba(0,0,0,.10); }
|
|
button.secondary:active { background: rgba(0,0,0,.14); }
|
|
|
|
button.danger { background: var(--red); }
|
|
button.danger:hover { background: var(--red-hover); }
|
|
button.danger:active { background: var(--red-active); }
|
|
|
|
button.small {
|
|
padding: 3px 10px;
|
|
font-size: 11px;
|
|
}
|
|
|
|
select,
|
|
input[type=text],
|
|
input[type=email],
|
|
input[type=date] {
|
|
padding: 7px 10px;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--r-md);
|
|
font-size: 13px;
|
|
font-family: inherit;
|
|
color: var(--text);
|
|
background: var(--surface);
|
|
transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
|
|
}
|
|
|
|
select:focus,
|
|
input[type=text]:focus,
|
|
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);
|
|
}
|
|
|
|
select {
|
|
-webkit-appearance: none;
|
|
-moz-appearance: none;
|
|
appearance: none;
|
|
padding-right: 28px;
|
|
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath fill='%236e6e73' d='M0 0h10L5 6z'/%3E%3C/svg%3E");
|
|
background-repeat: no-repeat;
|
|
background-position: right 10px center;
|
|
background-color: var(--surface);
|
|
}
|
|
|
|
.role-checkboxes {
|
|
display: flex;
|
|
gap: 12px;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
}
|
|
|
|
.role-checkboxes label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
input[type=checkbox] { accent-color: var(--accent); }
|
|
|
|
/* === Tabellen & Matrix === */
|
|
table {
|
|
border-collapse: separate;
|
|
border-spacing: 0;
|
|
width: 100%;
|
|
background: var(--surface);
|
|
font-size: 12px;
|
|
}
|
|
|
|
th,
|
|
td {
|
|
border: 1px solid var(--line-soft);
|
|
padding: 5px 7px;
|
|
text-align: center;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
thead tr:nth-child(1) th {
|
|
background: var(--surface-sunk);
|
|
color: var(--text);
|
|
font-weight: 600;
|
|
border: 1px solid var(--line);
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 10;
|
|
}
|
|
|
|
tr:nth-child(even) td { background: var(--surface-alt); }
|
|
|
|
/* === Status-Felder in der Projektzeile === */
|
|
.status {
|
|
min-width: 240px;
|
|
position: relative;
|
|
vertical-align: top;
|
|
}
|
|
|
|
.status-edit {
|
|
width: 100%;
|
|
min-height: 34px;
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-sm);
|
|
padding: 5px 7px;
|
|
font-size: 11px;
|
|
font-family: inherit;
|
|
line-height: 1.4;
|
|
color: var(--text);
|
|
background: var(--surface);
|
|
text-align: left;
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
|
|
}
|
|
|
|
.status-edit:focus {
|
|
outline: none;
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 3px rgba(0,113,227,.18);
|
|
}
|
|
|
|
.status-edit.status-new { color: var(--green); }
|
|
.status-edit.status-duplicated { color: var(--text); }
|
|
.status-edit p { margin: 0 0 4px; }
|
|
.status-edit p:last-child { margin-bottom: 0; }
|
|
.status-edit b,
|
|
.status-edit strong { font-weight: 600; }
|
|
|
|
/* === Kommentar-Editor im Board und im Wochenbericht ======================
|
|
Ersetzt das frühere contenteditable-Feld samt execCommand-Leiste: Textfeld
|
|
mit Verfasser-Kopfzeile, ausdrücklichem Speichern und dem eingeklappten,
|
|
scrollbaren Verlauf der früheren Sitzungen. Aufgebaut von
|
|
renderCommentEditor() in js/board/board.js. */
|
|
|
|
.comment-block { display: flex; flex-direction: column; gap: 10px; }
|
|
|
|
.comment-editor {
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--r-md);
|
|
background: var(--surface);
|
|
overflow: hidden;
|
|
}
|
|
.comment-editor-head,
|
|
.comment-head-line {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
padding: 6px 10px;
|
|
font-size: 11px;
|
|
color: var(--text-muted);
|
|
background: var(--surface-alt);
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.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-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;
|
|
}
|
|
.comment-kbd { margin-left: auto; font-size: 10px; color: var(--text-subtle); white-space: nowrap; }
|
|
|
|
.comment-editor textarea {
|
|
width: 100%;
|
|
display: block;
|
|
border: none;
|
|
border-radius: 0;
|
|
padding: 8px 10px;
|
|
font-family: inherit;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
color: var(--text);
|
|
background: var(--surface);
|
|
resize: vertical;
|
|
min-height: 62px;
|
|
}
|
|
.comment-editor textarea:focus { outline: none; box-shadow: none; }
|
|
.comment-editor textarea::placeholder { color: var(--text-subtle); }
|
|
|
|
.comment-editor-foot {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 7px;
|
|
padding: 7px 10px;
|
|
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-readonly {
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-md);
|
|
padding: 7px 9px;
|
|
font-size: 11.5px;
|
|
line-height: 1.45;
|
|
background: var(--surface);
|
|
}
|
|
|
|
/* Verlauf: eingeklappt, mit Anzahl im Kopf; die Liste selbst scrollt */
|
|
.comment-history {
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-md);
|
|
background: var(--surface);
|
|
overflow: hidden;
|
|
}
|
|
.comment-history > summary {
|
|
cursor: pointer;
|
|
list-style: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 7px 10px;
|
|
font-size: 11.5px;
|
|
color: var(--text);
|
|
user-select: none;
|
|
}
|
|
.comment-history > summary::-webkit-details-marker { display: none; }
|
|
.comment-history > summary:hover { background: var(--surface-alt); }
|
|
.comment-history-caret {
|
|
color: var(--text-subtle);
|
|
font-size: 9px;
|
|
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;
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
border-radius: var(--r-pill);
|
|
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-list {
|
|
max-height: 220px;
|
|
overflow-y: auto;
|
|
overscroll-behavior: contain;
|
|
}
|
|
.comment-history-entry { padding: 8px 0; }
|
|
.comment-history-entry + .comment-history-entry { border-top: 1px solid var(--line-soft); }
|
|
.comment-history-head {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 3px;
|
|
font-size: 10.5px;
|
|
}
|
|
.comment-history-week {
|
|
font-weight: 600;
|
|
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 b,
|
|
.comment-history-text strong { font-weight: 600; color: var(--text); }
|
|
|
|
.comment-take {
|
|
margin-left: auto;
|
|
padding: 2px 9px;
|
|
font-size: 10px;
|
|
border-radius: var(--r-pill);
|
|
background: transparent;
|
|
color: var(--text-muted);
|
|
border: 1px solid var(--line);
|
|
flex-shrink: 0;
|
|
}
|
|
.comment-take:hover { background: var(--surface-sunk); color: var(--text); }
|
|
|
|
.status-toolbar {
|
|
display: none;
|
|
position: absolute;
|
|
bottom: 100%;
|
|
left: 0;
|
|
margin-bottom: 4px;
|
|
background: rgba(255,255,255,.9);
|
|
-webkit-backdrop-filter: saturate(180%) blur(16px);
|
|
backdrop-filter: saturate(180%) blur(16px);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-md);
|
|
padding: 3px;
|
|
gap: 2px;
|
|
box-shadow: var(--sh-2);
|
|
z-index: 10;
|
|
}
|
|
|
|
.status:focus-within .status-toolbar { display: flex; }
|
|
|
|
.status-toolbar button {
|
|
padding: 3px 7px;
|
|
font-size: 11px;
|
|
line-height: 1.2;
|
|
min-width: 24px;
|
|
border-radius: var(--r-sm);
|
|
background: transparent;
|
|
color: var(--text);
|
|
border: none;
|
|
}
|
|
|
|
.status-toolbar button:hover { background: rgba(0,0,0,.06); }
|
|
.status-toolbar button:active { background: rgba(0,0,0,.10); transform: none; }
|
|
|
|
.status-toolbar button.color-red { color: var(--red); }
|
|
.status-toolbar button.color-green { color: var(--green); }
|
|
.status-toolbar button.color-blue { color: var(--accent); }
|
|
.status-toolbar button.color-black {
|
|
color: var(--text);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.locked-cell {
|
|
cursor: not-allowed !important;
|
|
background: var(--surface-sunk) !important;
|
|
opacity: .65;
|
|
}
|
|
|
|
.locked-cell input {
|
|
background: var(--surface-sunk) !important;
|
|
cursor: not-allowed !important;
|
|
border-color: var(--line-soft) !important;
|
|
}
|
|
|
|
.bar {
|
|
height: 5px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--line-soft);
|
|
margin-top: 4px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.bar > div {
|
|
height: 100%;
|
|
background: var(--green);
|
|
border-radius: var(--r-pill);
|
|
transition: width .3s var(--ease);
|
|
}
|
|
|
|
/* === Projektboard (Listenansicht) ===
|
|
Eine Bubble-Card je Projektgruppe (.board-list) mit den Projekten als
|
|
Listenzeilen (.board-row) — ersetzt die frühere breite Matrix (eine Spalte
|
|
je Person/Leistungsphase). Jede Zeile zeigt nur das Nötigste auf einen
|
|
Blick (Kürzel-Avatare der Zugeordneten, aktive Phase, Status-Vorschau);
|
|
Klick auf die Zeile klappt darunter das Detailpanel (.board-drawer) mit
|
|
Status-Editor, vollständiger Rollen-Zuordnung und allen LPH-Balken auf. */
|
|
.board-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-xl);
|
|
box-shadow: var(--sh-2);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.board-row { border-bottom: 1px solid var(--line-soft); }
|
|
.board-row:last-child { border-bottom: none; }
|
|
|
|
.board-row-main {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
padding: 12px 16px;
|
|
cursor: pointer;
|
|
transition: background .15s var(--ease);
|
|
}
|
|
.board-row-main:hover { background: var(--surface-sunk); }
|
|
|
|
.board-chev {
|
|
flex-shrink: 0;
|
|
color: var(--text-subtle);
|
|
display: inline-flex;
|
|
transition: transform .2s var(--ease);
|
|
}
|
|
.board-row.open .board-chev { transform: rotate(90deg); }
|
|
|
|
.board-nr {
|
|
flex-shrink: 0;
|
|
width: 64px;
|
|
font-size: 11.5px;
|
|
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;
|
|
cursor: pointer;
|
|
}
|
|
.board-name:hover { color: var(--accent); text-decoration: underline; }
|
|
|
|
.board-status-line {
|
|
margin-top: 3px;
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.board-newdot {
|
|
flex-shrink: 0;
|
|
width: 7px;
|
|
height: 7px;
|
|
border-radius: 50%;
|
|
background: var(--green);
|
|
}
|
|
|
|
.board-avatar-stack {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 4px;
|
|
max-width: 220px;
|
|
}
|
|
|
|
.board-avatar {
|
|
flex-shrink: 0;
|
|
width: 26px;
|
|
height: 26px;
|
|
border-radius: 50%;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
letter-spacing: -0.02em;
|
|
color: var(--text-muted);
|
|
background: var(--surface-sunk);
|
|
border: 1px solid var(--line-soft);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
transition: background .15s var(--ease), color .15s var(--ease), box-shadow .15s var(--ease);
|
|
}
|
|
|
|
.board-avatar.role-planung.state-1 { background: var(--green); border-color: var(--green); color: #fff; }
|
|
.board-avatar.role-projektleitung.state-1 { background: var(--red); border-color: var(--red); color: #fff; }
|
|
.board-avatar.role-bauüberwachung.state-1 { background: var(--accent); border-color: var(--accent); color: #fff; }
|
|
|
|
.board-avatar.role-planung.state-2 { background: transparent; color: var(--green); border-color: var(--green); }
|
|
.board-avatar.role-projektleitung.state-2 { background: transparent; color: var(--red); border-color: var(--red); }
|
|
.board-avatar.role-bauüberwachung.state-2 { background: transparent; color: var(--accent); border-color: var(--accent); }
|
|
|
|
.phase-pill {
|
|
flex-shrink: 0;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
font-family: ui-monospace, 'SF Mono', monospace;
|
|
padding: 4px 10px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
white-space: nowrap;
|
|
}
|
|
.phase-pill.muted { background: var(--surface-sunk); color: var(--text-subtle); font-family: inherit; font-weight: 500; }
|
|
|
|
/* --- Detailpanel (.board-drawer) --- */
|
|
.board-drawer {
|
|
padding: 18px 20px 22px 94px;
|
|
background: var(--surface-alt);
|
|
border-top: 1px solid var(--line-soft);
|
|
}
|
|
|
|
.board-drawer h4 {
|
|
margin: 0 0 8px;
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: .05em;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* Die Schublade liefert drei gleichrangige Blöcke (Kommentar, Leistungsphasen,
|
|
Beteiligte, siehe renderBoardDrawer() in js/board/board.js). Im Projektboard
|
|
stehen Kommentar und Leistungsphasen wie bisher übereinander in der linken
|
|
Spalte, die Beteiligten rechts daneben. */
|
|
.board-drawer-grid {
|
|
display: grid;
|
|
grid-template-columns: 1.3fr 1fr;
|
|
grid-template-areas:
|
|
"kommentar beteiligte"
|
|
"lph beteiligte";
|
|
align-content: start;
|
|
gap: 16px 24px;
|
|
}
|
|
.drawer-col-comment { grid-area: kommentar; }
|
|
.drawer-col-lph { grid-area: lph; }
|
|
.drawer-col-people { grid-area: beteiligte; }
|
|
|
|
@media (max-width: 720px) {
|
|
.board-drawer-grid {
|
|
grid-template-columns: 1fr;
|
|
grid-template-areas: "kommentar" "lph" "beteiligte";
|
|
}
|
|
}
|
|
|
|
/* Auswahl der beauftragten Leistungsphasen. Genutzt vom Honorar-Dialog der
|
|
Projektplan-Seite (renderHonorarEingaben(), js/plan/plan-honorar.js) und
|
|
vom Neues-Projekt-Modal (openNewProjModal(), js/load/load.js) — deshalb
|
|
hier im gemeinsamen Stylesheet statt inline in einer der beiden Seiten. */
|
|
.beauftragte-lp-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
|
|
gap: 4px 10px;
|
|
}
|
|
.beauftragte-lp-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 12px;
|
|
color: var(--text);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* --- Wochenbericht: immer aufgeklappte Projekt-Karten ("Neu kommentiert",
|
|
"Fortschritt aktualisiert") — im Unterschied zu .board-list/.board-row
|
|
(Akkordeon der "Unverändert"-Gruppe) ist hier jede Karte ein eigenständiger
|
|
Kasten, kein Container mit Trennlinien. */
|
|
.report-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
}
|
|
.report-card {
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-md);
|
|
box-shadow: var(--sh-1);
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* Kopfband: durchgefärbt in der Farbe der Änderungsart, damit beim Scrollen
|
|
ohne Blick auf die Abschnitts-Überschrift erkennbar ist, worum es geht.
|
|
Die Farbe kommt aus --band-neu/--band-fortschritt und lässt sich dort in
|
|
einem Zug abschwächen, falls die Leiste zu kräftig wirkt. */
|
|
.report-card-head {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
flex-wrap: wrap;
|
|
padding: 9px 14px;
|
|
background: var(--surface-alt);
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.report-card-head .board-name { cursor: pointer; }
|
|
|
|
.report-card-neu > .report-band { background: var(--band-neu); }
|
|
.report-card-fortschritt > .report-band { background: var(--band-fortschritt); }
|
|
|
|
.report-band {
|
|
border-bottom: none;
|
|
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:hover { text-decoration: underline; }
|
|
.report-band .tag-chip {
|
|
background: rgba(255,255,255,.22);
|
|
color: #fff;
|
|
border-color: transparent;
|
|
}
|
|
.report-band .report-reason-badge {
|
|
background: rgba(255,255,255,.22);
|
|
color: #fff;
|
|
}
|
|
|
|
/* Drei Spalten statt zwei: im Bericht stehen Leistungsphasen und Beteiligte
|
|
nebeneinander, wodurch die Karte flacher wird. Dasselbe Markup wie im
|
|
Projektboard, nur anders angeordnet. */
|
|
.report-card .board-drawer {
|
|
padding: 14px 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;
|
|
}
|
|
.report-card .board-role-label { width: 58px; }
|
|
|
|
@media (max-width: 860px) {
|
|
.report-card .board-drawer-grid {
|
|
grid-template-columns: 1fr;
|
|
grid-template-areas: "kommentar" "lph" "beteiligte";
|
|
gap: 16px;
|
|
}
|
|
}
|
|
|
|
/* === Dichte Fassung der Karte (.board-drawer-dicht, Wochenbericht) ===
|
|
Gleiche Angaben, gleiche Bedienelemente, enger gesetzt. Den Ausschlag gibt
|
|
die Leistungsphasen-Leiste: als Zeilen untereinander bestimmten bis zu zehn
|
|
Phasen die Höhe der ganzen Karte — bei 29 Projekten wurde der Bericht damit
|
|
rund 17 Bildschirmseiten lang. Nebeneinander braucht dieselbe Information
|
|
eine Zeile. */
|
|
.board-drawer-dicht .board-drawer-grid {
|
|
/* Die Beteiligten brauchen so viel Breite wie der Kommentar: Sobald ihre
|
|
Kürzel umbrechen, bestimmt ihre Spalte die Höhe der ganzen Karte. Mit
|
|
1.45/1.15/1 waren es 14,2 Bildschirmseiten, mit gleich breiter
|
|
Beteiligten-Spalte 11,6 — mehr Breite bringt darüber hinaus nichts,
|
|
weil dann ohnehin nichts mehr umbricht. */
|
|
/* Die rechte Spalte bekommt eine MINDESTBREITE: Zehn Phasenfelder in einer
|
|
reinen fr-Spalte wurden 27 px schmal, und "100" passte nicht mehr ins
|
|
Eingabefeld — 79 Werte waren abgeschnitten. Unter 620 px Containerbreite
|
|
gibt die Mindestbreite nach und die Spalten rutschen untereinander. */
|
|
grid-template-columns: minmax(0, 1fr) minmax(340px, 1fr);
|
|
grid-template-areas: "kommentar kompakt";
|
|
gap: 18px;
|
|
}
|
|
@media (max-width: 860px) {
|
|
.board-drawer-dicht .board-drawer-grid {
|
|
grid-template-columns: 1fr;
|
|
grid-template-areas: "kommentar" "kompakt";
|
|
gap: 14px;
|
|
}
|
|
}
|
|
.drawer-col-kompakt { grid-area: kompakt; min-width: 0; }
|
|
/* Die zweite Überschrift in derselben Spalte braucht Abstand nach oben, den
|
|
die erste (am Spaltenanfang) nicht haben darf. */
|
|
.drawer-h4-zweit { margin-top: 12px; }
|
|
|
|
.board-lph-leiste {
|
|
display: flex;
|
|
gap: 3px;
|
|
align-items: stretch;
|
|
}
|
|
.board-lph-cell {
|
|
flex: 1 1 0;
|
|
min-width: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 1px;
|
|
padding: 3px 2px 4px;
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-sm);
|
|
background: var(--surface-sunk);
|
|
/* Der Füllstand kommt als senkrechter Verlauf aus dem Inline-Stil
|
|
(renderBoardDrawer in js/board/board.js) — so bleibt der Balken erhalten,
|
|
den die Zeilenform als eigenes Element hatte. */
|
|
background-repeat: no-repeat;
|
|
}
|
|
.board-lph-cell-label {
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
color: var(--text-muted);
|
|
line-height: 1.2;
|
|
}
|
|
.board-lph-cell input {
|
|
width: 100%;
|
|
min-width: 0;
|
|
padding: 1px 2px;
|
|
border: none;
|
|
background: transparent;
|
|
text-align: center;
|
|
font-size: 11.5px;
|
|
font-variant-numeric: tabular-nums;
|
|
color: var(--text);
|
|
font-family: inherit;
|
|
}
|
|
.board-lph-cell input:focus {
|
|
outline: 1.5px solid var(--accent);
|
|
outline-offset: -1px;
|
|
border-radius: 3px;
|
|
}
|
|
.board-lph-cell.lp-aktiv {
|
|
border-color: var(--accent);
|
|
}
|
|
.board-lph-cell.lp-aktiv .board-lph-cell-label,
|
|
.board-lph-cell.lp-aktiv input { color: var(--accent); }
|
|
.board-lph-cell.locked-cell input { cursor: default; }
|
|
|
|
/* Das Rollen-Label steht NEBEN seinen Kürzeln. Über ihnen kostete es drei
|
|
zusätzliche Zeilen, und damit bestimmte die Beteiligten-Spalte die Höhe der
|
|
ganzen Karte (189 px gegenüber 130 für den Kommentar). Die feste Breite ist
|
|
so bemessen, dass "Bauüberwachung" hineinpasst — bei 52 px lief die
|
|
Beschriftung über die Kürzel.
|
|
|
|
Die Regeln hängen am Merkmal .board-drawer-dicht, nicht am Ort: Sie
|
|
standen zunächst unter .report-card, und mit dem Umbau des Wochenberichts
|
|
auf die Tagesordnung gab es diesen Container nicht mehr — die dichte
|
|
Karte fiel still auf die Board-Darstellung zurück. Das zusätzliche
|
|
.board-role-mini liefert die Spezifität, die nötig ist, um die dortige
|
|
Regel für .board-role-row zu schlagen. */
|
|
.board-drawer-dicht .board-role-mini .board-role-row {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 7px;
|
|
margin-bottom: 4px;
|
|
}
|
|
.board-drawer-dicht .board-role-mini .board-role-label {
|
|
flex: 0 0 auto;
|
|
/* Bemessen am längsten Rollennamen: "BAUÜBERWACHUNG" braucht bei 10 px in
|
|
Versalien diese Breite — bei 88 px fehlte der letzte Buchstabe. */
|
|
width: 104px;
|
|
padding-top: 4px;
|
|
font-size: 10px;
|
|
line-height: 1.25;
|
|
letter-spacing: .02em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
/* Schmale Fenster: Dort reicht die Breite für Label UND Kürzel nicht mehr,
|
|
also wieder übereinander — lieber drei Zeilen mehr als abgeschnittene
|
|
Beschriftungen. */
|
|
@media (max-width: 1100px) {
|
|
.board-drawer-dicht .board-role-mini .board-role-row { display: block; }
|
|
.board-drawer-dicht .board-role-mini .board-role-label {
|
|
width: auto;
|
|
padding-top: 0;
|
|
margin-bottom: 2px;
|
|
}
|
|
}
|
|
|
|
.report-reason-badge {
|
|
margin-left: auto;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
padding: 3px 10px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
white-space: nowrap;
|
|
}
|
|
/* Innerhalb einer Report-Karte braucht das Detailpanel nicht den
|
|
Zeilen-Einzug/die obere Trennlinie, die es im Board-Akkordeon ausrichtet. */
|
|
.report-card .board-drawer {
|
|
padding: 16px 20px 20px;
|
|
border-top: none;
|
|
}
|
|
|
|
.board-lph-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 7px;
|
|
margin-top: 14px;
|
|
}
|
|
|
|
.board-lph-row {
|
|
display: grid;
|
|
grid-template-columns: 42px 1fr 50px;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.board-lph-row .bar { flex: 1; margin-top: 0; }
|
|
|
|
.board-lph-label {
|
|
font-size: 11px;
|
|
font-family: ui-monospace, 'SF Mono', monospace;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.board-lph-row input {
|
|
width: 100%;
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-sm);
|
|
padding: 3px 6px;
|
|
text-align: center;
|
|
font-size: 11px;
|
|
font-family: inherit;
|
|
background: var(--surface);
|
|
color: var(--text);
|
|
}
|
|
|
|
.board-lph-row.lp-aktiv .board-lph-label { color: var(--accent); font-weight: 600; }
|
|
.board-lph-row.lp-aktiv input { border-color: var(--accent); font-weight: 600; }
|
|
|
|
.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 .board-role-label {
|
|
width: 100px;
|
|
flex-shrink: 0;
|
|
font-size: 11.5px;
|
|
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;
|
|
color: var(--text);
|
|
letter-spacing: -0.02em;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
/* === Lade-/Auswertungsübersicht === */
|
|
.load-grid {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 24px;
|
|
width: 100%;
|
|
}
|
|
|
|
.load-row {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
gap: 16px;
|
|
align-items: start;
|
|
width: 100%;
|
|
}
|
|
|
|
/* === Auslastung: das Lastband ===
|
|
Eine Zeile je Person und Rolle; der Balken ist nach Projekten aufgeteilt.
|
|
Zuvor stand jede Person in einer eigenen .load-card mit ihrer Projektliste
|
|
klein darunter — man sah die Zahl, aber nicht, woraus sie besteht. Die
|
|
Frage nach einer Auslastung von 1,80 ist aber immer dieselbe: aus einem
|
|
großen Projekt oder aus fünf kleinen, und was davon lässt sich abgeben?
|
|
.load-card/.load-row/.load-num/.load-detail bleiben bestehen — das
|
|
Dashboard (js/dashboard/dashboard.js) und die Ressourcenansicht des
|
|
Projektbereichs (js/plan/plan-gantt.js) bauen darauf auf. */
|
|
.load-rolle { width: 100%; }
|
|
|
|
.load-rolle-titel {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
margin: 0 0 6px;
|
|
color: var(--text-muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: .04em;
|
|
}
|
|
|
|
.load-zeile {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
padding: 11px 4px;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.load-zeile:last-child { border-bottom: none; }
|
|
.load-zeile:hover { background: var(--surface); }
|
|
|
|
/* Wer — Name oben, Kürzel und Zusätze darunter. Feste Breite, damit die
|
|
Bänder aller Zeilen an derselben Stelle beginnen und vergleichbar sind. */
|
|
.load-wer {
|
|
flex: 0 0 200px;
|
|
min-width: 0;
|
|
}
|
|
.load-wer-name {
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.load-wer-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
flex-wrap: wrap;
|
|
font-size: 11px;
|
|
color: var(--text-subtle);
|
|
margin-top: 1px;
|
|
}
|
|
|
|
/* Das Band. Die Segmente füllen es von links; was frei bleibt, ist die
|
|
Restkapazität bis zum Skalenende (Vorgabe 8, firmenweit einstellbar). */
|
|
.load-band {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
height: 22px;
|
|
min-width: 140px;
|
|
background: var(--surface-sunk);
|
|
border-radius: var(--r-sm);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.load-seg {
|
|
display: flex;
|
|
align-items: center;
|
|
height: 100%;
|
|
padding: 0 7px;
|
|
min-width: 3px;
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
color: #fff;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
border-right: 1px solid rgba(255,255,255,.4);
|
|
transition: filter .15s var(--ease);
|
|
}
|
|
.load-seg:last-of-type { border-right: none; }
|
|
.load-seg:hover { filter: brightness(1.12); }
|
|
.load-seg span { overflow: hidden; }
|
|
|
|
.load-band-leer {
|
|
font-size: 11px;
|
|
color: var(--text-subtle);
|
|
padding-left: 9px;
|
|
}
|
|
|
|
.load-wert {
|
|
flex: 0 0 62px;
|
|
text-align: right;
|
|
font-size: 19px;
|
|
font-weight: 600;
|
|
letter-spacing: -.02em;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
.load-anbahnung {
|
|
font-size: 10px;
|
|
padding: 1px 7px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--surface-sunk);
|
|
color: var(--text-muted);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Kopfzeile: was die Zahlen abdecken. Sie steht oben, weil die Aussagekraft
|
|
der ganzen Seite daran hängt — eine Auslastung aus drei von 29 Projekten
|
|
ist etwas anderes als eine aus 29. */
|
|
.load-kopf {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
flex-wrap: wrap;
|
|
padding: 12px 14px;
|
|
background: var(--surface-sunk);
|
|
border-radius: var(--r-lg);
|
|
font-size: 13px;
|
|
}
|
|
.load-kopf-zahl strong {
|
|
font-size: 17px;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.load-kopf-warnung {
|
|
color: var(--red);
|
|
font-weight: 600;
|
|
}
|
|
.load-kopf-warnung::before {
|
|
content: '';
|
|
display: inline-block;
|
|
width: 7px; height: 7px;
|
|
border-radius: 50%;
|
|
background: var(--red);
|
|
margin-right: 7px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.load-luecken {
|
|
padding: 12px 14px;
|
|
border: 1px dashed var(--line);
|
|
border-radius: var(--r-lg);
|
|
font-size: 12px;
|
|
}
|
|
.load-luecke {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
padding: 4px 0;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.load-luecke:last-child { border-bottom: none; }
|
|
.load-luecke b { color: var(--text-muted); font-weight: 500; white-space: nowrap; }
|
|
|
|
/* 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-seg-summe { border-right: none; }
|
|
|
|
/* Marke der vollen Kapazität im Band. Sie sitzt am rechten Rand, weil das
|
|
volle Band genau die Wochenkapazität ist; ein Riegel, der sie erreicht,
|
|
stößt sichtbar an. */
|
|
.load-kapazitaet {
|
|
position: absolute;
|
|
right: 0; top: 0; bottom: 0;
|
|
width: 2px;
|
|
background: var(--text-subtle);
|
|
opacity: .5;
|
|
}
|
|
.load-zeile-summe .load-band { position: relative; }
|
|
|
|
.load-einheit {
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
color: var(--text-subtle);
|
|
margin-left: 2px;
|
|
}
|
|
|
|
.load-legende-item em {
|
|
font-style: normal;
|
|
color: var(--text-subtle);
|
|
margin-left: 3px;
|
|
}
|
|
|
|
/* Legende der Projektfarben, nur für die tatsächlich vorkommenden Projekte.
|
|
Nötig, weil in schmalen Segmenten die Projektnummer keinen Platz findet. */
|
|
.load-legende {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 6px 16px;
|
|
padding-top: 14px;
|
|
border-top: 1px solid var(--line-soft);
|
|
font-size: 11px;
|
|
color: var(--text-muted);
|
|
}
|
|
.load-legende-item {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
.load-legende-item i {
|
|
width: 9px;
|
|
height: 9px;
|
|
border-radius: 2px;
|
|
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-row-title {
|
|
grid-column: 1 / -1;
|
|
width: 100%;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
margin: 0 0 2px 0;
|
|
padding-top: 4px;
|
|
color: var(--text-muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: .04em;
|
|
}
|
|
|
|
.load-card {
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-xl);
|
|
padding: 20px 22px;
|
|
min-width: 0;
|
|
width: 100%;
|
|
box-shadow: var(--sh-2);
|
|
transition: box-shadow .2s var(--ease), transform .2s var(--ease);
|
|
}
|
|
|
|
.load-card:hover {
|
|
box-shadow: var(--sh-3);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.load-card h3 {
|
|
margin: 0 0 4px;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
letter-spacing: -0.01em;
|
|
line-height: 1.25;
|
|
}
|
|
|
|
.load-num {
|
|
font-size: 30px;
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
letter-spacing: -0.03em;
|
|
line-height: 1.1;
|
|
}
|
|
|
|
.load-detail {
|
|
font-size: 11px;
|
|
color: var(--text-muted);
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.load-detail div {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 4px 0;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
|
|
.load-detail div:last-child { border-bottom: none; }
|
|
|
|
/* === Modal, Form-Elemente & Listen === */
|
|
.modal-bg {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0,0,0,.35);
|
|
-webkit-backdrop-filter: blur(6px);
|
|
backdrop-filter: blur(6px);
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
/* Über Menüband (.app-topbar, 140) UND Seitenleiste (.side-menu, 200):
|
|
Mit dem früheren Wert 100 blieb die Navigation neben einem offenen Dialog
|
|
sichtbar und anklickbar — auch hinter dem "blockierenden" Login-Fenster —
|
|
und die Seitenleiste verdeckte bei mittleren Fensterbreiten die linke
|
|
Kante breiter Dialoge. */
|
|
z-index: 300;
|
|
}
|
|
|
|
.modal {
|
|
background: var(--surface);
|
|
padding: 28px;
|
|
border-radius: var(--r-xl);
|
|
max-width: 500px;
|
|
width: 90%;
|
|
max-height: 85vh;
|
|
overflow: auto;
|
|
box-shadow: var(--sh-3);
|
|
}
|
|
|
|
.modal h2 {
|
|
margin-top: 0;
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
letter-spacing: -0.02em;
|
|
line-height: 1.15;
|
|
}
|
|
|
|
.form-row {
|
|
margin-bottom: 14px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 5px;
|
|
}
|
|
|
|
.form-row label {
|
|
font-weight: 500;
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* Gesperrte Bedienelemente: Ohne eigene :disabled-Regeln schlagen die
|
|
Farbangaben oben die Browser-Voreinstellung, und ein deaktivierter Knopf
|
|
sieht exakt aus wie ein bedienbarer (z. B. in gesperrten Sitzungen oder
|
|
bei der eigenen Zeile in der Benutzerverwaltung). */
|
|
button:disabled,
|
|
input:disabled,
|
|
select:disabled,
|
|
textarea:disabled {
|
|
opacity: .45;
|
|
cursor: not-allowed;
|
|
box-shadow: none;
|
|
}
|
|
button:disabled:hover,
|
|
select:disabled:hover {
|
|
filter: none;
|
|
transform: none;
|
|
}
|
|
|
|
/* Warnband unten rechts, wenn das Speichern fehlschlägt (showSyncProblem() in
|
|
js/store.js). Liegt über allem, damit es auch neben einem offenen Dialog
|
|
sichtbar bleibt. */
|
|
.sync-problem-bar {
|
|
position: fixed;
|
|
right: 18px;
|
|
bottom: 18px;
|
|
z-index: 500;
|
|
max-width: 340px;
|
|
background: var(--red);
|
|
color: #fff;
|
|
font-size: 13px;
|
|
line-height: 1.45;
|
|
padding: 11px 15px;
|
|
border-radius: var(--r-md);
|
|
box-shadow: var(--sh-3);
|
|
}
|
|
|
|
/* Hinweisband gesperrter Sitzungen (renderBoard()/renderWochenbericht()).
|
|
Vorher standen die Farben als Inline-Angaben im Markup und waren damit im
|
|
Dunkelmodus grell weiß-rosa. */
|
|
.lock-notice {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
flex-wrap: wrap;
|
|
background: var(--surface-alt);
|
|
border: 1px solid var(--red);
|
|
color: var(--red);
|
|
border-radius: var(--r-md);
|
|
padding: 9px 13px;
|
|
margin-bottom: 12px;
|
|
font-size: 13px;
|
|
}
|
|
|
|
/* === LP-Aufwand-Maske als Matrix-Tabelle ===
|
|
Zeilen = Leistungsphasen, Spalten = Rollen + "amtierend" (Radio). */
|
|
.lp-matrix {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 6px 0 12px;
|
|
}
|
|
.lp-matrix thead th {
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
color: var(--text-muted);
|
|
text-align: left;
|
|
padding: 4px 8px;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.lp-matrix th.lp-lph {
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
text-align: left;
|
|
padding: 6px 8px;
|
|
white-space: nowrap;
|
|
}
|
|
.lp-matrix td {
|
|
padding: 3px 8px;
|
|
}
|
|
.lp-matrix td input[type=text] {
|
|
width: 64px;
|
|
padding: 4px 7px;
|
|
font-size: 13px;
|
|
}
|
|
.lp-matrix tbody th.lp-lph,
|
|
.lp-matrix tbody td {
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.lp-matrix tbody tr:last-child th.lp-lph,
|
|
.lp-matrix tbody tr:last-child td {
|
|
border-bottom: none;
|
|
}
|
|
.lp-matrix tbody tr:nth-child(even) th.lp-lph,
|
|
.lp-matrix tbody tr:nth-child(even) td {
|
|
background: var(--surface-alt);
|
|
}
|
|
|
|
/* LP-Aufwand- und Neues-Projekt-Modal etwas breiter für die Matrix-Tabelle */
|
|
#lpModal .modal,
|
|
#newProjModal .modal {
|
|
max-width: 640px;
|
|
}
|
|
|
|
/* .bubble-card: gemeinsame "Bubble-Card"-Optik für Projekt- und
|
|
Personen-Karten (Projekte-/Projektbeteiligte-Tab) — gleicher Radius/
|
|
Schatten wie .load-card (Dashboard/Auslastung), aber ohne Hover-Anhebung,
|
|
weil die Projekt-Karten Formularelemente enthalten (eine Anhebung beim
|
|
Überfahren wäre dort irritierend). */
|
|
.bubble-card {
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-xl);
|
|
padding: 20px 22px;
|
|
box-shadow: var(--sh-2);
|
|
transition: box-shadow .2s var(--ease);
|
|
}
|
|
|
|
.bubble-card:hover {
|
|
box-shadow: var(--sh-3);
|
|
}
|
|
|
|
.person-list-item,
|
|
.person-card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
}
|
|
|
|
.person-list-item {
|
|
align-items: center;
|
|
gap: 8px;
|
|
overflow-x: auto;
|
|
flex-direction: row;
|
|
}
|
|
|
|
.person-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 8px 4px;
|
|
cursor: pointer;
|
|
overflow-x: auto;
|
|
transition: background .2s var(--ease);
|
|
}
|
|
|
|
.person-header:hover { background: var(--surface-sunk); }
|
|
|
|
/* Schaltflächen-Optik auch für Links: Ein <a class="secondary"> in einer
|
|
Knopfleiste sah sonst aus wie ein blauer Standardlink, weil .secondary
|
|
ausschließlich für <button> definiert war. */
|
|
a.secondary {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
background: var(--surface-alt);
|
|
color: var(--text);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--r-md);
|
|
padding: 6px 12px;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
transition: background .15s var(--ease), border-color .15s var(--ease);
|
|
}
|
|
a.secondary:hover { background: var(--surface-sunk); border-color: var(--text-subtle); }
|
|
|
|
/* Trennzeichen in der Board-Legende (Rollenfarben | Art der Zuordnung) */
|
|
.legend-sep { color: var(--text-subtle); }
|
|
|
|
/* Zugehörigkeit zur aktuellen Sitzung + Schaltfläche rechts in der Zeile
|
|
(renderPeople(), js/people/people.js). */
|
|
.person-week-state {
|
|
margin-left: auto;
|
|
font-size: 12px;
|
|
color: var(--green);
|
|
white-space: nowrap;
|
|
}
|
|
.person-header button { flex: 0 0 auto; }
|
|
|
|
.person-toggle {
|
|
flex: 0 0 auto;
|
|
font-size: 11px;
|
|
color: var(--text-subtle);
|
|
width: 14px;
|
|
text-align: center;
|
|
}
|
|
|
|
.person-toggle .icon {
|
|
transition: transform .2s var(--ease);
|
|
}
|
|
|
|
.person-card.open .person-toggle .icon {
|
|
transform: rotate(90deg);
|
|
}
|
|
|
|
.person-list-item span.drag-handle,
|
|
.person-header span.drag-handle {
|
|
flex: 0 0 auto;
|
|
color: var(--text-subtle);
|
|
cursor: grab;
|
|
}
|
|
|
|
.person-list-item input[type=text],
|
|
.person-header input[type=text] { flex: 0 0 auto; max-width: 25vw; }
|
|
.person-list-item input[type=text]:nth-of-type(1),
|
|
.person-header input[type=text]:nth-of-type(1) { max-width: 80px; }
|
|
.person-list-item input[type=text]:nth-of-type(2),
|
|
.person-header input[type=text]:nth-of-type(2) { max-width: 180px; }
|
|
|
|
.person-list-item select,
|
|
.person-header select,
|
|
.person-header .role-checkboxes {
|
|
flex: 0 0 auto;
|
|
min-width: 110px;
|
|
}
|
|
|
|
.person-list-item button,
|
|
.person-header button {
|
|
flex: 0 0 auto;
|
|
margin-left: auto;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* .projects-sortable: Listen-Container je Projekt-Gruppe im Projekte-Tab
|
|
(projects.js) — eine Bubble-Card mit den Projekten als Listenzeilen
|
|
(kein Karten-Raster mehr, siehe .project-item). Der Container-Klassenname
|
|
bleibt unverändert, damit die Drag-and-Drop-Selektoren (handleDrop/
|
|
reorderProjects) weiter greifen. */
|
|
.projects-sortable {
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-xl);
|
|
box-shadow: var(--sh-2);
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* .people-readonly: Listen-Container im Projektbeteiligte-Tab (people.js) —
|
|
eine Bubble-Card mit den Personen als Listenzeilen (kein Karten-Raster
|
|
mehr, siehe .person-card). */
|
|
.people-readonly {
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-xl);
|
|
box-shadow: var(--sh-2);
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* .person-card: eine Listenzeile im Projektbeteiligte-Tab (ersetzt die
|
|
vormalige eigene Bubble-Card je Person) — der klickbare .person-header
|
|
bleibt die sichtbare Zeile, .person-absences klappt darunter auf. */
|
|
.person-card {
|
|
border-bottom: 1px solid var(--line-soft);
|
|
padding: 0 16px;
|
|
}
|
|
.person-card:last-child { border-bottom: none; }
|
|
|
|
/* .sidebar-nav-divider: trennt die Modul-Navigation von Einstellungen/Admin. */
|
|
.sidebar-nav-divider {
|
|
border: none;
|
|
border-top: 1px solid var(--line-soft);
|
|
margin: 8px 6px;
|
|
}
|
|
|
|
/* .project-item: eine Listenzeile im Projekte-Tab (ersetzt die vormalige
|
|
eigene Bubble-Card je Projekt) — überschreibt die Zeilen-Basis von
|
|
.person-list-item mit einer umbrechenden Zeile plus rechtsbündigen
|
|
Aktionen (.project-card-footer); das Karten-Attribut (data-project-id) und
|
|
die Drag-Handler bleiben unverändert. */
|
|
.project-item {
|
|
overflow-x: visible;
|
|
flex-wrap: wrap;
|
|
padding: 12px 16px;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
border-radius: 0;
|
|
transition: background .15s var(--ease);
|
|
}
|
|
.project-item:last-child { border-bottom: none; }
|
|
.project-item:hover { background: var(--surface-sunk); }
|
|
|
|
.project-tags-row {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 6px;
|
|
flex: 1 1 200px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.project-card-footer {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-left: auto;
|
|
}
|
|
/* Überschreibt die generische .person-list-item-button-Regel (margin-left:
|
|
auto auf jedem direkten Button), sonst würden sich die beiden Footer-
|
|
Buttons gegenseitig auseinanderschieben statt gruppiert zu bleiben — nur
|
|
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; }
|
|
|
|
/* === Hinweise & Hilfsklassen === */
|
|
.legend {
|
|
font-size: 11px;
|
|
color: var(--text-muted);
|
|
margin: 10px 0;
|
|
display: flex;
|
|
gap: 16px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.legend span {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
}
|
|
|
|
|
|
/* === Anwesenheitsblock der Sitzung ======================================
|
|
Eigener Block oben im Projektboard (renderAttendance(), js/board/board.js).
|
|
Zustände sind bewusst binär (anwesend / nicht anwesend, Tabelle attendance);
|
|
der Zähler in der Kopfzeile macht sichtbar, wenn noch niemand geklickt hat. */
|
|
|
|
.attendance-block {
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-lg);
|
|
box-shadow: var(--sh-1);
|
|
margin-top: 16px;
|
|
overflow: hidden;
|
|
}
|
|
.attendance-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
flex-wrap: wrap;
|
|
padding: 9px 14px;
|
|
background: var(--surface-alt);
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.attendance-title { font-weight: 600; font-size: 13px; }
|
|
.attendance-count {
|
|
font-size: 11.5px;
|
|
color: var(--text-muted);
|
|
font-variant-numeric: tabular-nums;
|
|
white-space: nowrap;
|
|
}
|
|
.attendance-spacer { margin-left: auto; }
|
|
|
|
.attendance-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
padding: 12px 14px;
|
|
}
|
|
|
|
.attendance-tile {
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 4px;
|
|
width: 84px;
|
|
padding: 9px 5px 8px;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--r-md);
|
|
background: var(--surface);
|
|
color: var(--text-muted);
|
|
font-family: inherit;
|
|
font-weight: 400;
|
|
cursor: pointer;
|
|
transition: border-color .15s var(--ease), background .15s var(--ease), color .15s var(--ease);
|
|
}
|
|
.attendance-tile:hover { border-color: var(--text-subtle); background: var(--surface-alt); }
|
|
.attendance-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
|
|
.attendance-av {
|
|
width: 30px; height: 30px;
|
|
border-radius: 50%;
|
|
background: var(--surface-sunk);
|
|
color: var(--text-muted);
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-size: 11px; font-weight: 600;
|
|
transition: background .15s var(--ease), color .15s var(--ease);
|
|
}
|
|
.attendance-name {
|
|
font-size: 10.5px;
|
|
line-height: 1.25;
|
|
text-align: center;
|
|
word-break: break-word;
|
|
}
|
|
.attendance-note {
|
|
font-size: 9.5px;
|
|
color: var(--amber);
|
|
line-height: 1.2;
|
|
text-align: center;
|
|
}
|
|
/* Der Haken trägt den Zustand zusätzlich zur Farbe — nicht jede Person
|
|
unterscheidet Grün und Grau zuverlässig. */
|
|
.attendance-mark {
|
|
position: absolute;
|
|
top: 4px; right: 6px;
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
color: var(--green);
|
|
line-height: 1;
|
|
}
|
|
|
|
.attendance-tile.present {
|
|
border-color: var(--green);
|
|
background: var(--attend-bg);
|
|
color: var(--green);
|
|
font-weight: 500;
|
|
}
|
|
.attendance-tile.present:hover { background: var(--attend-bg-hover); border-color: var(--green); }
|
|
.attendance-tile.present .attendance-av { background: var(--green); color: #fff; }
|
|
|
|
.attendance-tile.locked-cell { cursor: not-allowed; opacity: .7; }
|
|
.attendance-tile.locked-cell:hover { border-color: var(--line); background: var(--surface); }
|
|
.attendance-tile.present.locked-cell:hover { background: var(--attend-bg); border-color: var(--green); }
|
|
|
|
/* Legende ist seit der Trennung reine Namenserklärung, nicht mehr klickbar */
|
|
|
|
|
|
.swatch {
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 4px;
|
|
display: inline-block;
|
|
box-shadow: inset 0 0 0 1px rgba(0,0,0,.06);
|
|
}
|
|
|
|
.table-wrap {
|
|
overflow: auto;
|
|
max-height: 75vh;
|
|
border-radius: var(--r-lg);
|
|
border: 1px solid var(--line-soft);
|
|
box-shadow: var(--sh-1);
|
|
background: var(--surface);
|
|
}
|
|
|
|
/* 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); }
|
|
|
|
.hint {
|
|
color: var(--text-subtle);
|
|
font-size: 12px;
|
|
margin: 8px 0;
|
|
}
|
|
|
|
.del-proj {
|
|
color: var(--red);
|
|
cursor: pointer;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.lock-notice button { margin-left: 12px; }
|
|
|
|
|
|
input[type=text].edit-name {
|
|
border: 1px solid transparent;
|
|
background: transparent;
|
|
font-weight: 600;
|
|
width: 100%;
|
|
font-size: 12px;
|
|
padding: 3px 5px;
|
|
border-radius: var(--r-sm);
|
|
transition: background .15s var(--ease), border-color .15s var(--ease), box-shadow .15s var(--ease);
|
|
}
|
|
|
|
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);
|
|
outline: none;
|
|
}
|
|
|
|
/* === Scrollbars (WebKit) === */
|
|
::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
::-webkit-scrollbar-track { background: transparent; }
|
|
::-webkit-scrollbar-thumb {
|
|
background: rgba(0,0,0,.2);
|
|
border-radius: var(--r-pill);
|
|
border: 2px solid transparent;
|
|
background-clip: content-box;
|
|
}
|
|
::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,.32); background-clip: content-box; }
|
|
|
|
/* ============================================================
|
|
=== DARK MODE ===
|
|
Automatisch nach Systemeinstellung ODER manuell per
|
|
<html data-theme="dark"> auslösbar.
|
|
============================================================ */
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
html:not([data-theme="light"]) { color-scheme: dark; }
|
|
|
|
html:not([data-theme="light"]) {
|
|
--accent: #0a84ff;
|
|
--accent-hover: #2f95ff;
|
|
--accent-active: #0060df;
|
|
--accent-soft: #10263f;
|
|
|
|
--text: #f5f5f7;
|
|
--text-muted: #a1a1a6;
|
|
--text-subtle: #86868b;
|
|
|
|
--bg: #000000;
|
|
--surface: #1c1c1e;
|
|
--surface-alt: #232326;
|
|
--surface-sunk: #2c2c2e;
|
|
|
|
--line: #3a3a3c;
|
|
--line-soft: #2c2c2e;
|
|
|
|
--green: #30d158;
|
|
--amber: #ff9f0a;
|
|
--red: #ff453a;
|
|
--red-hover: #ff453a;
|
|
--red-active: #a3000f;
|
|
|
|
--attend-bg: rgba(48,209,88,.16);
|
|
--attend-bg-hover: rgba(48,209,88,.24);
|
|
|
|
--band-neu: #0a6fd0;
|
|
--band-fortschritt: #1e7a38;
|
|
|
|
--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);
|
|
}
|
|
}
|
|
|
|
html[data-theme="dark"] {
|
|
color-scheme: dark;
|
|
|
|
--accent: #0a84ff;
|
|
--accent-hover: #2f95ff;
|
|
--accent-active: #0060df;
|
|
--accent-soft: #10263f;
|
|
|
|
--text: #f5f5f7;
|
|
--text-muted: #a1a1a6;
|
|
--text-subtle: #86868b;
|
|
|
|
--bg: #000000;
|
|
--surface: #1c1c1e;
|
|
--surface-alt: #232326;
|
|
--surface-sunk: #2c2c2e;
|
|
|
|
--line: #3a3a3c;
|
|
--line-soft: #2c2c2e;
|
|
|
|
--green: #30d158;
|
|
--amber: #ff9f0a;
|
|
--red: #ff453a;
|
|
--red-hover: #ff453a;
|
|
--red-active: #a3000f;
|
|
|
|
--attend-bg: rgba(48,209,88,.16);
|
|
--attend-bg-hover: rgba(48,209,88,.24);
|
|
|
|
--band-neu: #0a6fd0;
|
|
--band-fortschritt: #1e7a38;
|
|
|
|
--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);
|
|
}
|
|
|
|
/* 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);
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
html:not([data-theme="light"]) .toolbar-divider { background: var(--line); }
|
|
html:not([data-theme="light"]) .sidebar-nav-divider { border-top-color: var(--line); }
|
|
html:not([data-theme="light"]) .side-menu {
|
|
background: var(--surface);
|
|
border-right-color: var(--line);
|
|
}
|
|
html:not([data-theme="light"]) .side-menu-mobile-header,
|
|
html:not([data-theme="light"]) .sidebar-collapse-bar {
|
|
border-color: var(--line);
|
|
}
|
|
html:not([data-theme="light"]) .user-menu-dropdown {
|
|
background: var(--surface);
|
|
border-color: var(--line);
|
|
}
|
|
html:not([data-theme="light"]) .user-menu-info { border-bottom-color: var(--line); }
|
|
html:not([data-theme="light"]) a.menu-item:hover,
|
|
html:not([data-theme="light"]) button.menu-item:hover { background: rgba(255,255,255,.08); }
|
|
html:not([data-theme="light"]) .sidebar-collapse-bar:hover { background: rgba(255,255,255,.08); }
|
|
html:not([data-theme="light"]) .show-mode-overlay { background: var(--bg); }
|
|
html:not([data-theme="light"]) .show-mode-header {
|
|
background: var(--surface);
|
|
border-bottom-color: var(--line);
|
|
}
|
|
html:not([data-theme="light"]) .show-mode-paused {
|
|
background: var(--surface);
|
|
border-color: var(--line);
|
|
}
|
|
html:not([data-theme="light"]) .theme-toggle-circle {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
color: var(--text);
|
|
}
|
|
html:not([data-theme="light"]) .menu-corner-btn {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
color: var(--text);
|
|
}
|
|
html:not([data-theme="light"]) .menu-corner-btn:hover { background: var(--line); }
|
|
html:not([data-theme="light"]) .topbar-logo { filter: brightness(.92); }
|
|
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.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); }
|
|
html:not([data-theme="light"]) button.danger { background: #d70015; }
|
|
html:not([data-theme="light"]) button.danger:hover { background: var(--red-hover); }
|
|
html:not([data-theme="light"]) button.danger:active { background: var(--red-active); }
|
|
|
|
html:not([data-theme="light"]) select,
|
|
html:not([data-theme="light"]) input[type=text],
|
|
html:not([data-theme="light"]) input[type=email],
|
|
html:not([data-theme="light"]) input[type=date] {
|
|
background-color: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
color: var(--text);
|
|
}
|
|
html:not([data-theme="light"]) select:focus,
|
|
html:not([data-theme="light"]) input[type=text]:focus,
|
|
html:not([data-theme="light"]) input[type=email]:focus,
|
|
html:not([data-theme="light"]) input[type=date]:focus {
|
|
box-shadow: 0 0 0 3px rgba(10,132,255,.28);
|
|
}
|
|
html:not([data-theme="light"]) select {
|
|
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath fill='%23a1a1a6' d='M0 0h10L5 6z'/%3E%3C/svg%3E");
|
|
}
|
|
html:not([data-theme="light"]) ::placeholder { color: var(--text-subtle); }
|
|
|
|
html:not([data-theme="light"]) .status-edit {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
}
|
|
html:not([data-theme="light"]) .status-edit:focus { box-shadow: 0 0 0 3px rgba(10,132,255,.28); }
|
|
html:not([data-theme="light"]) .status-edit.status-new { color: var(--green); }
|
|
html:not([data-theme="light"]) .status-toolbar {
|
|
background: rgba(44,44,46,.9);
|
|
border-color: var(--line);
|
|
}
|
|
html:not([data-theme="light"]) .status-toolbar button:hover { background: rgba(255,255,255,.10); }
|
|
html:not([data-theme="light"]) .status-toolbar button:active { background: rgba(255,255,255,.16); }
|
|
|
|
html:not([data-theme="light"]) .locked-cell { background: #38383a !important; opacity: .55; }
|
|
html:not([data-theme="light"]) .locked-cell input {
|
|
background: #38383a !important;
|
|
border-color: var(--line) !important;
|
|
color: var(--text-muted) !important;
|
|
}
|
|
|
|
html:not([data-theme="light"]) .board-lph-row input {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
color: var(--text);
|
|
}
|
|
html:not([data-theme="light"]) .bar { background: #38383a; }
|
|
html:not([data-theme="light"]) .board-avatar { border-color: var(--line); }
|
|
|
|
html:not([data-theme="light"]) .load-card { border-color: var(--line); }
|
|
html:not([data-theme="light"]) .bubble-card,
|
|
html:not([data-theme="light"]) .projects-sortable,
|
|
html:not([data-theme="light"]) .people-readonly,
|
|
html:not([data-theme="light"]) .board-list { border-color: var(--line); }
|
|
html:not([data-theme="light"]) .modal-bg { background: rgba(0,0,0,.6); }
|
|
html:not([data-theme="light"]) .modal { border: 1px solid var(--line); }
|
|
|
|
html:not([data-theme="light"]) .swatch { box-shadow: inset 0 0 0 1px rgba(255,255,255,.14); }
|
|
html:not([data-theme="light"]) .table-wrap { border-color: var(--line); }
|
|
html:not([data-theme="light"]) .del-proj { color: var(--red); }
|
|
html:not([data-theme="light"]) input[type=text].edit-name { border-color: transparent; background: transparent; }
|
|
html:not([data-theme="light"]) input[type=text].edit-name:hover { background: rgba(255,255,255,.06); }
|
|
html:not([data-theme="light"]) input[type=text].edit-name:focus {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 3px rgba(10,132,255,.28);
|
|
}
|
|
|
|
html:not([data-theme="light"]) ::-webkit-scrollbar-thumb { background: rgba(255,255,255,.22); background-clip: content-box; }
|
|
html:not([data-theme="light"]) ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.34); background-clip: content-box; }
|
|
}
|
|
|
|
html[data-theme="dark"] .app-topbar {
|
|
background: rgba(28,28,30,.75);
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
html[data-theme="dark"] .toolbar-divider { background: var(--line); }
|
|
html[data-theme="dark"] .sidebar-nav-divider { border-top-color: var(--line); }
|
|
html[data-theme="dark"] .side-menu {
|
|
background: var(--surface);
|
|
border-right-color: var(--line);
|
|
}
|
|
html[data-theme="dark"] .side-menu-mobile-header,
|
|
html[data-theme="dark"] .sidebar-collapse-bar {
|
|
border-color: var(--line);
|
|
}
|
|
html[data-theme="dark"] .user-menu-dropdown {
|
|
background: var(--surface);
|
|
border-color: var(--line);
|
|
}
|
|
html[data-theme="dark"] .user-menu-info { border-bottom-color: var(--line); }
|
|
html[data-theme="dark"] a.menu-item:hover,
|
|
html[data-theme="dark"] button.menu-item:hover { background: rgba(255,255,255,.08); }
|
|
html[data-theme="dark"] .sidebar-collapse-bar:hover { background: rgba(255,255,255,.08); }
|
|
html[data-theme="dark"] .show-mode-overlay { background: var(--bg); }
|
|
html[data-theme="dark"] .show-mode-header {
|
|
background: var(--surface);
|
|
border-bottom-color: var(--line);
|
|
}
|
|
html[data-theme="dark"] .show-mode-paused {
|
|
background: var(--surface);
|
|
border-color: var(--line);
|
|
}
|
|
html[data-theme="dark"] .theme-toggle-circle {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
color: var(--text);
|
|
}
|
|
html[data-theme="dark"] .menu-corner-btn {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
color: var(--text);
|
|
}
|
|
html[data-theme="dark"] .menu-corner-btn:hover { background: var(--line); }
|
|
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.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); }
|
|
html[data-theme="dark"] button.danger { background: #d70015; }
|
|
html[data-theme="dark"] button.danger:hover { background: var(--red-hover); }
|
|
html[data-theme="dark"] button.danger:active { background: var(--red-active); }
|
|
|
|
html[data-theme="dark"] select,
|
|
html[data-theme="dark"] input[type=text],
|
|
html[data-theme="dark"] input[type=date] {
|
|
background-color: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
color: var(--text);
|
|
}
|
|
html[data-theme="dark"] select:focus,
|
|
html[data-theme="dark"] input[type=text]:focus,
|
|
html[data-theme="dark"] input[type=date]:focus {
|
|
box-shadow: 0 0 0 3px rgba(10,132,255,.28);
|
|
}
|
|
html[data-theme="dark"] select {
|
|
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath fill='%23a1a1a6' d='M0 0h10L5 6z'/%3E%3C/svg%3E");
|
|
}
|
|
html[data-theme="dark"] ::placeholder { color: var(--text-subtle); }
|
|
|
|
html[data-theme="dark"] .status-edit {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
}
|
|
html[data-theme="dark"] .status-edit:focus { box-shadow: 0 0 0 3px rgba(10,132,255,.28); }
|
|
html[data-theme="dark"] .status-edit.status-new { color: var(--green); }
|
|
html[data-theme="dark"] .status-toolbar {
|
|
background: rgba(44,44,46,.9);
|
|
border-color: var(--line);
|
|
}
|
|
html[data-theme="dark"] .status-toolbar button:hover { background: rgba(255,255,255,.10); }
|
|
html[data-theme="dark"] .status-toolbar button:active { background: rgba(255,255,255,.16); }
|
|
|
|
html[data-theme="dark"] .locked-cell { background: #38383a !important; opacity: .55; }
|
|
html[data-theme="dark"] .locked-cell input {
|
|
background: #38383a !important;
|
|
border-color: var(--line) !important;
|
|
color: var(--text-muted) !important;
|
|
}
|
|
|
|
html[data-theme="dark"] .board-lph-row input {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
color: var(--text);
|
|
}
|
|
html[data-theme="dark"] .bar { background: #38383a; }
|
|
html[data-theme="dark"] .board-avatar { border-color: var(--line); }
|
|
|
|
html[data-theme="dark"] .load-card { border-color: var(--line); }
|
|
html[data-theme="dark"] .bubble-card,
|
|
html[data-theme="dark"] .projects-sortable,
|
|
html[data-theme="dark"] .people-readonly,
|
|
html[data-theme="dark"] .board-list { border-color: var(--line); }
|
|
html[data-theme="dark"] .modal-bg { background: rgba(0,0,0,.6); }
|
|
html[data-theme="dark"] .modal { border: 1px solid var(--line); }
|
|
|
|
html[data-theme="dark"] .swatch { box-shadow: inset 0 0 0 1px rgba(255,255,255,.14); }
|
|
html[data-theme="dark"] .table-wrap { border-color: var(--line); }
|
|
html[data-theme="dark"] .del-proj { color: var(--red); }
|
|
html[data-theme="dark"] input[type=text].edit-name { border-color: transparent; background: transparent; }
|
|
html[data-theme="dark"] input[type=text].edit-name:hover { background: rgba(255,255,255,.06); }
|
|
html[data-theme="dark"] input[type=text].edit-name:focus {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 3px rgba(10,132,255,.28);
|
|
}
|
|
|
|
html[data-theme="dark"] ::-webkit-scrollbar-thumb { background: rgba(255,255,255,.22); background-clip: content-box; }
|
|
html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.34); background-clip: content-box; }
|
|
|
|
/* === GANTT / Projektplan === */
|
|
.modal-wide {
|
|
max-width: 900px;
|
|
width: 92%;
|
|
}
|
|
|
|
.gantt-container {
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-lg);
|
|
padding: 12px 0;
|
|
box-shadow: var(--sh-1);
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
overflow-x: auto;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
|
|
.gantt-chart {
|
|
width: 100%;
|
|
min-width: 0;
|
|
position: relative;
|
|
}
|
|
|
|
.gantt-row {
|
|
display: flex;
|
|
align-items: center;
|
|
position: relative;
|
|
height: 32px;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
|
|
.gantt-row.gantt-header,
|
|
.gantt-row.gantt-days {
|
|
height: 26px;
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
|
|
.gantt-timeline {
|
|
position: relative;
|
|
flex: 1 1 auto;
|
|
height: 100%;
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.gantt-row.gantt-project {
|
|
height: 34px;
|
|
}
|
|
|
|
.gantt-row.gantt-project.highlighted {
|
|
background: var(--accent-soft);
|
|
}
|
|
|
|
.gantt-row.gantt-vacation {
|
|
height: 22px;
|
|
background: transparent;
|
|
font-size: 11px;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.gantt-label {
|
|
width: 220px;
|
|
flex: 0 0 220px;
|
|
min-width: 220px;
|
|
max-width: 220px;
|
|
height: 100%;
|
|
align-self: stretch;
|
|
box-sizing: border-box;
|
|
padding: 0 12px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
font-weight: 500;
|
|
font-size: 12px;
|
|
border-right: 1px solid var(--line-soft);
|
|
position: sticky;
|
|
left: 0;
|
|
z-index: 10;
|
|
background: var(--surface);
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.gantt-row.gantt-header .gantt-label,
|
|
.gantt-row.gantt-days .gantt-label {
|
|
background: var(--surface);
|
|
z-index: 15;
|
|
}
|
|
|
|
.gantt-row.gantt-project.highlighted .gantt-label {
|
|
background: var(--accent-soft);
|
|
}
|
|
|
|
.gantt-row.gantt-vacation .gantt-label {
|
|
font-weight: normal;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
background: var(--surface);
|
|
}
|
|
|
|
.gantt-row.gantt-todo .gantt-label {
|
|
background: var(--surface);
|
|
}
|
|
|
|
.gantt-vacation-dot {
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
background: var(--amber);
|
|
}
|
|
|
|
.gantt-month,
|
|
.gantt-day {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
border-right: 1px solid var(--line-soft);
|
|
font-size: 10px;
|
|
color: var(--text-muted);
|
|
padding: 2px 4px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.gantt-month {
|
|
background: var(--surface-sunk);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.gantt-day {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.gantt-day.weekend {
|
|
background: var(--surface-sunk);
|
|
opacity: .7;
|
|
}
|
|
|
|
.gantt-day.gantt-week {
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
border-right: 1px solid var(--line);
|
|
}
|
|
|
|
/* Raster-Overlay: liegt über die gesamte Timeline-Breite (rechts der Labels).
|
|
Wochenend-Flächen zeichnen ohne z-index (Zeilen liegen darüber, sind aber
|
|
transparent); die Heute-Linie bekommt z-index, damit sie über den Balken,
|
|
aber unter den sticky Labels liegt. */
|
|
.gantt-grid-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
left: 220px;
|
|
right: 0;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.gantt-grid-weekend {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
background: var(--surface-sunk);
|
|
opacity: .55;
|
|
}
|
|
|
|
.gantt-grid-today {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 0;
|
|
border-left: 2px solid var(--red);
|
|
opacity: .7;
|
|
z-index: 9;
|
|
}
|
|
|
|
.gantt-bar {
|
|
position: absolute;
|
|
top: 6px;
|
|
bottom: 6px;
|
|
border-radius: var(--r-sm);
|
|
overflow: hidden;
|
|
box-shadow: var(--sh-1);
|
|
}
|
|
|
|
.gantt-bar.project {
|
|
color: #fff;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.gantt-bar .gantt-progress {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
background: rgba(0,0,0,.22);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.gantt-bar-label {
|
|
position: relative;
|
|
z-index: 1;
|
|
padding: 0 8px;
|
|
font-size: 11px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.gantt-bar.vacation {
|
|
top: 4px;
|
|
bottom: 4px;
|
|
background: repeating-linear-gradient(
|
|
45deg,
|
|
rgba(255, 159, 10, .55),
|
|
rgba(255, 159, 10, .55) 6px,
|
|
rgba(255, 159, 10, .35) 6px,
|
|
rgba(255, 159, 10, .35) 12px
|
|
);
|
|
border: 1px solid var(--amber);
|
|
border-radius: var(--r-pill);
|
|
}
|
|
|
|
.gantt-row.gantt-todo { height: 26px; font-size: 11px; }
|
|
.gantt-row.gantt-todo.done { opacity: .55; }
|
|
.gantt-row.gantt-milestone-row { height: 40px; font-size: 11px; background: transparent; }
|
|
.gantt-row.gantt-milestone-row .gantt-milestone { top: 6px; }
|
|
.gantt-row.gantt-milestone-row .gantt-milestone-label { top: 24px; max-width: 140px; overflow: hidden; text-overflow: ellipsis; }
|
|
.gantt-row.gantt-todo-add {
|
|
height: 34px;
|
|
font-size: 12px;
|
|
background: var(--surface-alt);
|
|
position: relative;
|
|
}
|
|
.gantt-todo-add-sticky {
|
|
position: sticky;
|
|
left: 0;
|
|
z-index: 10;
|
|
display: flex;
|
|
align-items: center;
|
|
background: var(--surface-alt);
|
|
border-right: 1px solid var(--line-soft);
|
|
height: 100%;
|
|
align-self: stretch;
|
|
box-sizing: border-box;
|
|
}
|
|
.gantt-todo-add-sticky .gantt-label {
|
|
position: static;
|
|
border-right: none;
|
|
background: transparent;
|
|
flex: 0 0 220px;
|
|
width: 220px;
|
|
min-width: 220px;
|
|
max-width: 220px;
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 0 12px;
|
|
}
|
|
.gantt-bar.todo {
|
|
top: 5px;
|
|
bottom: 5px;
|
|
background: var(--accent);
|
|
border-radius: var(--r-sm);
|
|
}
|
|
.gantt-bar.todo.done {
|
|
background: var(--green);
|
|
}
|
|
.gantt-bar.todo.critical {
|
|
background: var(--red);
|
|
box-shadow: 0 0 0 2px rgba(215,0,21,.25);
|
|
}
|
|
.gantt-todo-add-controls {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-wrap: nowrap;
|
|
width: fit-content;
|
|
max-width: 100%;
|
|
flex-shrink: 0;
|
|
padding-right: 8px;
|
|
}
|
|
.gantt-todo-add input[type=text],
|
|
.gantt-todo-add input[type=date] {
|
|
padding: 4px 7px;
|
|
font-size: 12px;
|
|
}
|
|
.gantt-todo-add input[type=text] {
|
|
flex: 0 0 180px;
|
|
width: 180px;
|
|
min-width: 140px;
|
|
}
|
|
.gantt-todo-add input[type=date] {
|
|
flex: 0 0 120px;
|
|
width: 120px;
|
|
min-width: 120px;
|
|
}
|
|
.gantt-todo-add button {
|
|
flex: 0 0 auto;
|
|
padding: 4px 12px;
|
|
font-size: 12px;
|
|
}
|
|
.gantt-todo-add .gantt-timeline {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 0 8px;
|
|
overflow: hidden;
|
|
}
|
|
.gantt-todo-actions {
|
|
display: inline-flex;
|
|
gap: 4px;
|
|
margin-left: 6px;
|
|
}
|
|
|
|
/* === GANTT Abhängigkeiten (Dependencies) === */
|
|
.gantt-dependencies-svg {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
pointer-events: none;
|
|
z-index: 8;
|
|
overflow: visible;
|
|
}
|
|
|
|
.gantt-dep-path {
|
|
fill: none;
|
|
stroke: var(--accent);
|
|
stroke-width: 2.2px;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
opacity: 0.85;
|
|
transition: stroke 0.2s, stroke-width 0.2s, opacity 0.2s;
|
|
}
|
|
|
|
.gantt-dep-path.conflict {
|
|
stroke: var(--red);
|
|
stroke-dasharray: 5 3;
|
|
}
|
|
|
|
.gantt-dep-path.done {
|
|
stroke: var(--green);
|
|
}
|
|
|
|
.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;
|
|
padding: 1px 6px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
margin-left: 6px;
|
|
max-width: 100px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
vertical-align: middle;
|
|
border: 1px solid rgba(0, 113, 227, 0.2);
|
|
}
|
|
|
|
.gantt-dep-badge.conflict {
|
|
background: rgba(215, 0, 21, 0.1);
|
|
color: var(--red);
|
|
border-color: rgba(215, 0, 21, 0.2);
|
|
}
|
|
.gantt-todo-actions button {
|
|
padding: 2px 7px;
|
|
font-size: 10px;
|
|
}
|
|
|
|
.gantt-milestone {
|
|
position: absolute;
|
|
top: 2px;
|
|
width: 0;
|
|
height: 0;
|
|
border-left: 7px solid transparent;
|
|
border-right: 7px solid transparent;
|
|
border-bottom: 12px solid var(--red);
|
|
transform: translateX(-50%);
|
|
z-index: 2;
|
|
cursor: grab;
|
|
}
|
|
.gantt-milestone:active { cursor: grabbing; }
|
|
|
|
.gantt-milestone-label {
|
|
position: absolute;
|
|
top: 16px;
|
|
transform: translateX(-50%);
|
|
font-size: 10px;
|
|
color: var(--text-muted);
|
|
white-space: nowrap;
|
|
pointer-events: none;
|
|
z-index: 2;
|
|
}
|
|
|
|
.gantt-bar.project,
|
|
.gantt-bar.vacation { cursor: grab; }
|
|
.gantt-bar.project:active,
|
|
.gantt-bar.vacation:active { cursor: grabbing; }
|
|
|
|
.gantt-resize {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 10px;
|
|
cursor: col-resize;
|
|
z-index: 3;
|
|
}
|
|
.gantt-resize-left { left: 0; }
|
|
.gantt-resize-right { right: 0; }
|
|
.gantt-resize:hover { background: rgba(255,255,255,.25); }
|
|
|
|
.gantt-form {
|
|
display: grid;
|
|
gap: 12px;
|
|
}
|
|
|
|
.gantt-form-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.gantt-form-row input[type=date] { flex: 1 1 140px; }
|
|
.gantt-form-row input[type=text] { flex: 2 1 200px; }
|
|
|
|
.gantt-modal-preview .gantt-chart {
|
|
min-width: auto;
|
|
}
|
|
|
|
/* === Datumsbereich-Picker (Von/Bis in einem Kalenderfenster) === */
|
|
.range-picker {
|
|
position: fixed;
|
|
z-index: 1100;
|
|
width: 288px;
|
|
background: var(--surface);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--r-lg);
|
|
box-shadow: var(--sh-3);
|
|
padding: 10px;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.range-picker-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.range-picker-title {
|
|
font-weight: 600;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.range-picker-hint {
|
|
font-size: 11px;
|
|
color: var(--text-muted);
|
|
text-align: center;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.range-picker-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(7, 1fr);
|
|
gap: 2px;
|
|
}
|
|
|
|
.range-picker-weekday {
|
|
text-align: center;
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
color: var(--text-muted);
|
|
padding: 2px 0;
|
|
}
|
|
|
|
.range-picker-day {
|
|
text-align: center;
|
|
padding: 5px 0;
|
|
border-radius: var(--r-sm);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
transition: background .15s var(--ease);
|
|
}
|
|
|
|
.range-picker-day:hover { background: var(--surface-sunk); }
|
|
.range-picker-day.weekend { color: var(--text-subtle); }
|
|
.range-picker-day.today { outline: 1px solid var(--accent); outline-offset: -1px; }
|
|
.range-picker-day.in-range { background: var(--accent-soft); border-radius: 0; }
|
|
.range-picker-day.sel-start,
|
|
.range-picker-day.sel-end {
|
|
background: var(--accent);
|
|
color: #fff;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.range-picker-footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 8px;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
/* Anzeige-Feld, das den Picker öffnet */
|
|
.range-picker-display {
|
|
cursor: pointer;
|
|
background: var(--surface);
|
|
min-width: 170px;
|
|
}
|
|
|
|
.person-absences {
|
|
padding: 8px 8px 8px 40px;
|
|
margin-top: 4px;
|
|
border-radius: var(--r-md);
|
|
background: var(--surface-alt);
|
|
}
|
|
|
|
.absence-list {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 6px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.absence-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-pill);
|
|
padding: 3px 10px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.absence-chip small {
|
|
color: var(--text-muted);
|
|
font-size: 11px;
|
|
}
|
|
|
|
.absence-form {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.absence-form input[type=date] { width: 130px; }
|
|
.absence-form select { min-width: 110px; }
|
|
|
|
/* Tag-Chips: editierbar in der Projekte-Liste (projects.js), read-only auf
|
|
Board-Zeilen, Dashboard-Aufgabenkarten und der Projektplan-Kopfzeile.
|
|
Farben ausschließlich über CSS-Variablen, die in beiden Dark-Mode-Blöcken
|
|
bereits passend umdefiniert sind — keine zusätzlichen Dark-Overrides nötig. */
|
|
.tag-chip-list {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 4px;
|
|
}
|
|
|
|
.tag-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
background: var(--surface-sunk);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-pill);
|
|
padding: 2px 8px;
|
|
font-size: 11px;
|
|
font-weight: 400;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.tag-chip .tag-remove {
|
|
cursor: pointer;
|
|
font-weight: 600;
|
|
color: var(--text-subtle);
|
|
line-height: 1;
|
|
transition: color .15s var(--ease);
|
|
}
|
|
|
|
.tag-chip .tag-remove:hover { color: var(--red); }
|
|
|
|
/* === Dashboard ("Meine Aufgaben"-Tab, js/dashboard/dashboard.js) ===
|
|
Aufbau: Kopf — Band — zwei Zonen. Die frühere Anordnung stellte die
|
|
Uhrzeit als größte Zahl heraus, zeigte vier gleich große Kennzahlkacheln
|
|
(meist drei davon mit einer Null) und legte alles untereinander, sodass
|
|
der Urlaub eines Kollegen gleichrangig unter den eigenen offenen Aufgaben
|
|
stand. */
|
|
|
|
/* ---------- Kopf: Begrüßung links, Nebensachen rechts ---------- */
|
|
.dash-kopf {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: 20px;
|
|
flex-wrap: wrap;
|
|
margin-bottom: 20px;
|
|
}
|
|
.dash-gruss {
|
|
margin: 0;
|
|
font-size: 22px;
|
|
font-weight: 600;
|
|
letter-spacing: -.02em;
|
|
}
|
|
.dash-gruss em {
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
color: var(--text-muted);
|
|
}
|
|
.dash-kopf-rechts {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 12px;
|
|
}
|
|
.dash-sitzung {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
padding: 2px 9px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--surface-sunk);
|
|
color: var(--text-muted);
|
|
}
|
|
.dash-uhr {
|
|
font-size: 13px;
|
|
color: var(--text-muted);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
/* ---------- Band: der Befund als Satz ---------- */
|
|
.dash-band {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 22px;
|
|
flex-wrap: wrap;
|
|
padding: 16px 20px;
|
|
margin-bottom: 24px;
|
|
background: var(--surface-sunk);
|
|
border-radius: var(--r-lg);
|
|
}
|
|
/* Ohne Befund bleibt das Band farblos — eine Null in Alarmfarbe behauptet
|
|
ein Problem, das es nicht gibt. */
|
|
.dash-band.ist-ruhig {
|
|
background: transparent;
|
|
border: 1px solid var(--line-soft);
|
|
}
|
|
.dash-befund {
|
|
margin: 0;
|
|
flex: 1 1 300px;
|
|
min-width: 0;
|
|
font-size: 17px;
|
|
}
|
|
/* 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-variant-numeric: tabular-nums;
|
|
}
|
|
.dash-befund b.ist-rot { color: var(--red); }
|
|
.dash-befund b.ist-ruhig { color: var(--green); }
|
|
|
|
.dash-band-zahlen { display: flex; gap: 20px; flex-wrap: wrap; }
|
|
.dash-zahl { display: flex; flex-direction: column; gap: 1px; min-width: 74px; }
|
|
.dash-zahl b {
|
|
font-size: 19px;
|
|
font-weight: 600;
|
|
line-height: 1.15;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.dash-zahl span { font-size: 11px; color: var(--text-subtle); white-space: nowrap; }
|
|
.dash-zahl.ist-null b { color: var(--text-subtle); }
|
|
|
|
/* ---------- Zwei Zonen: links der Arbeitsstrom, rechts der Rand ---------- */
|
|
.dash-zonen {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) 300px;
|
|
gap: 24px;
|
|
align-items: start;
|
|
}
|
|
|
|
.dash-abschnitt { margin-bottom: 24px; }
|
|
.dash-abschnitt:last-child { margin-bottom: 0; }
|
|
.dash-abschnitt-kopf {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 10px;
|
|
margin-bottom: 8px;
|
|
}
|
|
.dash-abschnitt-titel {
|
|
margin: 0;
|
|
font-size: 11.5px;
|
|
font-weight: 600;
|
|
letter-spacing: .06em;
|
|
text-transform: uppercase;
|
|
color: var(--text-muted);
|
|
}
|
|
.dash-abschnitt-zahl {
|
|
font-size: 11px;
|
|
padding: 1px 7px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--surface-sunk);
|
|
color: var(--text-muted);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.dash-abschnitt-zusatz {
|
|
margin-left: auto;
|
|
font-size: 11px;
|
|
color: var(--text-subtle);
|
|
}
|
|
|
|
.dash-karte {
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-lg);
|
|
box-shadow: var(--sh-1);
|
|
overflow: hidden;
|
|
}
|
|
.dash-leer { padding: 16px 18px; 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;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
text-decoration: none;
|
|
color: inherit;
|
|
transition: background .12s var(--ease);
|
|
}
|
|
.dash-auf:last-child { border-bottom: none; }
|
|
.dash-auf:hover { background: var(--surface-sunk); }
|
|
.dash-auf:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
|
|
.dash-auf-text { flex: 1 1 auto; min-width: 0; }
|
|
.dash-auf-titel {
|
|
display: block;
|
|
font-size: 13.5px;
|
|
font-weight: 500;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.dash-auf-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 7px;
|
|
flex-wrap: wrap;
|
|
margin-top: 1px;
|
|
font-size: 11px;
|
|
color: var(--text-subtle);
|
|
}
|
|
.dash-auf-tag {
|
|
font-size: 10px;
|
|
padding: 0 6px;
|
|
border-radius: var(--r-sm);
|
|
background: var(--surface-sunk);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.dash-auf-fortschritt { flex: 0 0 96px; display: flex; align-items: center; gap: 8px; }
|
|
.dash-auf-bar {
|
|
flex: 1;
|
|
height: 5px;
|
|
background: var(--surface-sunk);
|
|
border-radius: var(--r-pill);
|
|
overflow: hidden;
|
|
}
|
|
.dash-auf-bar i { display: block; height: 100%; background: var(--accent); border-radius: var(--r-pill); }
|
|
.dash-auf-pct {
|
|
min-width: 30px;
|
|
text-align: right;
|
|
font-size: 11px;
|
|
color: var(--text-subtle);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
.dash-auf-frist {
|
|
flex: 0 0 118px;
|
|
text-align: right;
|
|
font-size: 12px;
|
|
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.ist-ueberfaellig, .dash-auf-frist.ist-ueberfaellig em { color: var(--red); }
|
|
.dash-auf-frist.ist-bald { color: var(--amber); }
|
|
|
|
/* ---------- Rechte Zone: Freigaben und Abwesenheiten ---------- */
|
|
.dash-rand-zeile {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 10px 14px;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.dash-rand-zeile:last-child { border-bottom: none; }
|
|
.dash-avatar {
|
|
flex: 0 0 auto;
|
|
width: 28px;
|
|
height: 28px;
|
|
border-radius: 50%;
|
|
display: grid;
|
|
place-items: center;
|
|
font-size: 10.5px;
|
|
font-weight: 600;
|
|
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-weight: 500;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.dash-rand-meta {
|
|
display: block;
|
|
font-size: 10.5px;
|
|
color: var(--text-subtle);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.dash-chip {
|
|
flex: 0 0 auto;
|
|
font-size: 10px;
|
|
padding: 1px 7px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--surface-sunk);
|
|
color: var(--text-muted);
|
|
white-space: nowrap;
|
|
}
|
|
/* Wer heute fehlt, ist die eigentliche Nachricht. */
|
|
.dash-chip.ist-heute { background: var(--red); color: #fff; }
|
|
|
|
@media (max-width: 1080px) {
|
|
.dash-zonen { grid-template-columns: 1fr; }
|
|
}
|
|
@media (max-width: 720px) {
|
|
.dash-auf-fortschritt { display: none; }
|
|
.dash-gruss { font-size: 19px; }
|
|
}
|
|
|
|
/* Farbe je Abwesenheitsart. Genutzt von .absence-chip (Projektbeteiligte,
|
|
Benutzerverwaltung, Projektbereich) und von .dash-chip im Dashboard.
|
|
.absence-chip-live ist entfallen — das Dashboard kennzeichnet eine heute
|
|
laufende Abwesenheit über .dash-chip.ist-heute. */
|
|
.absence-type-urlaub { background: rgba(36,138,61,.12); color: var(--green); border-color: transparent; }
|
|
.absence-type-krank { background: rgba(215,0,21,.10); color: var(--red); border-color: transparent; }
|
|
.absence-type-fortbildung { background: rgba(178,80,0,.12); color: var(--amber); border-color: transparent; }
|
|
|
|
/* Dark mode GANTT */
|
|
@media (prefers-color-scheme: dark) {
|
|
html:not([data-theme="light"]) .gantt-container { border-color: var(--line); }
|
|
html:not([data-theme="light"]) .gantt-row { border-color: var(--line); }
|
|
html:not([data-theme="light"]) .gantt-row.gantt-header,
|
|
html:not([data-theme="light"]) .gantt-row.gantt-days { border-color: var(--line); }
|
|
html:not([data-theme="light"]) .gantt-month { background: var(--surface-sunk); }
|
|
html:not([data-theme="light"]) .gantt-day.weekend { background: var(--surface-sunk); }
|
|
html:not([data-theme="light"]) .gantt-row.gantt-project.highlighted { background: var(--accent-soft); }
|
|
html:not([data-theme="light"]) .person-absences { background: var(--surface-sunk); border-color: var(--line); }
|
|
html:not([data-theme="light"]) .absence-chip { background: var(--surface); border-color: var(--line); }
|
|
html:not([data-theme="light"]) .absence-type-urlaub { background: rgba(48,209,88,.16); }
|
|
html:not([data-theme="light"]) .absence-type-krank { background: rgba(255,69,58,.16); }
|
|
html:not([data-theme="light"]) .absence-type-fortbildung { background: rgba(255,159,10,.16); }
|
|
}
|
|
|
|
html[data-theme="dark"] .gantt-container { border-color: var(--line); }
|
|
html[data-theme="dark"] .gantt-row { border-color: var(--line); }
|
|
html[data-theme="dark"] .gantt-row.gantt-header,
|
|
html[data-theme="dark"] .gantt-row.gantt-days { border-color: var(--line); }
|
|
html[data-theme="dark"] .gantt-month { background: var(--surface-sunk); }
|
|
html[data-theme="dark"] .gantt-day.weekend { background: var(--surface-sunk); }
|
|
html[data-theme="dark"] .gantt-row.gantt-project.highlighted { background: var(--accent-soft); }
|
|
html[data-theme="dark"] .person-absences { background: var(--surface-sunk); border-color: var(--line); }
|
|
html[data-theme="dark"] .absence-chip { background: var(--surface); border-color: var(--line); }
|
|
html[data-theme="dark"] .absence-type-urlaub { background: rgba(48,209,88,.16); }
|
|
html[data-theme="dark"] .absence-type-krank { background: rgba(255,69,58,.16); }
|
|
html[data-theme="dark"] .absence-type-fortbildung { background: rgba(255,159,10,.16); }
|
|
/* === Bereich „Einstellungen" (js/settings/settings.js) ===
|
|
Karten in einem Raster: „Mein Konto" und „Honorar" sind schmal, die
|
|
Vorlagen-Pflege bekommt über .settings-card-wide die volle Breite, weil
|
|
dort eine Liste mit Bezeichnung, Versatz/Dauer und Lösch-Knopf steht. Die
|
|
Felder der beiden firmenweiten Abschnitte nutzen weiterhin die Klassen aus
|
|
plan-styles.css (.honorar-anteil-field, .template-admin-row …) — sie sind
|
|
mit den Masken aus den Projekt-Dialogen hierher gezogen und mussten dafür
|
|
nicht umbenannt werden. */
|
|
.settings-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
|
gap: 16px;
|
|
align-items: start;
|
|
/* Seit immer nur EIN Abschnitt sichtbar ist (showAdminSection()), füllt
|
|
eine einzelne Karte sonst die ganze Fensterbreite — Beschriftung links,
|
|
Eingabefeld ganz rechts. Die Grenze hält Feld und Bezeichnung beisammen
|
|
und lässt der Aufwands-Matrix trotzdem genug Platz. */
|
|
max-width: 1180px;
|
|
}
|
|
/* Ausnahme fuer breite Abschnitte (Kennzeichen wide in ADMIN_SECTIONS,
|
|
js/admin/admin.js): Die Benutzertabelle hat zehn Spalten und scrollte in
|
|
der begrenzten Breite quer. Sie darf das Fenster ausnutzen. */
|
|
.settings-grid.is-wide { max-width: none; }
|
|
.settings-card-wide { grid-column: 1 / -1; }
|
|
|
|
.settings-card {
|
|
background: var(--surface);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-lg);
|
|
padding: 16px 18px;
|
|
box-shadow: var(--sh-1);
|
|
}
|
|
.settings-card-title {
|
|
margin: 0 0 10px;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 10px;
|
|
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;
|
|
color: var(--text-muted);
|
|
background: var(--surface-alt);
|
|
border-radius: var(--r-pill);
|
|
padding: 2px 8px;
|
|
}
|
|
|
|
.settings-kv { display: flex; flex-direction: column; gap: 2px; margin-bottom: 10px; }
|
|
.settings-kv-row {
|
|
display: flex;
|
|
gap: 10px;
|
|
font-size: 12.5px;
|
|
padding: 5px 0;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.settings-kv-row:last-child { border-bottom: none; }
|
|
.settings-kv-key { width: 150px; flex-shrink: 0; color: var(--text-muted); }
|
|
.settings-warn { color: var(--amber); }
|
|
.settings-email-edit { display: flex; gap: 8px; align-items: center; flex: 1; flex-wrap: wrap; }
|
|
.settings-email-edit input[type=email] { flex: 1; max-width: 320px; min-width: 160px; }
|
|
|
|
.settings-inline-field {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 12.5px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.settings-inline-field select { min-width: 120px; }
|
|
|
|
/* KI-Zugangsdaten (Einstellungen -> Mein Konto, js/settings/settings.js):
|
|
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 + .ai-provider { margin-top: 12px; }
|
|
.ai-provider-head { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
|
|
.ai-provider-info { min-width: 0; }
|
|
.ai-provider-mark {
|
|
width: 26px; height: 26px; border-radius: 7px;
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-size: 12px; font-weight: 700; color: #fff; flex-shrink: 0; letter-spacing: -.02em;
|
|
}
|
|
.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); }
|
|
|
|
/* 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);
|
|
background: var(--surface-alt);
|
|
color: var(--text-muted);
|
|
flex-shrink: 0;
|
|
}
|
|
.ai-status-chip .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-subtle); flex-shrink: 0; }
|
|
.ai-status-chip.is-on { color: var(--green); }
|
|
.ai-status-chip.is-on .dot { background: var(--green); }
|
|
|
|
.ai-provider-row { display: flex; gap: 8px; }
|
|
.ai-provider-row input[type=password],
|
|
.ai-provider-row input[type=text] {
|
|
flex: 1; min-width: 0;
|
|
padding: 7px 10px;
|
|
font-size: 12.5px;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--r-sm);
|
|
background: var(--surface);
|
|
color: var(--text);
|
|
font-family: inherit;
|
|
}
|
|
.ai-provider-row input::placeholder { color: var(--text-subtle); }
|
|
.ai-provider-row input:focus {
|
|
outline: none;
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 3px var(--accent-soft);
|
|
}
|
|
|
|
/* Häkchen-Knopf statt Textknopf "Speichern" — spricht für sich, direkt neben
|
|
dem Feld, das er betrifft. "Entfernen" bleibt ein leiser Text-Link, weil
|
|
er der seltenere, destruktivere Pfad ist. */
|
|
.ai-icon-btn {
|
|
flex-shrink: 0;
|
|
width: 30px; height: 30px; padding: 0;
|
|
border-radius: var(--r-sm);
|
|
border: 1px solid var(--accent);
|
|
background: var(--accent);
|
|
color: #fff;
|
|
display: flex; align-items: center; justify-content: center;
|
|
cursor: pointer;
|
|
transition: background .15s var(--ease), border-color .15s var(--ease);
|
|
}
|
|
.ai-icon-btn:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
|
|
/* flex-shrink:0 ist hier kein Stil-Detail, sondern die Abhilfe für einen
|
|
Chromium-Eigenheit: ein <svg> als Flex-Kind schrumpft ohne explizites
|
|
flex-shrink:0 auf Breite 0 (min-width:auto berechnet die Inhaltsgröße
|
|
eines SVG offenbar als 0), wodurch das Häkchen-Icon unsichtbar wurde. */
|
|
.ai-icon-btn svg { width: 15px; height: 15px; flex-shrink: 0; }
|
|
|
|
.ai-text-btn {
|
|
flex-shrink: 0;
|
|
border: none; background: none;
|
|
font-size: 11.5px; color: var(--text-subtle);
|
|
cursor: pointer; padding: 0 2px;
|
|
}
|
|
.ai-text-btn:hover { color: var(--red); }
|
|
.ai-text-btn:disabled { opacity: .4; cursor: default; }
|
|
.ai-text-btn:disabled:hover { color: var(--text-subtle); }
|
|
|
|
/* Cloud/Eigener-Server-Umschalter: ersetzt den früheren, eingeklappten
|
|
"API-URL"-Link. Ein eigener Server (LM Studio, Ollama) ist ein Kernfall,
|
|
kein Nebendetail — genau das wollte Erik als Erstes ausprobieren, als
|
|
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;
|
|
}
|
|
.ai-mode-toggle button {
|
|
border: none; background: none; padding: 5px 13px; border-radius: var(--r-pill);
|
|
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-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 .ai-provider-row { margin-bottom: 0; }
|
|
|
|
/* "Neu verbinden": prüft die gespeicherte Konfiguration wirklich (POST
|
|
/my-ai-settings/test), statt nur anzuzeigen, dass irgendein Schlüssel
|
|
gespeichert ist. Umrandet statt gefüllt, da kein primärer Speichern-
|
|
Knopf — sitzt direkt neben dem Status-Pill, den er betrifft. */
|
|
.ai-reconnect-btn {
|
|
flex-shrink: 0; width: 26px; height: 26px; padding: 0; border-radius: 50%;
|
|
border: 1px solid var(--line); background: var(--surface); color: var(--text-muted);
|
|
display: flex; align-items: center; justify-content: center; cursor: pointer;
|
|
transition: background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease);
|
|
}
|
|
.ai-reconnect-btn:hover { background: var(--surface-alt); color: var(--accent); border-color: var(--accent); }
|
|
.ai-reconnect-btn:disabled { opacity: .4; cursor: default; }
|
|
.ai-reconnect-btn:disabled:hover { background: var(--surface); color: var(--text-muted); border-color: var(--line); }
|
|
.ai-reconnect-btn svg { width: 13px; height: 13px; flex-shrink: 0; }
|
|
.ai-reconnect-btn.is-testing svg { animation: ai-reconnect-spin .9s linear infinite; }
|
|
@keyframes ai-reconnect-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
|
|
|
/* Fehler aus "Neu verbinden": bleibt stehen, bis der nächste Test läuft
|
|
oder erfolgreich ist — kein flüchtiger Hinweis. Dieselbe Lehre wie beim
|
|
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: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;
|
|
color: var(--green);
|
|
opacity: 0;
|
|
transition: opacity .25s var(--ease);
|
|
}
|
|
.settings-note.show { opacity: 1; }
|
|
|
|
/* Felder und Matrix der firmenweiten Einstellungen (js/settings/settings.js).
|
|
Die Aufwands-Matrix kann breiter werden als die Karte — sie scrollt dann in
|
|
ihrem eigenen Container, statt die Seite quer zu ziehen. */
|
|
.settings-field-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
|
|
gap: 8px 16px;
|
|
margin-bottom: 12px;
|
|
}
|
|
.settings-field {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 10px;
|
|
font-size: 12.5px;
|
|
}
|
|
.settings-field input { width: 88px; padding: 4px 7px; font-size: 12.5px; text-align: right; }
|
|
|
|
.settings-check {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 12.5px;
|
|
margin: 4px 0 2px;
|
|
}
|
|
|
|
.settings-subtitle {
|
|
margin: 16px 0 4px;
|
|
font-size: 12.5px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.settings-matrix-wrap { overflow-x: auto; margin-bottom: 10px; }
|
|
.settings-matrix { border-collapse: collapse; font-size: 12px; }
|
|
.settings-matrix th, .settings-matrix td {
|
|
padding: 3px 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-holiday-list { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; }
|
|
|
|
/* Abweichende Stelle im Auslastungs-Tab (js/load/load.js) — steht nur da,
|
|
wenn die Person nicht voll beschäftigt ist. */
|
|
.load-capacity {
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
color: var(--text-muted);
|
|
background: var(--surface-alt);
|
|
border-radius: var(--r-pill);
|
|
padding: 1px 7px;
|
|
margin-left: 6px;
|
|
}
|
|
|
|
/* Benutzerverwaltung (Abschnitt „Benutzerverwaltung" des Bereichs #admin,
|
|
js/admin-users.js). Diese Regeln standen als <style>-Block in der frueheren
|
|
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; }
|
|
td.actions-cell { white-space: nowrap; }
|
|
td.actions-cell button { margin: 2px; }
|
|
.badge-active { color: var(--green); font-weight: 600; }
|
|
.badge-inactive { color: var(--text-muted); }
|
|
.badge-warn { color: var(--amber); font-weight: 600; }
|
|
/* Das einmalig angezeigte Passwort laesst sich mit einem Klick markieren. */
|
|
#generatedPasswordBox {
|
|
display: none;
|
|
margin-bottom: 14px;
|
|
padding: 12px 14px;
|
|
border-radius: var(--r-md);
|
|
background: var(--surface-alt);
|
|
border: 1px solid var(--line-soft);
|
|
font-size: 13px;
|
|
}
|
|
#generatedPasswordBox b { user-select: all; }
|
|
|
|
/* === Verlauf: die Kacheln der Vorwochen (js/wochenbericht/wochenbericht.js)
|
|
Im wöchentlichen Teammeeting wird jedes Projekt angesehen; der Verlauf
|
|
zeigt auf Knopfdruck, wie der Stand in den Sitzungen davor war. Waagerecht
|
|
und scrollbar, weil der Bericht ohnehin sehr lang ist — eine Liste
|
|
untereinander hätte ihn je Projekt um ein Vielfaches verlängert. === */
|
|
.timeline-block {
|
|
grid-column: 1 / -1;
|
|
margin-top: 12px;
|
|
border-top: 1px solid var(--line-soft);
|
|
padding-top: 10px;
|
|
}
|
|
.timeline-block > summary {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
cursor: pointer;
|
|
font-size: 12.5px;
|
|
color: var(--text-muted);
|
|
list-style: none;
|
|
user-select: none;
|
|
}
|
|
.timeline-block > summary::-webkit-details-marker { display: none; }
|
|
/* Der Zähler schiebt sich sonst über die ganze Kartenbreite ans rechte Ende
|
|
(margin-left:auto von .comment-history-count) und steht dort verloren —
|
|
hier gehört er direkt an das Wort "Verlauf". */
|
|
.timeline-block > summary .comment-history-count { margin-left: 0; }
|
|
.timeline-block > summary:hover { color: var(--text); }
|
|
.timeline-block[open] > summary .comment-history-caret { transform: rotate(90deg); }
|
|
|
|
.timeline-body { padding-top: 10px; }
|
|
|
|
/* 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;
|
|
overflow-x: auto;
|
|
padding-bottom: 6px;
|
|
scroll-snap-type: x proximity;
|
|
}
|
|
.timeline-card {
|
|
flex: 0 0 190px;
|
|
scroll-snap-align: start;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
padding: 10px 11px;
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-md);
|
|
background: var(--surface-alt);
|
|
font-size: 12px;
|
|
}
|
|
.timeline-card-head {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: 6px;
|
|
}
|
|
.timeline-kw { font-weight: 600; 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
|
|
Schiene gleich hoch bleiben; der vollständige Text steht im Tooltip. */
|
|
.timeline-text {
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 6;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
line-height: 1.45;
|
|
min-height: 3em;
|
|
}
|
|
.timeline-leer { color: var(--text-muted); font-style: italic; }
|
|
|
|
.timeline-lph-list { display: flex; flex-direction: column; gap: 1px; }
|
|
.timeline-lph {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 8px;
|
|
font-variant-numeric: tabular-nums;
|
|
color: var(--text-muted);
|
|
}
|
|
.timeline-termine { display: flex; flex-direction: column; gap: 1px; }
|
|
.timeline-termin { color: var(--text-muted); font-size: 11.5px; }
|
|
|
|
/* 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; }
|
|
|
|
/* "übernehmen" in der Verlaufs-Kachel: übernimmt die einzige Funktion, die
|
|
der entfallene Aufklapper "Frühere Sitzungen" über das Anzeigen hinaus
|
|
hatte. Dezent, weil es in jeder Kachel steht und nicht mit dem Kommentar
|
|
um Aufmerksamkeit ringen soll. */
|
|
.timeline-take {
|
|
align-self: flex-start;
|
|
padding: 1px 8px;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--r-pill);
|
|
background: transparent;
|
|
color: var(--text-muted);
|
|
font-family: inherit;
|
|
font-size: 10.5px;
|
|
cursor: pointer;
|
|
}
|
|
.timeline-take:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
|
|
.timeline-take:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
|
|
|
/* Der Verfasser steht in der dichten Fassung in der Fußzeile neben den
|
|
Knöpfen statt in einer eigenen Kopfzeile darüber. */
|
|
/* Der Verfasser teilt sich die Fußzeile mit den Knöpfen. Er darf sie nicht
|
|
zweizeilig machen — deshalb bleibt er auf einer Zeile und wird lieber
|
|
gekürzt; der vollständige Eintrag steht ohnehin im Verlauf. */
|
|
.comment-foot-author {
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
font-size: 11px;
|
|
color: var(--text-subtle);
|
|
}
|
|
.comment-foot-author * { display: inline; white-space: nowrap; }
|
|
/* Das Verfasser-Kürzel klebte sonst am Namen: Der Avatar ist in der Fußzeile
|
|
inline gesetzt und bringt keinen eigenen Abstand mehr mit. */
|
|
.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-chip {
|
|
font-size: 10.5px;
|
|
font-weight: 600;
|
|
padding: 1px 6px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--surface-sunk);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* === Wochenbericht als Tagesordnung (js/wochenbericht/wochenbericht.js) ===
|
|
Links die vollständige Projektliste, rechts das gewählte Projekt. Die
|
|
frühere Abfolge gestapelter Karten war bei 29 Projekten 18 Bildschirmseiten
|
|
lang; hier bleibt die Liste stehen und man sieht jederzeit, wo man steht
|
|
und was noch kommt. */
|
|
.bericht-titelzeile { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
|
|
.bericht-titelzeile button { margin-left: auto; }
|
|
|
|
.bericht-kopf {
|
|
display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
|
|
margin-bottom: 12px;
|
|
}
|
|
.bericht-gewerk-select { font-size: 12.5px; padding: 5px 10px; min-width: 170px; }
|
|
|
|
/* ---------- Planung (Terminplan-Sandbox, js/planung/planung.js) ---------- */
|
|
.planung-row {
|
|
display: flex; align-items: center; gap: 14px;
|
|
padding: 13px 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;
|
|
}
|
|
.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-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; }
|
|
.choice-card {
|
|
border: 1.5px solid var(--line); border-radius: var(--r-md); padding: 14px 14px 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; }
|
|
.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; }
|
|
.bericht-fortschritt { display: flex; align-items: center; gap: 9px; margin-left: auto; }
|
|
.bericht-fortschritt-text { font-size: 12.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
.bericht-fortschritt-bar { width: 120px; height: 6px; border-radius: 3px; background: var(--surface-sunk); overflow: hidden; }
|
|
.bericht-fortschritt-bar i { display: block; height: 100%; background: var(--green); transition: width .25s var(--ease); }
|
|
|
|
.bericht-split {
|
|
display: grid;
|
|
grid-template-columns: 272px minmax(0, 1fr);
|
|
gap: 16px;
|
|
align-items: start;
|
|
}
|
|
@media (max-width: 900px) { .bericht-split { grid-template-columns: 1fr; } }
|
|
|
|
.bericht-liste-spalte {
|
|
background: var(--surface); border-radius: var(--r-md); box-shadow: var(--sh-1);
|
|
overflow: hidden;
|
|
/* Die Liste bleibt beim Scrollen im Blick — sie IST die Tagesordnung. */
|
|
position: sticky; top: 64px;
|
|
}
|
|
.bericht-suche { padding: 8px 9px; border-bottom: 1px solid var(--line-soft); }
|
|
.bericht-suche input { width: 100%; padding: 5px 9px; font-size: 12.5px; }
|
|
.bericht-liste { max-height: min(62vh, 620px); overflow-y: auto; }
|
|
|
|
.bericht-gruppe {
|
|
font-size: 10px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
|
|
color: var(--text-subtle); padding: 9px 11px 3px;
|
|
}
|
|
.bericht-zeile {
|
|
display: flex; align-items: center; gap: 7px;
|
|
padding: 5px 10px; cursor: pointer;
|
|
border-left: 2px solid transparent;
|
|
font-size: 12.5px;
|
|
}
|
|
.bericht-zeile:hover { background: var(--surface-alt); }
|
|
.bericht-zeile:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
.bericht-zeile.is-aktiv { background: var(--accent-soft); border-left-color: var(--accent); }
|
|
/* Abgehakt: zurückgenommen, aber lesbar — man muss im Meeting noch erkennen
|
|
können, was man besprochen hat. */
|
|
.bericht-zeile.is-ab .bericht-zeile-name,
|
|
.bericht-zeile.is-ab .bericht-zeile-nr { color: var(--text-subtle); }
|
|
.bericht-zeile-nr {
|
|
font-family: ui-monospace, 'SF Mono', monospace; font-size: 11px;
|
|
color: var(--text-muted); flex-shrink: 0;
|
|
}
|
|
.bericht-zeile-name { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
|
|
.bericht-haken {
|
|
width: 17px; height: 17px; flex-shrink: 0; padding: 0;
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
border: 1.5px solid var(--line); border-radius: 50%;
|
|
background: transparent; color: transparent;
|
|
font-size: 10px; line-height: 1; cursor: pointer;
|
|
}
|
|
.bericht-haken:hover:not(:disabled) { border-color: var(--green); color: var(--green); }
|
|
.bericht-haken.ab { background: var(--green); border-color: var(--green); color: #fff; }
|
|
.bericht-haken:disabled { cursor: default; opacity: .5; }
|
|
|
|
/* Änderungs-Kennzeichen: nur noch ein Punkt in der Liste — die Gruppierung
|
|
nach Änderungsart ist entfallen, weil im Meeting ohnehin jedes Projekt
|
|
besprochen wird. Die ausformulierte Begründung steht im Detail. */
|
|
/* Die Zustandsklassen tragen ein "is-"-Präfix: Ohne es hieß eine davon
|
|
schlicht "status" und traf die Regel .status { min-width: 240px } weiter
|
|
oben — der 7-px-Punkt wurde 240 px breit und quetschte den Projektnamen
|
|
auf null. */
|
|
.bericht-punkt { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
|
|
.bericht-punkt.is-new, .bericht-punkt.is-status { background: var(--band-neu); }
|
|
.bericht-punkt.is-progress { background: var(--band-fortschritt); }
|
|
.bericht-abwesend {
|
|
font-size: 10px; font-weight: 600; color: var(--amber);
|
|
background: color-mix(in srgb, var(--amber) 15%, transparent);
|
|
border-radius: var(--r-pill); padding: 0 5px; flex-shrink: 0;
|
|
}
|
|
|
|
.bericht-detail {
|
|
background: var(--surface); border-radius: var(--r-md); box-shadow: var(--sh-1);
|
|
padding: 15px 17px 16px; min-width: 0;
|
|
}
|
|
.bericht-detail-kopf { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
|
|
.bericht-detail-kopf h3 { margin: 0; font-size: 16px; font-weight: 600; }
|
|
.bericht-detail-zaehler {
|
|
font-family: ui-monospace, 'SF Mono', monospace; font-size: 11px;
|
|
color: var(--text-subtle); font-variant-numeric: tabular-nums;
|
|
}
|
|
.bericht-detail-meta { color: var(--text-muted); font-size: 12px; margin: 2px 0 12px; }
|
|
.bericht-kennz {
|
|
font-size: 11px; border-radius: var(--r-pill); padding: 1px 9px; color: #fff;
|
|
}
|
|
.bericht-kennz.is-new, .bericht-kennz.is-status { background: var(--band-neu); }
|
|
.bericht-kennz.is-progress { background: var(--band-fortschritt); }
|
|
|
|
.bericht-abwesend-hinweis {
|
|
font-size: 12.5px; color: var(--amber);
|
|
background: color-mix(in srgb, var(--amber) 10%, transparent);
|
|
border-radius: var(--r-sm); padding: 6px 10px; margin-bottom: 10px;
|
|
}
|
|
|
|
/* Der Kommentar der Vorwoche steht ÜBER dem Eingabefeld: "Was hatten wir
|
|
letzte Woche vereinbart?" ist die häufigste Frage im Meeting. */
|
|
.bericht-vorwoche {
|
|
display: flex; gap: 9px; align-items: baseline;
|
|
padding: 7px 10px; margin-bottom: 11px;
|
|
background: var(--surface-alt); border-left: 2px solid var(--line);
|
|
border-radius: 0 var(--r-sm) var(--r-sm) 0;
|
|
font-size: 12.5px;
|
|
}
|
|
.bericht-vorwoche-label { font-weight: 600; color: var(--text-muted); white-space: nowrap; flex-shrink: 0; }
|
|
.bericht-vorwoche-text { color: var(--text-muted); }
|
|
|
|
.bericht-detail-fuss {
|
|
display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
|
|
margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line-soft);
|
|
}
|
|
.bericht-fuss-spacer { flex: 1; }
|
|
|
|
.person-chip-label { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; }
|
|
.protokoll-text {
|
|
width: 100%; font-family: ui-monospace, 'SF Mono', monospace;
|
|
font-size: 12px; line-height: 1.5; resize: vertical;
|
|
}
|
|
|
|
/* === Projektbereich: Leistungsstand & Abrechnung ===========================
|
|
Karte im Dashboard des Projektbereichs (renderPlanLeistung() in
|
|
js/plan/plan-leistung.js): erbrachter Leistungswert aus Honorar, HOAI-Anteil
|
|
je Leistungsphase und Fortschritt der Phase. Ausschliesslich Design-Tokens,
|
|
damit die Karte in hellem und dunklem Thema ohne eigene Dark-Regeln traegt.
|
|
Die Tabelle nutzt .lp-matrix als Grundlage; .num/.strong sind hier eigene
|
|
Regeln, weil die gleichnamigen des Honorar-Dialogs auf .honorar-table
|
|
eingeschraenkt sind (plan-styles.css). */
|
|
|
|
.leistung-kpis {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
margin-bottom: 12px;
|
|
}
|
|
.leistung-kpi {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
flex: 1 1 160px;
|
|
min-width: 150px;
|
|
padding: 10px 12px;
|
|
background: var(--surface-alt);
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-md);
|
|
}
|
|
.leistung-kpi-label {
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
color: var(--text-muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: .03em;
|
|
}
|
|
.leistung-kpi-value {
|
|
font-size: 19px;
|
|
font-weight: 600;
|
|
font-variant-numeric: tabular-nums;
|
|
line-height: 1.2;
|
|
}
|
|
.leistung-kpi-value.accent { color: var(--accent); }
|
|
.leistung-kpi-sub {
|
|
font-size: 11.5px;
|
|
color: var(--text-subtle);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
/* Fortschrittsbalken: derselbe Prozentwert wie die Kennzahl darueber, nur als
|
|
Flaeche — bei zehn Leistungsphasen ist die Gesamtlage sonst nur aus der
|
|
Tabelle zu erschliessen. */
|
|
.leistung-balken {
|
|
height: 7px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--surface-sunk);
|
|
overflow: hidden;
|
|
margin: 0 0 14px;
|
|
}
|
|
.leistung-balken > span {
|
|
display: block;
|
|
height: 100%;
|
|
background: var(--accent);
|
|
border-radius: var(--r-pill);
|
|
transition: width .25s var(--ease);
|
|
}
|
|
|
|
.leistung-table { font-size: 12.5px; }
|
|
.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 tfoot th,
|
|
.leistung-table tfoot td {
|
|
border-top: 1px solid var(--line);
|
|
padding: 6px 8px;
|
|
font-weight: 600;
|
|
background: var(--surface-alt);
|
|
}
|
|
|
|
/* Hinweis, wenn die Rechnung nicht moeglich ist (kein Honorar, keine
|
|
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;
|
|
color: var(--text-muted);
|
|
padding: 10px 12px;
|
|
background: var(--surface-alt);
|
|
border-left: 2px solid var(--amber);
|
|
border-radius: 0 var(--r-sm) var(--r-sm) 0;
|
|
}
|
|
|
|
/* === Auftragsstatus: Kennzeichen an der Projektzeile und Auswahlfeld in den
|
|
Pflegemasken (js/auftrag.js) ===
|
|
Die Farbflächen entstehen mit color-mix aus den Ampel-Tokens, damit sie im
|
|
hellen und im dunklen Erscheinungsbild von selbst mitwandern (feste rgba-
|
|
Flächen tragen im Dark Mode nicht, siehe --attend-bg). Die Schriftfarbe ist
|
|
dasselbe Token — es dreht je Erscheinungsbild ins jeweils kontrastreichere
|
|
Ende. */
|
|
.auftrag-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
border-radius: var(--r-pill);
|
|
padding: 1px 8px;
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
white-space: nowrap;
|
|
background: var(--surface-sunk);
|
|
border: 1px solid var(--line-soft);
|
|
color: var(--text-muted);
|
|
}
|
|
/* Anfrage: hereinkommend, noch nichts entschieden. */
|
|
.auftrag-chip-anfrage {
|
|
background: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
border-color: color-mix(in srgb, var(--accent) 30%, transparent);
|
|
color: var(--accent);
|
|
}
|
|
/* Angebot: draußen, Entscheidung offen — dieselbe Warnfarbe wie die Ampel. */
|
|
.auftrag-chip-angebot {
|
|
background: color-mix(in srgb, var(--amber) 12%, transparent);
|
|
border-color: color-mix(in srgb, var(--amber) 30%, transparent);
|
|
color: var(--amber);
|
|
}
|
|
/* Beauftragt: der Regelfall. Wird an der Projektzeile normalerweise gar nicht
|
|
gezeigt (auftragsstatusChip() gibt dafür einen leeren String zurück), nur in
|
|
Masken, die den Status ausdrücklich ausweisen. */
|
|
.auftrag-chip-beauftragt {
|
|
background: color-mix(in srgb, var(--green) 12%, transparent);
|
|
border-color: color-mix(in srgb, var(--green) 30%, transparent);
|
|
color: var(--green);
|
|
}
|
|
/* Abgeschlossen: erledigt, tritt bewusst zurück. */
|
|
.auftrag-chip-abgeschlossen {
|
|
background: var(--surface-sunk);
|
|
border-color: var(--line);
|
|
color: var(--text-subtle);
|
|
}
|
|
|
|
/* Status-Chip einer Sitzung in der Admin-Liste "Termine & Sitzungen"
|
|
(renderAdminSitzungen(), js/admin/admin.js) — dasselbe Muster wie
|
|
.auftrag-chip: eine neutrale Grundform, drei eingefärbte Zustände. */
|
|
.sitzung-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
border-radius: var(--r-pill);
|
|
padding: 1px 8px;
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
white-space: nowrap;
|
|
background: var(--surface-sunk);
|
|
border: 1px solid var(--line-soft);
|
|
color: var(--text-muted);
|
|
}
|
|
.sitzung-chip.ist-geoeffnet {
|
|
background: color-mix(in srgb, var(--green) 12%, transparent);
|
|
border-color: color-mix(in srgb, var(--green) 30%, transparent);
|
|
color: var(--green);
|
|
}
|
|
.sitzung-chip.ist-entsperrt {
|
|
background: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
border-color: color-mix(in srgb, var(--accent) 30%, transparent);
|
|
color: var(--accent);
|
|
}
|
|
.sitzung-chip.ist-gesperrt {
|
|
background: color-mix(in srgb, var(--amber) 12%, transparent);
|
|
border-color: color-mix(in srgb, var(--amber) 30%, transparent);
|
|
color: var(--amber);
|
|
}
|
|
|
|
.auftrag-select {
|
|
font-size: 12px;
|
|
padding: 3px 8px;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--r-sm);
|
|
background: var(--surface);
|
|
color: var(--text);
|
|
max-width: 100%;
|
|
}
|
|
.auftrag-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
|
|
|
/* ===========================================================
|
|
Ein Ort je Angabe — Anzeige statt Eingabe
|
|
===========================================================
|
|
Kommentar, Fortschritt und Zuordnung werden nur noch im Wochenbericht
|
|
erfasst. Die Projektliste und der Projektbereich zeigen dieselben Werte in
|
|
derselben Anordnung, aber ohne Eingabefelder (Klasse is-ansicht) — daneben
|
|
steht der Weg zur Bearbeitung (.drawer-verweis/.plan-verweis). */
|
|
|
|
/* Der Kommentar als Text: dieselbe Fläche wie der Editor, nur ruhiger. */
|
|
.status-edit.is-ansicht{
|
|
cursor: default;
|
|
background: var(--surface-sunk);
|
|
border-style: dashed;
|
|
}
|
|
|
|
/* Der Prozentwert einer Leistungsphase an der Stelle des Eingabefeldes. Die
|
|
Breite entspricht dem Feld, damit die Balken aller Zeilen gleich weit
|
|
reichen; tabular-nums hält die Ziffern in einer Spalte. */
|
|
.board-lph-wert{
|
|
min-width: 52px;
|
|
text-align: right;
|
|
font-size: 12px;
|
|
font-variant-numeric: tabular-nums;
|
|
color: var(--text-muted);
|
|
}
|
|
.board-lph-row.is-ansicht{ cursor: default; }
|
|
|
|
/* Ein Kürzel, das nicht angeklickt werden kann, zeigt das auch. */
|
|
.board-avatar.is-ansicht{ cursor: default; }
|
|
|
|
/* Der Verweis auf den Erfassungsort. Er steht unter der Karte, in einer
|
|
Zeile mit der Begründung, warum hier nichts einzugeben ist. */
|
|
.drawer-verweis{
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 8px 2px 2px;
|
|
}
|
|
.plan-verweis{
|
|
background: none;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--r-pill);
|
|
padding: 3px 12px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
color: var(--accent);
|
|
cursor: pointer;
|
|
}
|
|
.plan-verweis:hover{ background: var(--accent-soft); }
|
|
.plan-verweis:focus-visible{ outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
|
|
/* ===========================================================
|
|
Projektliste: die Listenoperationen des früheren Projekte-Tabs
|
|
=========================================================== */
|
|
|
|
/* Öffnen/Löschen am Zeilenende. Sichtbar erst beim Überfahren der Zeile,
|
|
damit die Liste im Ruhezustand ruhig bleibt — auf Tastatur-Fokus aber
|
|
ebenfalls, sonst wären die Knöpfe nicht erreichbar. */
|
|
.board-row-actions{
|
|
display: flex;
|
|
gap: 6px;
|
|
flex: 0 0 auto;
|
|
opacity: 0;
|
|
transition: opacity .12s;
|
|
}
|
|
.board-row:hover .board-row-actions,
|
|
.board-row.open .board-row-actions,
|
|
.board-row-actions:focus-within{ opacity: 1; }
|
|
|
|
/* Der Ziehgriff steht vor dem Aufklapp-Pfeil. */
|
|
.board-row .drag-handle{
|
|
flex: 0 0 auto;
|
|
cursor: grab;
|
|
color: var(--text-subtle);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
}
|
|
.board-row .drag-handle:active{ cursor: grabbing; }
|
|
|
|
/* Die Gruppe ist eine Ablagefläche: sie behält eine Mindesthöhe, damit eine
|
|
leer geräumte Gruppe ein Ziel bleibt. */
|
|
.board-list.projects-sortable{ min-height: 34px; }
|
|
|
|
/* Der Verweis unter einer Anzeige-Karte im Projektbereich. */
|
|
.plan-verweis-row{
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
padding-top: 10px;
|
|
}
|
|
.plan-verweis-row:empty{ display: none; }
|
|
|
|
/* Die Schlagwörter-Liste in den Projekteinstellungen darf umbrechen. */
|
|
#settingsProjTags{
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
#settingsProjTags .tag-input{ width: 110px; }
|
|
|
|
/* === Dashboard: Termine meiner Projekte ===
|
|
Die Aufgaben und Meilensteine der Projekte, denen man zugeordnet ist
|
|
(GET /my-dashboard, Feld projectDates). Bewusst eine Liste und keine
|
|
Kartenwand wie "Meine Aufgaben": Hier geht es um Reihenfolge in der Zeit,
|
|
und Termine, die untereinander stehen, lassen sich der Reihe nach
|
|
abarbeiten. */
|
|
/* Die Gruppen sitzen in derselben .dash-karte wie die eigenen Aufgaben
|
|
darüber — beides ist der eigene Arbeitsstrom und soll gleich aussehen.
|
|
Die Titelzeile ist deshalb ein abgesetzter Streifen innerhalb der Karte
|
|
und kein freistehender Abschnittstitel mehr. */
|
|
.fristen-gruppe + .fristen-gruppe { border-top: 1px solid var(--line); }
|
|
|
|
.fristen-gruppe-titel {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 9px;
|
|
padding: 9px 16px 6px;
|
|
background: var(--surface-alt);
|
|
font-size: 10.5px;
|
|
font-weight: 600;
|
|
letter-spacing: .06em;
|
|
text-transform: uppercase;
|
|
color: var(--text-muted);
|
|
}
|
|
.fristen-gruppe-titel span {
|
|
font-size: 10px;
|
|
padding: 1px 7px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--surface-sunk);
|
|
color: var(--text-muted);
|
|
letter-spacing: 0;
|
|
}
|
|
.fristen-gruppe.ist-ueberfaellig .fristen-gruppe-titel { color: var(--red); }
|
|
.fristen-gruppe.ist-ueberfaellig .fristen-gruppe-titel span {
|
|
background: var(--red);
|
|
color: #fff;
|
|
}
|
|
.fristen-gruppe.ist-bald .fristen-gruppe-titel { color: var(--amber); }
|
|
|
|
/* Eine Zeile: Datum — Art — Bezeichnung — Projekt — Zuständige.
|
|
Die Bezeichnung nimmt den freien Platz, alles andere hat feste Breiten,
|
|
damit die Spalten über alle Zeilen fluchten. */
|
|
.fristen-zeile {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
padding: 9px 16px;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
text-decoration: none;
|
|
color: inherit;
|
|
transition: background .12s var(--ease);
|
|
}
|
|
.fristen-zeile:last-child { border-bottom: none; }
|
|
.fristen-zeile:hover { background: var(--surface); }
|
|
.fristen-zeile:focus-visible {
|
|
outline: 2px solid var(--accent);
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
.fristen-datum {
|
|
flex: 0 0 104px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
line-height: 1.25;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.fristen-datum b { font-size: 13px; font-weight: 600; }
|
|
.fristen-datum em {
|
|
font-style: normal;
|
|
font-size: 11px;
|
|
color: var(--text-subtle);
|
|
}
|
|
.ist-ueberfaellig .fristen-datum b,
|
|
.ist-ueberfaellig .fristen-datum em { color: var(--red); }
|
|
.ist-bald .fristen-datum b { color: var(--amber); }
|
|
|
|
.fristen-art {
|
|
flex: 0 0 auto;
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
padding: 2px 8px;
|
|
border-radius: var(--r-pill);
|
|
background: var(--surface-sunk);
|
|
color: var(--text-muted);
|
|
white-space: nowrap;
|
|
}
|
|
.fristen-art.ist-meilenstein {
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
}
|
|
|
|
.fristen-titel {
|
|
flex: 1 1 auto;
|
|
min-width: 0;
|
|
font-size: 13.5px;
|
|
font-weight: 500;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.fristen-projekt {
|
|
flex: 0 0 auto;
|
|
max-width: 230px;
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.fristen-wer {
|
|
flex: 0 0 140px;
|
|
font-size: 11px;
|
|
color: var(--text-subtle);
|
|
text-align: right;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Die Warn-Kachel im Kennzahlenband. Eine Null bleibt neutral — "0
|
|
überfällig" ist eine gute Nachricht und darf nicht rot sein (siehe
|
|
renderStatTile()). */
|
|
.load-num-warnung { color: var(--red); }
|
|
|
|
@media (max-width: 860px) {
|
|
.fristen-projekt, .fristen-wer { display: none; }
|
|
.fristen-datum { flex-basis: 92px; }
|
|
}
|
|
|
|
/* Überfälliges Datum in der Aufgabenkarte des Dashboards — dieselbe
|
|
Kennzeichnung wie in der Terminliste darunter, damit die Kachel
|
|
"Überfällig" und die Listen zusammenpassen. */
|
|
.load-detail b.ist-ueberfaellig { color: var(--red); }
|
|
|
|
/* === Assistent "Neues Projekt" (js/projekt-wizard.js) ===
|
|
Ersetzt den früheren Dialog #newProjModal, der alle Felder auf einmal
|
|
zeigte. Sechs Schritte, und jeder muss vollständig sein, bevor es
|
|
weitergeht — genau die Lücken, die sonst entstehen (kein Honorar, keine
|
|
Phase, niemand zugeordnet), sind der Grund für Projekte, die später in
|
|
der Auslastung als "nicht bewertbar" erscheinen. */
|
|
.wizard-modal {
|
|
max-width: 820px;
|
|
width: 100%;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.wiz-kopf {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 18px 24px 14px;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.wiz-kopf h2 { margin: 0; flex: 1; }
|
|
.wiz-schliessen {
|
|
font-size: 20px;
|
|
line-height: 1;
|
|
padding: 2px 9px;
|
|
background: none;
|
|
border: none;
|
|
color: var(--text-subtle);
|
|
cursor: pointer;
|
|
}
|
|
.wiz-schliessen:hover { color: var(--text); background: none; }
|
|
|
|
/* Schrittleiste: erledigte Stationen tragen einen Haken, damit auch bei
|
|
sechs Schritten jederzeit erkennbar ist, was noch aussteht. */
|
|
.wiz-leiste {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
padding: 16px 24px 0;
|
|
}
|
|
.wiz-stufe {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 12px;
|
|
color: var(--text-subtle);
|
|
}
|
|
.wiz-stufe b {
|
|
width: 24px; height: 24px;
|
|
border-radius: 50%;
|
|
display: grid;
|
|
place-items: center;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
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 b { background: var(--accent); color: #fff; }
|
|
.wiz-stufe.ist-fertig b { background: var(--green); color: #fff; }
|
|
.wiz-strich {
|
|
flex: 1 1 16px;
|
|
min-width: 10px;
|
|
height: 1px;
|
|
background: var(--line);
|
|
margin: 0 8px;
|
|
}
|
|
|
|
.wiz-inhalt {
|
|
padding: 20px 24px 22px;
|
|
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-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); }
|
|
|
|
/* Fußzeile: Der Weiter-Knopf bleibt gesperrt, solange etwas fehlt — und
|
|
daneben steht, WAS fehlt. Ein gesperrter Knopf ohne Begründung ist eine
|
|
Sackgasse. */
|
|
.wiz-fuss {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 14px 24px;
|
|
border-top: 1px solid var(--line-soft);
|
|
background: var(--surface-alt);
|
|
}
|
|
.wiz-zaehler { font-size: 12px; color: var(--text-subtle); }
|
|
.wiz-fuss-rechts {
|
|
margin-left: auto;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
flex-wrap: wrap;
|
|
justify-content: flex-end;
|
|
}
|
|
.wiz-fehlt { font-size: 11.5px; 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;
|
|
cursor: pointer;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--r-pill);
|
|
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; }
|
|
|
|
/* 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;
|
|
color: var(--text-muted);
|
|
}
|
|
.wiz-person {
|
|
font: inherit;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
width: 34px; height: 34px;
|
|
border-radius: 50%;
|
|
border: 1px solid var(--line);
|
|
background: var(--surface);
|
|
color: var(--text-muted);
|
|
padding: 0;
|
|
}
|
|
.wiz-person[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }
|
|
.wiz-person[data-rolle="Projektleitung"][aria-pressed="true"] { background: var(--red); border-color: var(--red); }
|
|
.wiz-person[data-rolle="Bauüberwachung"][aria-pressed="true"] { background: var(--green); border-color: var(--green); }
|
|
/* Wer aus einem anderen Gewerk dazugeholt wurde: gestrichelter Rand, damit
|
|
die Herkunft sichtbar bleibt, ohne eine zweite Farbe einzuführen. */
|
|
.wiz-person.ist-fremd { border-style: dashed; border-width: 1.5px; }
|
|
|
|
.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;
|
|
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-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 11px;
|
|
padding: 3px 6px 3px 10px;
|
|
border-radius: var(--r-pill);
|
|
border: 1px dashed var(--line);
|
|
color: var(--text-muted);
|
|
}
|
|
.wiz-fremd-chip button {
|
|
font: inherit;
|
|
font-size: 13px;
|
|
line-height: 1;
|
|
cursor: pointer;
|
|
border: none;
|
|
background: none;
|
|
color: var(--text-subtle);
|
|
padding: 0 2px;
|
|
}
|
|
.wiz-fremd-chip button:hover { color: var(--red); background: none; }
|
|
|
|
/* Hinweis anstelle eines Schritts, der gerade nicht möglich ist */
|
|
.wiz-sperre {
|
|
padding: 18px 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 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 input { width: 16px; height: 16px; accent-color: var(--accent); }
|
|
|
|
/* Terminplan-Tabelle */
|
|
.wiz-plan {
|
|
margin-top: 16px;
|
|
border: 1px solid var(--line-soft);
|
|
border-radius: var(--r-md);
|
|
overflow: hidden;
|
|
}
|
|
.wiz-plan-zeile {
|
|
display: grid;
|
|
grid-template-columns: 78px 62px 1fr 64px 170px;
|
|
gap: 10px;
|
|
padding: 7px 12px;
|
|
font-size: 12.5px;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.wiz-plan-zeile:last-child { border-bottom: none; }
|
|
.wiz-plan-zeile span:nth-child(2),
|
|
.wiz-plan-zeile span:nth-child(3),
|
|
.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;
|
|
color: var(--text-subtle);
|
|
}
|
|
.wiz-plan-summe { background: var(--surface-alt); font-weight: 600; }
|
|
|
|
/* Zusammenfassung */
|
|
.wiz-pruef { font-size: 13.5px; }
|
|
.wiz-pruef-zeile {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 18px;
|
|
padding: 7px 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; }
|
|
|
|
/* Abschluss */
|
|
.wiz-fertig { text-align: center; padding: 44px 24px; }
|
|
.wiz-haken {
|
|
width: 52px; height: 52px;
|
|
border-radius: 50%;
|
|
margin: 0 auto 16px;
|
|
display: grid;
|
|
place-items: center;
|
|
font-size: 26px;
|
|
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; }
|
|
|
|
@media (max-width: 760px) {
|
|
.wiz-zeile { grid-template-columns: 1fr; }
|
|
.wiz-stufe span { display: none; }
|
|
.wiz-plan-zeile { grid-template-columns: 66px 1fr 130px; }
|
|
.wiz-plan-zeile span:nth-child(2),
|
|
.wiz-plan-zeile span:nth-child(4) { display: none; }
|
|
}
|