Erste Version deckte nur die fünf Tabellen-Seiten ab. Auf Nutzerwunsch jetzt auch Dashboard, Posteingang, Register, Nutzerverwaltung, Fall-/ Antrag-Detail, Wiedervorlage, Betreiber-Accounts/-Audit-Log/-Dashboard und die neuen Genehmiger-Rollen/Freigaben-Seiten. Reine Formular-/Auth- Seiten (Login, Registrieren, Einladung, Nutzer/Firma anlegen) bleiben bewusst bei 1100px - ein einzelnes Formular auf voller Breite wäre schlechter lesbar. .page-wide selbst wurde von "kein Limit" auf 1600px korrigiert, da Detailseiten mit Fließtext (Fall-/Antrag-Detail) sonst auf Ultrawide-Monitoren unlesbar lange Zeilen bekommen hätten. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1074 lines
23 KiB
CSS
1074 lines
23 KiB
CSS
/* Deklarix — eigenes, schlankes Stylesheet auf Basis der Design-Tokens
|
|
aus dem enconf Enterprise Light Theme (design/enterprise.css): gleiche
|
|
Marke (Primärblau #1677ff, Inter, Radius-Skala). Mobile-first:
|
|
Basis-Stile gelten fürs Telefon (Nav als aufklappbares <details>-Menü
|
|
ohne JavaScript), @media (min-width: 960px) verwandelt dieselbe
|
|
Nav-Markup-Struktur per CSS in eine feste Seitenleiste (siehe
|
|
.topbar/.app-nav) — kein separates Desktop-Template nötig. */
|
|
|
|
@import url('/static/inter.css');
|
|
|
|
:root {
|
|
--branding-primary: #1677ff;
|
|
--radius: 6px;
|
|
--radius-md: 8px;
|
|
--radius-lg: 10px;
|
|
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
--shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
|
|
--color-bg: #f8fafc;
|
|
--color-text: #334155;
|
|
--color-heading: #0f172a;
|
|
--color-border: #e2e8f0;
|
|
--color-muted: #64748b;
|
|
|
|
--color-hoch: #b91c1c;
|
|
--color-hoch-bg: #fef2f2;
|
|
--color-mittel: #b45309;
|
|
--color-mittel-bg: #fffbeb;
|
|
--color-niedrig: #166534;
|
|
--color-niedrig-bg: #f0fdf4;
|
|
|
|
--sidebar-width: 220px;
|
|
--sidebar-bg: linear-gradient(180deg, #0b1426 0%, #101d33 50%, #0d1829 100%);
|
|
--sidebar-text: #b6c2d9;
|
|
--sidebar-text-hover: #ffffff;
|
|
--sidebar-hover-bg: rgba(255, 255, 255, 0.08);
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html {
|
|
-webkit-text-size-adjust: 100%;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background: var(--color-bg);
|
|
color: var(--color-text);
|
|
font-size: 16px;
|
|
line-height: 1.5;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
|
|
h1, h2, h3 {
|
|
color: var(--color-heading);
|
|
font-weight: 600;
|
|
letter-spacing: -0.02em;
|
|
margin: 0 0 0.6em;
|
|
}
|
|
|
|
h2 {
|
|
font-size: 1.25rem;
|
|
}
|
|
|
|
h3 {
|
|
font-size: 1.0625rem;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 1.5rem;
|
|
}
|
|
|
|
p {
|
|
margin: 0 0 1em;
|
|
}
|
|
|
|
a {
|
|
color: var(--branding-primary);
|
|
}
|
|
|
|
/* Container: volle Breite + Innenabstand auf dem Handy, zentriert mit
|
|
fester Breite ab Tablet-Größe aufwärts. */
|
|
.page {
|
|
padding: 16px;
|
|
max-width: 640px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
/* ── Navigation ──────────────────────────────────────────────────────
|
|
Mobil: .topbar ist eine schmale, fixierte Kopfleiste mit einem
|
|
aufklappbaren <details>-Menü (siehe layout.html) — kein JavaScript,
|
|
das <details>-Element liefert Auf-/Zuklappen nativ. Ab Desktop-Breite
|
|
(siehe Media Query unten) wird dieselbe Markup-Struktur per CSS in
|
|
eine permanent sichtbare, dunkle Seitenleiste verwandelt. */
|
|
.topbar {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 10;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 12px 16px;
|
|
background: #fff;
|
|
border-bottom: 1px solid var(--color-border);
|
|
}
|
|
|
|
.brand {
|
|
font-weight: 600;
|
|
color: var(--color-heading);
|
|
text-decoration: none;
|
|
letter-spacing: -0.01em;
|
|
}
|
|
|
|
/* Checkbox-Hack: eine unsichtbare Checkbox plus ein <label for=...>
|
|
als Klick-/Tap-Ziel steuern per CSS-Geschwister-Selektor, ob .app-nav
|
|
sichtbar ist — funktioniert ohne JavaScript und ohne die Falle von
|
|
<details> (siehe Kommentar in layout.html). */
|
|
.nav-toggle {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
overflow: hidden;
|
|
clip: rect(0, 0, 0, 0);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.nav-toggle-label {
|
|
cursor: pointer;
|
|
padding: 8px 14px;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius);
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
color: var(--color-text);
|
|
}
|
|
|
|
.nav-toggle:focus-visible ~ .nav-toggle-label {
|
|
outline: 2px solid var(--branding-primary);
|
|
outline-offset: 1px;
|
|
}
|
|
|
|
.nav-toggle:checked ~ .nav-toggle-label {
|
|
border-color: var(--branding-primary);
|
|
color: var(--branding-primary);
|
|
}
|
|
|
|
.app-nav {
|
|
display: none;
|
|
position: absolute;
|
|
top: calc(100% + 6px);
|
|
right: 16px;
|
|
z-index: 20;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
min-width: 220px;
|
|
padding: 8px;
|
|
background: #fff;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-md);
|
|
box-shadow: var(--shadow-md);
|
|
}
|
|
|
|
.nav-toggle:checked ~ .app-nav {
|
|
display: flex;
|
|
}
|
|
|
|
.app-nav a {
|
|
padding: 10px 12px;
|
|
border-radius: var(--radius);
|
|
color: var(--color-text);
|
|
font-size: 0.9375rem;
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.app-nav a:hover {
|
|
background: var(--color-bg);
|
|
color: var(--branding-primary);
|
|
}
|
|
|
|
.app-nav form {
|
|
margin: 4px 0 0;
|
|
}
|
|
|
|
.app-nav button {
|
|
width: 100%;
|
|
margin-top: 0;
|
|
background: transparent;
|
|
color: var(--color-hoch);
|
|
border: 1px solid var(--color-hoch-bg);
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* Formulare: großzügige Touch-Ziele (min. 44px Höhe), volle Breite auf
|
|
dem Handy. */
|
|
form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
label {
|
|
font-weight: 500;
|
|
font-size: 0.875rem;
|
|
color: var(--color-heading);
|
|
margin-top: 12px;
|
|
}
|
|
|
|
input, select, textarea, button {
|
|
font: inherit;
|
|
font-size: 16px; /* verhindert Auto-Zoom beim Fokussieren auf iOS */
|
|
}
|
|
|
|
input, select, textarea {
|
|
padding: 10px 12px;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius);
|
|
background: #fff;
|
|
color: var(--color-text);
|
|
min-height: 44px;
|
|
width: 100%;
|
|
}
|
|
|
|
textarea {
|
|
min-height: 120px;
|
|
resize: vertical;
|
|
}
|
|
|
|
input:focus, select:focus, textarea:focus {
|
|
outline: 2px solid var(--branding-primary);
|
|
outline-offset: 1px;
|
|
border-color: var(--branding-primary);
|
|
}
|
|
|
|
button {
|
|
margin-top: 16px;
|
|
padding: 12px 20px;
|
|
min-height: 44px;
|
|
border: none;
|
|
border-radius: var(--radius);
|
|
background: var(--branding-primary);
|
|
color: #fff;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
button:hover {
|
|
filter: brightness(0.94);
|
|
}
|
|
|
|
button:active {
|
|
filter: brightness(0.88);
|
|
}
|
|
|
|
nav button {
|
|
margin-top: 0;
|
|
background: transparent;
|
|
color: var(--color-muted);
|
|
border: 1px solid var(--color-border);
|
|
box-shadow: none;
|
|
min-height: 36px;
|
|
padding: 6px 14px;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.hinweis {
|
|
font-size: 0.8125rem;
|
|
color: var(--color-muted);
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.disclaimer {
|
|
font-size: 0.8125rem;
|
|
color: var(--color-muted);
|
|
border-top: 1px solid var(--color-border);
|
|
padding-top: 12px;
|
|
margin-top: 24px;
|
|
}
|
|
|
|
/* Support-Login-Hinweis (siehe currentImpersonator in middleware.go) —
|
|
bewusst auffällig (nicht im normalen .hinweis-Grauton), damit niemand
|
|
vergisst, gerade im Kontext eines fremden Kontos zu handeln. */
|
|
.impersonation-banner {
|
|
background: var(--color-mittel-bg);
|
|
color: var(--color-mittel);
|
|
padding: 10px 16px;
|
|
font-size: 0.875rem;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 12px;
|
|
border-bottom: 1px solid var(--color-mittel);
|
|
}
|
|
|
|
.impersonation-banner form {
|
|
margin: 0;
|
|
}
|
|
|
|
.impersonation-banner button {
|
|
margin-top: 0;
|
|
min-height: 32px;
|
|
padding: 4px 12px;
|
|
font-size: 0.8125rem;
|
|
}
|
|
|
|
@media (min-width: 960px) {
|
|
.impersonation-banner {
|
|
margin-left: var(--sidebar-width);
|
|
}
|
|
}
|
|
|
|
.fehler {
|
|
background: var(--color-hoch-bg);
|
|
color: var(--color-hoch);
|
|
border-radius: var(--radius);
|
|
padding: 12px;
|
|
font-size: 0.9375rem;
|
|
}
|
|
|
|
.rueckfrage {
|
|
background: var(--color-mittel-bg);
|
|
color: var(--color-mittel);
|
|
border-radius: var(--radius);
|
|
padding: 12px;
|
|
}
|
|
|
|
.keine-findings {
|
|
background: var(--color-niedrig-bg);
|
|
color: var(--color-niedrig);
|
|
border-radius: var(--radius);
|
|
padding: 12px;
|
|
}
|
|
|
|
.archiviert {
|
|
background: var(--color-niedrig-bg);
|
|
color: var(--color-niedrig);
|
|
border-radius: var(--radius);
|
|
padding: 12px;
|
|
}
|
|
|
|
.findings {
|
|
list-style: none;
|
|
margin: 0 0 16px;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.finding {
|
|
border-radius: var(--radius-md);
|
|
padding: 12px 14px;
|
|
box-shadow: var(--shadow);
|
|
}
|
|
|
|
.finding p {
|
|
margin: 6px 0 0;
|
|
font-size: 0.9375rem;
|
|
}
|
|
|
|
.finding-hoch {
|
|
background: var(--color-hoch-bg);
|
|
border-left: 4px solid var(--color-hoch);
|
|
}
|
|
|
|
.finding-mittel {
|
|
background: var(--color-mittel-bg);
|
|
border-left: 4px solid var(--color-mittel);
|
|
}
|
|
|
|
.finding-niedrig {
|
|
background: var(--color-niedrig-bg);
|
|
border-left: 4px solid var(--color-niedrig);
|
|
}
|
|
|
|
.status {
|
|
display: inline-block;
|
|
font-size: 0.75rem;
|
|
font-weight: 500;
|
|
padding: 2px 8px;
|
|
border-radius: var(--radius);
|
|
background: var(--color-border);
|
|
color: var(--color-muted);
|
|
}
|
|
|
|
.status-published {
|
|
background: var(--color-niedrig-bg);
|
|
color: var(--color-niedrig);
|
|
}
|
|
|
|
.status-checked,
|
|
.status-mittel {
|
|
background: var(--color-mittel-bg);
|
|
color: var(--color-mittel);
|
|
}
|
|
|
|
.status-niedrig {
|
|
background: var(--color-niedrig-bg);
|
|
color: var(--color-niedrig);
|
|
}
|
|
|
|
.status-hoch {
|
|
background: var(--color-hoch-bg);
|
|
color: var(--color-hoch);
|
|
}
|
|
|
|
.beitraege-liste {
|
|
list-style: none;
|
|
margin: 0 0 16px;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
|
|
.beitraege-liste li a,
|
|
/* Einträge ohne umschließenden Link (Zeilen mit Badge/Aktions-Buttons
|
|
statt Navigation, z. B. Nutzer-/Abteilungsliste) bekommen dieselbe
|
|
Karte direkt auf dem <li> — :has() unterscheidet beide Fälle, damit
|
|
ein verlinkter Eintrag nicht doppelt (li UND a) gerahmt wird. */
|
|
.beitraege-liste > li:not(:has(> a)) {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 12px 14px;
|
|
border-radius: var(--radius-md);
|
|
box-shadow: var(--shadow);
|
|
background: #fff;
|
|
color: var(--color-text);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.beitraege-liste > li:not(:has(> a)) form {
|
|
margin: 0;
|
|
flex: 0 0 auto;
|
|
max-width: 100%;
|
|
}
|
|
|
|
.beitraege-liste > li:not(:has(> a)) button {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.beteiligte {
|
|
list-style: none;
|
|
margin: 0 0 16px;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
|
|
.beteiligter {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 12px 14px;
|
|
border-radius: var(--radius-md);
|
|
box-shadow: var(--shadow);
|
|
background: #fff;
|
|
}
|
|
|
|
.beteiligter-kopf {
|
|
flex: 1 1 100%;
|
|
}
|
|
|
|
.beteiligter .rolle {
|
|
color: var(--color-muted);
|
|
font-weight: 400;
|
|
}
|
|
|
|
.beteiligter-form {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin: 0;
|
|
flex: 1 1 auto;
|
|
}
|
|
|
|
.beteiligter-form label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
font-weight: 400;
|
|
margin: 0;
|
|
}
|
|
|
|
.beteiligter-form input[type="checkbox"] {
|
|
width: auto;
|
|
min-height: 0;
|
|
}
|
|
|
|
.beteiligter form:last-child {
|
|
margin: 0;
|
|
}
|
|
|
|
button.entfernen {
|
|
margin: 0;
|
|
background: transparent;
|
|
color: var(--color-hoch);
|
|
border: 1px solid var(--color-hoch-bg);
|
|
box-shadow: none;
|
|
min-height: 36px;
|
|
padding: 6px 14px;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.admin-kacheln {
|
|
list-style: none;
|
|
margin: 0 0 16px;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
|
|
.admin-kacheln a {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 14px 16px;
|
|
border-radius: var(--radius-md);
|
|
box-shadow: var(--shadow);
|
|
background: #fff;
|
|
color: var(--color-text);
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.kanzlei-eintrag {
|
|
display: block;
|
|
padding: 12px 14px;
|
|
border-radius: var(--radius-md);
|
|
box-shadow: var(--shadow);
|
|
background: #fff;
|
|
}
|
|
|
|
.fragebogen fieldset {
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-md);
|
|
padding: 12px 14px;
|
|
margin: 12px 0;
|
|
}
|
|
|
|
.fragebogen legend {
|
|
font-weight: 600;
|
|
font-size: 1rem;
|
|
padding: 0 4px;
|
|
}
|
|
|
|
.fragebogen fieldset label {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
font-weight: 400;
|
|
margin: 4px 12px 4px 0;
|
|
}
|
|
|
|
/* ── Formular-Karten (Enterprise-Look, siehe design/enterprise.css
|
|
.ant-card/.ant-form-item) ─────────────────────────────────────────
|
|
Ersetzt "ein Formular = eine flache, ununterbrochene Spalte" durch
|
|
klar abgegrenzte Abschnitte mit Titel und ein Grid für kurze Felder
|
|
nebeneinander statt jedes Feld einzeln untereinander. */
|
|
.form-card {
|
|
background: #fff;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow-sm);
|
|
margin-bottom: 24px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.form-card form {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.form-section {
|
|
border: none;
|
|
margin: 0;
|
|
padding: 20px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.form-section + .form-section {
|
|
border-top: 1px solid var(--color-border);
|
|
}
|
|
|
|
/* <legend> ignoriert das padding des umschließenden <fieldset> (es
|
|
positioniert sich an dessen Border-Box, nicht an der Padding-Box) —
|
|
ohne eigenes padding-left säße die Abschnittsüberschrift bündig am
|
|
Kartenrand, während der restliche Inhalt eingerückt ist. */
|
|
.form-section > legend {
|
|
padding: 0 0 16px 0;
|
|
font-size: 1.0625rem;
|
|
font-weight: 700;
|
|
color: var(--color-heading);
|
|
width: 100%;
|
|
}
|
|
|
|
.form-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr;
|
|
gap: 0 16px;
|
|
}
|
|
|
|
@media (min-width: 640px) {
|
|
.form-grid {
|
|
grid-template-columns: 1fr 1fr;
|
|
}
|
|
|
|
.form-grid .form-full {
|
|
grid-column: 1 / -1;
|
|
}
|
|
}
|
|
|
|
/* Checkbox-/Radio-Gruppen als Chips statt einer langen
|
|
Untereinander-Liste — v. a. bei den zwölf Zweck-Kategorien war das
|
|
vorher eine kaum überblickbare Spalte. */
|
|
.chip-group {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.chip-group label {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
margin-top: 0;
|
|
padding: 7px 14px;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 999px;
|
|
font-size: 0.8125rem;
|
|
font-weight: 500;
|
|
color: var(--color-text);
|
|
background: var(--color-bg);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.chip-group input[type="checkbox"],
|
|
.chip-group input[type="radio"] {
|
|
width: auto;
|
|
min-height: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.chip-group label:has(input:checked) {
|
|
border-color: var(--branding-primary);
|
|
background: rgba(22, 119, 255, 0.08);
|
|
color: var(--branding-primary);
|
|
}
|
|
|
|
.form-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
padding: 16px 20px;
|
|
background: var(--color-bg);
|
|
}
|
|
|
|
.form-actions form,
|
|
.form-actions button {
|
|
margin: 0;
|
|
}
|
|
|
|
.form-gefahrenzone {
|
|
border-top: 1px solid var(--color-border);
|
|
padding: 16px 20px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.form-gefahrenzone form {
|
|
margin: 0;
|
|
}
|
|
|
|
.fragebogen fieldset input[type="radio"] {
|
|
width: auto;
|
|
min-height: 0;
|
|
}
|
|
|
|
/* Adaptive Folgefragen: rein clientseitig per :has() ein-/ausgeblendet,
|
|
kein JavaScript nötig. Siehe templates/antrag_neu.html — die "Ja"-
|
|
Antwort trägt eine eigene Klasse (c2-ja/c3-ja), damit sich die
|
|
jeweilige Folgefrage gezielt zuordnen lässt. */
|
|
.mit-folgefrage .folgefrage {
|
|
display: none;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.mit-folgefrage:has(.c2-ja input:checked) .folgefrage,
|
|
.mit-folgefrage:has(.c3-ja input:checked) .folgefrage {
|
|
display: block;
|
|
}
|
|
|
|
/* Tabellen (z. B. Register-Export-Ansicht) — bewusst horizontal
|
|
scrollbar in einem eigenen Wrapper statt schrumpfender Spalten: bei
|
|
neun Spalten wie im Register würde Schrumpfen nur unlesbaren Text
|
|
erzeugen, siehe .table-scroll in register_liste.html. */
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
background: #fff;
|
|
border-radius: var(--radius-md);
|
|
overflow: hidden;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
th, td {
|
|
padding: 10px 12px;
|
|
text-align: left;
|
|
border-bottom: 1px solid var(--color-border);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
th {
|
|
background: var(--color-bg);
|
|
color: var(--color-heading);
|
|
font-weight: 600;
|
|
font-size: 0.8125rem;
|
|
}
|
|
|
|
tbody tr:hover {
|
|
background: var(--color-bg);
|
|
}
|
|
|
|
/* Ohne dieses Signal sieht eine breite, am Fensterrand abgeschnittene
|
|
Tabelle wie ein Rendering-Fehler aus statt wie "hier geht's mit
|
|
Scrollen weiter" — der Fade ist bewusst immer sichtbar (kein JS, das
|
|
den Scroll-Zustand prüfen könnte), auch am Ende der Tabelle. */
|
|
.table-scroll {
|
|
overflow-x: auto;
|
|
box-shadow: var(--shadow);
|
|
border-radius: var(--radius-md);
|
|
margin-bottom: 16px;
|
|
-webkit-mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
|
|
mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
|
|
}
|
|
|
|
/* Filter-/Paginierungsleiste für Listen-Seiten (Werkzeugkatalog,
|
|
Register, ...) — ein einziges GET-Formular ohne JavaScript, siehe
|
|
pagination.go. */
|
|
.filter-bar {
|
|
display: flex;
|
|
/* explizit setzen, nicht dem initial-value überlassen: .filter-bar
|
|
landet manchmal direkt auf einem <form>, und "form { flex-direction:
|
|
column }" (oben) hat dieselbe Spezifität für DIESE Property, wenn
|
|
.filter-bar sie nicht selbst deklariert — das Formular würde dann
|
|
senkrecht stapeln statt in einer Zeile. */
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.filter-bar input[type="search"] {
|
|
flex: 1 1 220px;
|
|
min-height: 40px;
|
|
}
|
|
|
|
.filter-bar select {
|
|
flex: 0 1 200px;
|
|
min-height: 40px;
|
|
}
|
|
|
|
.filter-bar button {
|
|
margin-top: 0;
|
|
min-height: 40px;
|
|
}
|
|
|
|
.pagination {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.pagination button {
|
|
margin-top: 0;
|
|
min-height: 36px;
|
|
padding: 6px 14px;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
/* ── Responsive Tabellen — Card-Ansicht auf dem Handy ────────────────
|
|
enconf-Pattern (ProTable.tsx): auf schmalen Screens wird nicht
|
|
horizontal gescrollt, sondern jede Zeile zu einer eigenen Karte mit
|
|
Label/Wert-Paaren. Braucht data-label="Spaltenname" auf jedem <td>.
|
|
Ab 640px bleibt es eine normale Tabelle (mit Scroll-Fade als
|
|
Sicherheitsnetz bei vielen Spalten). */
|
|
.table-responsive {
|
|
overflow-x: auto;
|
|
box-shadow: var(--shadow);
|
|
border-radius: var(--radius-md);
|
|
margin-bottom: 16px;
|
|
-webkit-mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
|
|
mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
|
|
}
|
|
|
|
@media (max-width: 639px) {
|
|
.table-responsive {
|
|
overflow-x: visible;
|
|
box-shadow: none;
|
|
border-radius: 0;
|
|
-webkit-mask-image: none;
|
|
mask-image: none;
|
|
}
|
|
|
|
.table-responsive table,
|
|
.table-responsive tbody,
|
|
.table-responsive tr,
|
|
.table-responsive td {
|
|
display: block;
|
|
width: 100%;
|
|
}
|
|
|
|
.table-responsive thead {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
overflow: hidden;
|
|
clip: rect(0, 0, 0, 0);
|
|
}
|
|
|
|
.table-responsive tbody tr {
|
|
margin-bottom: 12px;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-md);
|
|
background: #fff;
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
.table-responsive td {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: baseline;
|
|
gap: 12px;
|
|
text-align: right;
|
|
padding: 8px 12px;
|
|
border-bottom: 1px solid var(--color-border);
|
|
white-space: normal;
|
|
}
|
|
|
|
.table-responsive td:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.table-responsive td::before {
|
|
content: attr(data-label);
|
|
font-weight: 600;
|
|
color: var(--color-heading);
|
|
text-align: left;
|
|
flex-shrink: 0;
|
|
}
|
|
}
|
|
|
|
/* ── Seitenkopf (PageHeader-Pattern, enconf) ─────────────────────────
|
|
Titel + Unterzeile links, primäre Aktion rechts — statt eines
|
|
nackten <h1> mit einem Link irgendwo unten auf der Seite. */
|
|
.page-header {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.page-header h1 {
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.page-header .hinweis {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.page-header .page-header-action {
|
|
margin-top: 4px;
|
|
white-space: nowrap;
|
|
display: inline-block;
|
|
padding: 10px 18px;
|
|
border-radius: var(--radius);
|
|
background: var(--branding-primary);
|
|
color: #fff;
|
|
font-weight: 500;
|
|
font-size: 0.9375rem;
|
|
text-decoration: none;
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
.page-header .page-header-action:hover {
|
|
filter: brightness(0.94);
|
|
}
|
|
|
|
/* ── Kennzahl-Kacheln (StatCard-Pattern, enconf Dashboard) ───────────
|
|
Vorher: einfache Text-Links in einer Liste ohne visuelle Priorität.
|
|
Jetzt: farbiger oberer Akzentrand + große Zahl + Klick navigiert zur
|
|
Liste, wie enconfs StatCard-Komponente — nur ohne Icon-Bibliothek. */
|
|
.stat-cards {
|
|
list-style: none;
|
|
margin: 0 0 24px;
|
|
padding: 0;
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
gap: 12px;
|
|
}
|
|
|
|
.stat-card {
|
|
display: block;
|
|
background: #fff;
|
|
border: 1px solid var(--color-border);
|
|
border-top: 3px solid var(--branding-primary);
|
|
border-radius: var(--radius-md);
|
|
box-shadow: var(--shadow-sm);
|
|
padding: 16px 18px;
|
|
text-decoration: none;
|
|
transition: box-shadow 0.15s ease;
|
|
}
|
|
|
|
.stat-card:hover {
|
|
box-shadow: var(--shadow-md);
|
|
}
|
|
|
|
.stat-card-value {
|
|
display: block;
|
|
font-size: 1.75rem;
|
|
font-weight: 700;
|
|
color: var(--color-heading);
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.stat-card-label {
|
|
display: block;
|
|
font-size: 0.875rem;
|
|
color: var(--color-muted);
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.stat-card-mittel {
|
|
border-top-color: var(--color-mittel);
|
|
}
|
|
|
|
.stat-card-hoch {
|
|
border-top-color: var(--color-hoch);
|
|
}
|
|
|
|
.stat-card-action {
|
|
background: var(--branding-primary);
|
|
border-color: var(--branding-primary);
|
|
display: flex;
|
|
align-items: center;
|
|
height: 100%;
|
|
}
|
|
|
|
.stat-card-action .stat-card-label {
|
|
color: #fff;
|
|
font-weight: 600;
|
|
font-size: 0.9375rem;
|
|
margin-top: 0;
|
|
}
|
|
|
|
/* Ab hier mehr Platz (Tablet) — der Container bekommt spürbaren
|
|
Rand statt volle Breite, sonst bleibt alles identisch. */
|
|
@media (min-width: 640px) {
|
|
.page {
|
|
padding: 32px 24px;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 1.75rem;
|
|
}
|
|
}
|
|
|
|
/* Ab Desktop-Breite: dieselbe .topbar/.app-nav-Markup wird zu einer
|
|
permanent sichtbaren, dunklen Seitenleiste — kein separates
|
|
Desktop-Template, nur CSS. Der `details`/`summary`-Aufklapp-
|
|
Mechanismus wird hier überschrieben (Inhalt immer sichtbar,
|
|
summary versteckt), das Handy-Verhalten bleibt darunter unverändert. */
|
|
@media (min-width: 960px) {
|
|
.topbar {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
width: var(--sidebar-width);
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
justify-content: flex-start;
|
|
gap: 8px;
|
|
padding: 20px 16px;
|
|
background: var(--sidebar-bg);
|
|
border-bottom: none;
|
|
border-right: 1px solid rgba(255, 255, 255, 0.08);
|
|
z-index: 10;
|
|
}
|
|
|
|
.brand {
|
|
color: #fff;
|
|
font-size: 1.125rem;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.nav-toggle-label {
|
|
display: none;
|
|
}
|
|
|
|
.app-nav {
|
|
display: flex;
|
|
position: static;
|
|
min-width: 0;
|
|
padding: 0;
|
|
background: transparent;
|
|
border: none;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.app-nav a {
|
|
color: var(--sidebar-text);
|
|
}
|
|
|
|
.app-nav a:hover {
|
|
background: var(--sidebar-hover-bg);
|
|
color: var(--sidebar-text-hover);
|
|
}
|
|
|
|
.app-nav button {
|
|
color: var(--sidebar-text);
|
|
border-color: rgba(255, 255, 255, 0.15);
|
|
}
|
|
|
|
.app-nav button:hover {
|
|
background: var(--sidebar-hover-bg);
|
|
color: var(--sidebar-text-hover);
|
|
filter: none;
|
|
}
|
|
|
|
.page {
|
|
margin-left: var(--sidebar-width);
|
|
max-width: 1100px;
|
|
padding: 32px 40px;
|
|
width: 100%;
|
|
}
|
|
|
|
/* Tabellen-/Listen-/Dashboard-Seiten verschwenden bei 1100px sichtbar
|
|
Platz auf breiten Bildschirmen, während Tabellen selbst schon
|
|
horizontal gescrollt/gequetscht werden müssen — .page-wide hebt die
|
|
Deckelung für genau diese Seiten an. Bewusst 1600px statt "kein
|
|
Limit": manche dieser Seiten (Fall-/Antrag-Detail) enthalten auch
|
|
Fließtext-Absätze, die auf einem Ultrawide-Monitor sonst unlesbar
|
|
lange Zeilen bekämen. Reine Formular-/Auth-Seiten (Login,
|
|
Registrieren, Einladung, ...) bleiben bei 1100px, dort ist die
|
|
schmalere Spalte weiterhin die bessere Lesbarkeit. */
|
|
.page-wide {
|
|
max-width: 1600px;
|
|
}
|
|
}
|