Quelltext des aktuellen Standes
/**
* IT-Dokumentation - Hauptstylesheet
* Design: AdminLTE-inspiriert, professionelles IT-Admin-Interface
*/
/* ============================================================
CSS Custom Properties
============================================================ */
/* Design-Tokens (Farben, Abstände, Layout-Variablen) liegen in tokens.css
und werden in den Layouts vor dieser Datei geladen. */
/* ============================================================
Reset & Basis
============================================================ */
*, *::before, *::after { box-sizing: border-box; }
html {
font-size: 16px;
-webkit-text-size-adjust: 100%;
overflow-x: hidden;
}
body {
margin: 0;
padding: 0;
font-family: var(--font-family);
font-size: var(--font-size-base);
line-height: 1.6;
color: var(--color-text);
background-color: var(--color-bg-alt);
overflow-x: hidden;
}
h1, h2, h3, h4, h5, h6 {
margin: 0 0 var(--spacing-md);
font-weight: 600;
line-height: 1.3;
color: var(--color-gray-900);
}
h1 { font-size: var(--font-size-3xl); }
h2 { font-size: var(--font-size-2xl); }
h3 { font-size: var(--font-size-xl); }
h4 { font-size: var(--font-size-lg); }
p { margin: 0 0 var(--spacing-md); }
a {
color: var(--color-primary);
text-decoration: none;
}
a:hover { text-decoration: none; }
img { max-width: 100%; height: auto; }
code, pre { font-family: var(--font-family-mono); font-size: var(--font-size-sm); }
code {
padding: 0.1em 0.35em;
background: var(--color-gray-100);
border-radius: var(--radius-sm);
border: 1px solid var(--color-border);
}
pre {
padding: var(--spacing-md);
background: var(--color-gray-800);
color: var(--color-gray-50);
border-radius: var(--radius);
overflow-x: auto;
}
pre code { padding: 0; background: none; border: none; }
/* ============================================================
AdminLTE Layout - Wrapper + Sidebar + Navbar
============================================================ */
.wrapper {
display: block;
min-height: 100vh;
position: relative;
background: var(--color-bg-alt);
}
/* ---- Navbar ---- */
.main-header.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%;
height: var(--navbar-height);
background: var(--navbar-bg);
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
display: flex;
align-items: center;
padding: 0 0.5rem;
z-index: 1040;
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.navbar-nav {
display: flex;
align-items: center;
list-style: none;
margin: 0;
padding: 0;
}
.navbar-nav.ml-auto { margin-left: auto; }
.navbar-nav .nav-item { position: relative; }
.navbar-nav .nav-link {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0 0.75rem;
height: var(--navbar-height);
color: rgba(255, 255, 255, 0.8);
font-size: var(--font-size-sm);
background: none;
border: none;
cursor: pointer;
text-decoration: none;
transition: color var(--transition-fast), background var(--transition-fast);
white-space: nowrap;
}
.navbar-nav .nav-link:hover {
color: var(--color-on-accent);
background: rgba(255, 255, 255, 0.1);
text-decoration: none;
}
/* Sidebar Toggle Button */
.sidebar-toggle-btn {
font-size: 1.1rem;
padding: 0 1rem !important;
}
.burger-icon {
display: flex;
flex-direction: column;
gap: 5px;
width: 18px;
}
.burger-icon span {
display: block;
width: 18px;
height: 2px;
background: rgba(255,255,255,0.85);
border-radius: 2px;
}
/* Brand in Navbar */
.navbar-brand-item { display: flex; align-items: center; }
.navbar-brand-link {
display: flex;
align-items: center;
padding: 0 0.5rem;
gap: 0.75rem;
color: rgba(255,255,255,0.8);
font-size: 0.875rem;
font-weight: 600;
text-decoration: none;
}
.navbar-brand-link:hover { color: var(--color-on-accent); text-decoration: none; }
.navbar-brand-img { height: 28px; width: auto; }
.navbar-brand-text { color: rgba(255,255,255,0.85); }
/* Navbar Search */
.navbar-search-form { display: flex; align-items: center; padding: 0 0.5rem; }
.navbar-search-wrap {
position: relative;
display: flex;
align-items: center;
}
.navbar-search-icon {
position: absolute;
left: 0.625rem;
font-size: 0.875rem;
color: rgba(255,255,255,0.5);
pointer-events: none;
}
.navbar-search-input {
width: 220px;
padding: 0.35rem 0.75rem 0.35rem 2rem;
background: rgba(255,255,255,0.12);
border: 1px solid rgba(255,255,255,0.2);
border-radius: 20px;
color: var(--color-on-accent);
font-size: var(--font-size-sm);
font-family: inherit;
outline: none;
transition: all var(--transition-fast);
}
.navbar-search-input::placeholder { color: rgba(255,255,255,0.45); }
.navbar-search-input:focus {
background: rgba(255,255,255,0.2);
border-color: rgba(255,255,255,0.4);
width: 260px;
}
/* Navbar Phonebook Quick-Search */
.navbar-phonebook-item { display: flex; align-items: center; padding: 0 0.5rem; }
.navbar-phonebook-wrap {
position: relative;
display: flex;
align-items: center;
}
.navbar-phonebook-icon {
position: absolute;
left: 0.625rem;
font-size: 0.875rem;
color: rgba(255,255,255,0.5);
pointer-events: none;
}
.navbar-phonebook-input {
width: 200px;
padding: 0.35rem 0.75rem 0.35rem 2rem;
background: rgba(255,255,255,0.12);
border: 1px solid rgba(255,255,255,0.2);
border-radius: 20px;
color: var(--color-on-accent);
font-size: var(--font-size-sm);
font-family: inherit;
outline: none;
transition: all var(--transition-fast);
}
.navbar-phonebook-input::placeholder { color: rgba(255,255,255,0.45); }
.navbar-phonebook-input:focus {
background: rgba(255,255,255,0.2);
border-color: rgba(255,255,255,0.4);
width: 240px;
}
/* Navbar Favoriten-Schnellzugriff (gepinnte Services, nur Desktop) */
.navbar-fav-item { display: flex; align-items: center; padding: 0 0.25rem; }
.navbar-fav-wrap { display: flex; align-items: center; gap: 0.2rem; }
.navbar-fav-link {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: var(--border-radius, 6px);
text-decoration: none;
transition: background var(--transition-fast);
}
.navbar-fav-link:hover { background: rgba(255,255,255,0.15); text-decoration: none; }
.navbar-fav-icon { width: 20px; height: 20px; object-fit: contain; display: block; border-radius: 3px; }
.navbar-fav-letter {
width: 22px;
height: 22px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
background: var(--color-primary);
color: var(--color-on-accent);
font-size: 0.7rem;
font-weight: 700;
line-height: 1;
}
/* Nur Desktop: ab Tablet (<= 992px) und Handy ausblenden */
@media (max-width: 992px) {
.navbar-fav-item { display: none !important; }
}
/* User name display */
.user-name { color: rgba(255,255,255,0.85); font-size: var(--font-size-sm); }
.user-caret { font-size: 0.65rem; opacity: 0.7; }
.d-none { display: none !important; }
.d-md-inline { display: none; }
@media (min-width: 768px) { .d-md-inline { display: inline !important; } }
.d-sm-block { display: none !important; }
@media (min-width: 576px) { .d-sm-block { display: block !important; } }
/* ---- Sidebar ---- */
.main-sidebar {
position: fixed;
top: var(--navbar-height);
left: 0;
width: var(--sidebar-width);
height: calc(100vh - var(--navbar-height));
background: var(--sidebar-bg);
z-index: 1035;
overflow-y: auto;
overflow-x: hidden;
transition: width var(--transition), transform var(--transition);
box-shadow: 2px 0 5px rgba(0,0,0,0.15);
}
.main-sidebar::-webkit-scrollbar { width: 4px; }
.main-sidebar::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 2px; }
/* Brand Link */
.brand-link {
display: flex;
align-items: center;
gap: 0.625rem;
padding: 0.9rem 1rem;
border-bottom: 1px solid var(--sidebar-border);
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
background: rgba(0,0,0,0.1);
min-height: var(--navbar-height);
transition: background var(--transition-fast);
}
.brand-link:hover { background: rgba(0,0,0,0.15); text-decoration: none; color: var(--color-on-accent); }
.brand-image {
width: 30px;
height: 30px;
border-radius: var(--radius-sm);
object-fit: contain;
flex-shrink: 0;
}
.brand-icon-placeholder {
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.375rem;
flex-shrink: 0;
}
.brand-text {
font-size: 1rem;
font-weight: 600;
color: var(--color-on-accent);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Sidebar Scrollable Area */
.sidebar {
padding-top: 0.5rem;
padding-bottom: 1rem;
}
/* Sidebar Navigation */
.nav-sidebar {
list-style: none;
margin: 0;
padding: 0;
}
.nav-sidebar .nav-header {
padding: 0.5rem 1rem 0.25rem;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: rgba(255,255,255,0.35);
margin-top: 0.75rem;
pointer-events: none;
}
.nav-sidebar .nav-item { position: relative; }
.nav-sidebar .nav-link {
display: flex;
align-items: center;
gap: 0.625rem;
padding: 0.6rem 0.9rem 0.6rem 1rem;
color: var(--sidebar-text);
text-decoration: none;
font-size: 0.875rem;
font-weight: 400;
transition: background var(--transition-fast), color var(--transition-fast);
border-left: 3px solid transparent;
white-space: nowrap;
overflow: hidden;
}
.nav-sidebar .nav-link:hover {
background: var(--sidebar-hover-bg);
color: var(--color-on-accent);
text-decoration: none;
}
.nav-sidebar .nav-link.active {
background: var(--sidebar-active-bg);
color: var(--color-on-accent);
border-left-color: var(--color-primary);
font-weight: 500;
}
.nav-sidebar .nav-link.active .nav-icon { color: var(--color-primary); }
.nav-sidebar .nav-icon {
width: 1.375rem;
text-align: center;
font-size: 1rem;
flex-shrink: 0;
color: rgba(255,255,255,0.6);
}
.nav-sidebar .nav-link:hover .nav-icon { color: rgba(255,255,255,0.9); }
.nav-sidebar .nav-link p {
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
}
/* Sidebar collapsed (mini) */
body.sidebar-mini .main-sidebar { width: 4rem; }
body.sidebar-mini .nav-sidebar .nav-link p,
body.sidebar-mini .nav-sidebar .nav-header { display: none; }
body.sidebar-mini .content-wrapper { margin-left: 4rem; width: calc(100% - 4rem); }
body.sidebar-mini .main-sidebar:hover {
width: var(--sidebar-width);
}
body.sidebar-mini .main-sidebar:hover .nav-sidebar .nav-link p,
body.sidebar-mini .main-sidebar:hover .nav-sidebar .nav-header { display: block; }
/* Sidebar Collapse Button (at bottom of sidebar, desktop only) */
.sidebar-collapse-btn {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.7rem 1rem;
border-top: 1px solid var(--sidebar-border);
cursor: pointer;
color: rgba(255, 255, 255, 0.4);
font-size: 0.8rem;
transition: background var(--transition-fast), color var(--transition-fast);
user-select: none;
white-space: nowrap;
overflow: hidden;
flex-shrink: 0;
}
.sidebar-collapse-btn:hover {
background: rgba(255, 255, 255, 0.08);
color: rgba(255, 255, 255, 0.85);
}
.sidebar-collapse-icon {
font-size: 1.1rem;
line-height: 1;
flex-shrink: 0;
transition: transform var(--transition);
display: inline-block;
}
.sidebar-collapse-text { font-size: 0.79rem; font-weight: 500; }
body.sidebar-collapsed .sidebar-collapse-icon { transform: rotate(180deg); }
body.sidebar-collapsed .sidebar-collapse-text { display: none; }
body.sidebar-mini .sidebar-collapse-text { display: none; }
/* Responsive display helpers */
.d-lg-none { display: block; }
.d-lg-flex { display: flex; }
@media (min-width: 993px) {
.d-lg-none { display: none !important; }
}
@media (max-width: 992px) {
.d-lg-flex { display: none !important; }
}
/* Sidebar Overlay (mobile) */
.sidebar-overlay {
display: none;
position: fixed;
top: var(--navbar-height);
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1034;
}
.sidebar-overlay.active { display: block; }
/* ---- Content Wrapper ---- */
.content-wrapper {
margin-left: var(--sidebar-width);
width: calc(100% - var(--sidebar-width));
box-sizing: border-box;
padding-top: var(--navbar-height);
min-height: 100vh;
background: var(--color-bg-alt);
display: flex;
flex-direction: column;
transition: margin-left var(--transition), width var(--transition);
}
.main-content {
flex: 1;
padding: var(--spacing-xl);
max-width: var(--max-content-width);
width: 100%;
margin: 0 auto;
}
.main-content-fullwidth { max-width: none; padding: 0; }
/* ---- Footer ---- */
.main-footer {
padding: 0.9rem var(--spacing-xl);
background: var(--color-bg);
border-top: 1px solid var(--color-border);
}
.footer-content {
display: flex;
justify-content: space-between;
align-items: center;
font-size: var(--font-size-sm);
color: var(--color-text-muted);
flex-wrap: wrap;
gap: 0.5rem;
}
.footer-links {
display: flex;
align-items: center;
gap: 0.5rem;
}
.footer-sep {
color: var(--color-border-dark);
user-select: none;
}
.footer-link {
background: none;
border: none;
padding: 0;
color: var(--color-text-muted);
font-size: var(--font-size-sm);
cursor: pointer;
text-decoration: underline;
text-underline-offset: 2px;
}
.footer-link:hover { color: var(--color-primary); }
/* ============================================================
License Modal (Open-Source-Lizenzen)
============================================================ */
.modal-dialog-lg { max-width: 880px; }
/* ---- Hero / Intro ---- */
.license-hero {
background: linear-gradient(135deg, var(--slate-800) 0%, var(--slate-900) 100%);
color: var(--slate-200);
margin: calc(-1 * var(--spacing-lg)) calc(-1 * var(--spacing-lg)) var(--spacing-lg);
padding: 1.25rem 1.5rem 1.35rem;
}
.license-hero-title {
display: flex;
align-items: center;
gap: 0.55rem;
font-size: 0.95rem;
font-weight: 700;
color: var(--color-on-accent);
margin: 0 0 0.4rem;
}
.license-hero-title i { color: var(--color-primary-light); }
.license-lead {
font-size: 0.82rem;
line-height: 1.55;
margin: 0 0 0.85rem;
color: var(--slate-300);
max-width: 60ch;
}
/* Pfadangaben im dunklen Kopfbereich: Die globale code-Auszeichnung bringt
einen hellen Hintergrund mit, erbt hier aber die helle Textfarbe. Deshalb
eigene, auf den dunklen Verlauf abgestimmte Werte. */
.license-hero code {
background: rgba(255, 255, 255, 0.14);
border-color: rgba(255, 255, 255, 0.24);
color: var(--color-on-accent);
}
.license-legend {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
align-items: center;
}
.license-legend-label {
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--slate-400);
margin-right: 0.15rem;
}
/* ---- Sections ---- */
.license-section { margin-bottom: 1.75rem; }
.license-section:last-child { margin-bottom: 0.25rem; }
.license-section-title {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.78rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--color-text);
margin: 0 0 0.85rem;
padding-bottom: 0.45rem;
border-bottom: 2px solid var(--color-gray-200);
}
.license-section-title i { color: var(--color-primary); font-size: 0.85rem; }
.license-count {
margin-left: auto;
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0;
color: var(--color-text-muted);
background: var(--color-gray-100);
border: 1px solid var(--color-border);
border-radius: 999px;
padding: 0.05rem 0.55rem;
}
/* ---- Card grid ---- */
.license-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(370px, 1fr));
gap: 0.75rem;
align-items: start;
}
.license-card {
position: relative;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-left: 3px solid var(--color-gray-300);
border-radius: var(--radius-md);
padding: 0.7rem 0.85rem 0.75rem;
transition: box-shadow var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
}
.license-card:hover {
box-shadow: var(--shadow-md);
transform: translateY(-1px);
}
.license-card--mit { border-left-color: var(--bs-success); }
.license-card--apache { border-left-color: var(--color-primary); }
.license-card--bsd { border-left-color: var(--color-secondary); }
.license-card--lgpl { border-left-color: var(--color-warning); }
.license-card--ofl { border-left-color: var(--pink-600); }
.license-card--gpl { border-left-color: var(--tint-red-text); }
.license-card--multi { border-left-color: var(--violet-500); }
.license-card-top {
display: flex;
align-items: center;
gap: 0.4rem;
flex-wrap: wrap;
margin-bottom: 0.3rem;
}
.license-card-name {
font-size: 0.875rem;
font-weight: 600;
color: var(--color-text);
margin-right: auto;
}
.license-card-name a {
color: inherit;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 0.3rem;
}
.license-card-name a:hover { color: var(--color-primary); }
.license-card-name a .fa-arrow-up-right-from-square,
.license-card-name a .fa-external-link-alt {
font-size: 0.62rem;
opacity: 0.45;
}
.license-card-name a:hover .fa-external-link-alt { opacity: 0.9; }
/* ---- Badges ---- */
.license-badge {
display: inline-block;
font-size: 0.66rem;
font-weight: 700;
padding: 0.12rem 0.5rem;
border-radius: 999px;
white-space: nowrap;
letter-spacing: 0.03em;
border: 1px solid transparent;
}
.badge-mit { background: var(--tint-green-bg); color: var(--tint-green-text); border-color: var(--tint-green-border); }
.badge-apache { background: var(--color-primary-pale); color: var(--color-primary-strong); border-color: var(--color-primary-muted); }
.badge-lgpl { background: var(--tint-amber-bg); color: var(--tint-amber-text); border-color: var(--tint-amber-border); }
.badge-bsd { background: var(--color-gray-100); color: var(--color-gray-700); border-color: var(--color-gray-300); }
.badge-ofl { background: var(--pink-100); color: var(--pink-800); border-color: var(--pink-200); }
.badge-ccby { background: var(--color-primary-pale); color: var(--blue-700); border-color: var(--color-primary-muted); }
.badge-gpl { background: var(--tint-red-bg); color: var(--tint-red-text); border-color: var(--tint-red-border); }
.badge-mpl { background: var(--orange-50); color: var(--amber-800); border-color: var(--orange-200); }
/* ---- Meta tags (version, bundling) ---- */
.license-card-meta {
display: flex;
flex-wrap: wrap;
gap: 0.3rem;
margin-bottom: 0.4rem;
}
.license-tag {
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.66rem;
color: var(--color-text-muted);
background: var(--color-gray-50);
border: 1px solid var(--color-gray-200);
border-radius: var(--radius-sm);
padding: 0.08rem 0.4rem;
}
.license-tag i { font-size: 0.6rem; opacity: 0.7; }
.license-card-desc {
font-size: 0.79rem;
color: var(--color-text-muted);
line-height: 1.5;
margin: 0;
}
.license-card-desc code {
font-size: 0.72rem;
background: var(--color-gray-100);
border-radius: 3px;
padding: 0.05rem 0.25rem;
}
/* ---- Collapsible full license text ---- */
details.license-text { margin-top: 0.5rem; }
details.license-text summary {
cursor: pointer;
font-size: 0.74rem;
font-weight: 600;
color: var(--color-primary);
user-select: none;
list-style: none;
display: inline-flex;
align-items: center;
gap: 0.35rem;
}
details.license-text summary::-webkit-details-marker { display: none; }
details.license-text summary::before {
content: "\f0da"; /* fa caret-right */
font-family: "Font Awesome 6 Free", "Font Awesome 5 Free", sans-serif;
font-weight: 900;
font-size: 0.7rem;
transition: transform var(--transition-fast);
}
details.license-text[open] summary::before { transform: rotate(90deg); }
details.license-text summary:hover { text-decoration: underline; }
details.license-text pre {
font-size: 0.7rem;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
background: var(--color-gray-50);
border: 1px solid var(--color-border);
padding: 0.75rem;
border-radius: var(--radius-sm);
white-space: pre-wrap;
word-break: break-word;
max-height: 200px;
overflow-y: auto;
margin: 0.45rem 0 0;
line-height: 1.5;
color: var(--color-gray-800);
}
/* ---- Footer note ---- */
.license-footer-note {
font-size: 0.76rem;
color: var(--color-text-muted);
background: var(--color-gray-50);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 0.65rem 0.85rem;
margin: 1.5rem 0 0;
line-height: 1.55;
}
.license-footer-note a { color: var(--color-primary); text-decoration: none; }
.license-footer-note a:hover { text-decoration: underline; }
/* Legacy fallback classes (kept for any non-redesigned usage) */
.license-note {
font-size: 0.78rem;
color: var(--color-text-muted);
background: var(--color-gray-50);
border-left: 3px solid var(--color-primary);
padding: 0.5rem 0.75rem;
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
margin-bottom: 1rem;
line-height: 1.5;
}
@media (max-width: 640px) {
.license-grid { grid-template-columns: 1fr; }
}
/* ---- About Modal ---- */
.about-header {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 1.5rem 1.25rem 1rem;
background: linear-gradient(135deg, var(--slate-800) 0%, var(--slate-900) 100%);
color: var(--color-on-accent);
}
.about-app-icon {
font-size: 2.5rem;
line-height: 1;
margin-bottom: 0.5rem;
}
.about-app-name {
font-size: 1.375rem;
font-weight: 700;
letter-spacing: 0.04em;
margin: 0 0 0.2rem;
}
.about-app-version {
font-size: 0.8rem;
opacity: 0.85;
background: rgba(255,255,255,0.15);
padding: 0.15rem 0.6rem;
border-radius: 20px;
}
.about-app-tagline {
font-size: 0.8rem;
opacity: 0.8;
margin-top: 0.5rem;
max-width: 340px;
line-height: 1.4;
}
.about-body {
padding: var(--spacing-lg);
display: flex;
flex-direction: column;
gap: 1.25rem;
overflow-y: auto;
flex: 1;
}
.about-section-title {
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--color-text-muted);
margin: 0 0 0.5rem;
}
.about-row {
display: flex;
align-items: center;
gap: 0.625rem;
font-size: 0.875rem;
color: var(--color-text);
padding: 0.25rem 0;
}
.about-row-icon {
width: 1.25rem;
text-align: center;
flex-shrink: 0;
font-size: 1rem;
}
.about-row a {
color: var(--color-primary);
text-decoration: none;
}
.about-row a:hover { text-decoration: underline; }
.about-divider {
border: none;
border-top: 1px solid var(--color-border);
margin: 0;
}
.about-license-badge {
display: inline-flex;
align-items: center;
gap: 0.375rem;
font-size: 0.78rem;
font-weight: 600;
background: var(--alert-warning-bg);
color: var(--alert-warning-text);
border: 1px solid var(--bs-warning);
padding: 0.25rem 0.625rem;
border-radius: 4px;
text-decoration: none;
}
.about-license-badge:hover { background: var(--alert-warning-border); }
.about-license-text {
font-size: 0.78rem;
color: var(--color-text-muted);
line-height: 1.5;
margin: 0.375rem 0 0;
}
.about-footer-line {
font-size: 0.78rem;
color: var(--color-text-muted);
text-align: center;
padding-top: 0.25rem;
}
.about-actions {
display: flex;
gap: 0.625rem;
justify-content: center;
padding-top: 0.25rem;
}
.btn-report-bug {
display: inline-flex;
align-items: center;
gap: 0.375rem;
background: none;
border: 1px solid var(--color-border);
color: var(--color-text-muted);
font-size: 0.8rem;
padding: 0.4rem 0.875rem;
border-radius: var(--radius-sm);
cursor: pointer;
transition: all var(--transition-fast);
}
.btn-report-bug:hover {
border-color: var(--color-primary);
color: var(--color-primary);
background: var(--color-bg-hover);
}
/* ---- Bug Report Modal ---- */
.bug-report-form { display: flex; flex-direction: column; gap: 0.875rem; }
.bug-report-form label {
display: block;
font-size: 0.8rem;
font-weight: 600;
color: var(--color-text);
margin-bottom: 0.25rem;
}
.bug-report-form label span {
font-weight: 400;
color: var(--color-text-muted);
font-size: 0.75rem;
}
.bug-report-form input,
.bug-report-form textarea,
.bug-report-form select {
width: 100%;
padding: 0.45rem 0.7rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
font-size: 0.875rem;
font-family: inherit;
color: var(--color-text);
background: var(--color-bg);
transition: border-color var(--transition-fast);
}
.bug-report-form input:focus,
.bug-report-form textarea:focus {
outline: none;
border-color: var(--color-primary);
}
.bug-report-form textarea { resize: vertical; min-height: 110px; }
.bug-report-hint {
font-size: 0.75rem;
color: var(--color-text-muted);
line-height: 1.4;
}
.bug-report-actions {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
padding-top: 0.25rem;
}
/* ============================================================
User Menu Dropdown
============================================================ */
.user-menu { position: relative; }
.user-menu-trigger {
background: none;
border: none;
cursor: pointer;
}
.user-avatar {
width: 30px;
height: 30px;
background: var(--color-primary);
color: var(--color-on-accent);
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
font-weight: 700;
flex-shrink: 0;
}
.user-avatar-photo {
object-fit: cover;
background: none;
}
.user-menu-dropdown {
position: absolute;
top: calc(100% + 2px);
right: 0;
min-width: 220px;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-lg);
opacity: 0;
visibility: hidden;
transform: translateY(-8px);
transition: all var(--transition-fast);
z-index: 1050;
}
.user-menu.open .user-menu-dropdown {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.user-menu-header {
padding: 0.75rem 1rem;
border-bottom: 1px solid var(--color-border);
background: var(--color-gray-50);
}
.user-menu-header strong {
display: block;
font-size: var(--font-size-sm);
font-weight: 600;
color: var(--color-text);
}
.user-menu-header small {
display: block;
font-size: var(--font-size-xs);
color: var(--color-text-muted);
margin-top: 2px;
}
.user-menu-dropdown hr {
margin: 0;
border: none;
border-top: 1px solid var(--color-border);
}
.user-menu-dropdown .dropdown-item {
display: block;
padding: 0.5rem 1rem;
font-size: var(--font-size-sm);
color: var(--color-text);
text-decoration: none;
width: 100%;
text-align: left;
background: none;
border: none;
cursor: pointer;
transition: background var(--transition-fast);
font-family: inherit;
}
.user-menu-dropdown .dropdown-item:hover {
background: var(--color-bg-hover);
text-decoration: none;
}
.logout-form { margin: 0; }
.logout-btn { color: var(--color-danger) !important; }
/* ============================================================
Breadcrumbs
============================================================ */
.breadcrumb {
background: none;
padding: 0;
margin: 0 0 var(--spacing-lg);
}
.breadcrumb ol {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.25rem;
list-style: none;
margin: 0;
padding: 0;
font-size: var(--font-size-sm);
color: var(--color-text-muted);
}
.breadcrumb ol li { display: flex; align-items: center; gap: 0.25rem; }
.breadcrumb ol li::before { content: '/'; color: var(--color-gray-400); }
.breadcrumb ol li:first-child::before { display: none; }
.breadcrumb ol li a { color: var(--color-text-muted); }
.breadcrumb ol li a:hover { color: var(--color-primary); }
.breadcrumb ol li[aria-current="page"] { color: var(--color-text); font-weight: 500; }
/* ============================================================
Buttons
============================================================ */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
padding: 0.4375rem 0.875rem;
font-size: var(--font-size-sm);
font-weight: 400;
line-height: 1.5;
border: 1px solid transparent;
border-radius: var(--radius);
cursor: pointer;
transition: all var(--transition-fast);
text-decoration: none;
font-family: inherit;
white-space: nowrap;
vertical-align: middle;
}
.btn:hover { text-decoration: none; }
.btn:disabled { opacity: 0.65; cursor: not-allowed; }
.btn-primary {
background: var(--color-primary);
color: var(--color-on-accent);
border-color: var(--color-primary-dark);
}
.btn-primary:hover { background: var(--color-primary-dark); border-color: var(--color-primary-strong); color: var(--color-on-accent); }
.btn-secondary {
background: var(--color-gray-600);
color: var(--color-on-accent);
border-color: var(--color-secondary-dark);
}
.btn-secondary:hover { background: var(--color-secondary-dark); border-color: var(--color-gray-700); color: var(--color-on-accent); }
.btn-outline-secondary {
background: transparent;
color: var(--color-gray-700);
border-color: var(--color-border);
}
.btn-outline-secondary:hover {
background: var(--color-bg-hover);
color: var(--color-text);
border-color: var(--color-border-dark);
}
.btn-danger {
background: var(--color-danger);
color: var(--color-on-accent);
border-color: var(--color-danger-dark);
}
.btn-danger:hover { background: var(--color-danger-dark); border-color: var(--color-danger-dark); color: var(--color-on-accent); }
/* Dezente Lösch-Aktion: roter Text/Rahmen auf Oberfläche, füllt erst beim Hover leicht */
.btn-outline-danger {
background: var(--color-bg);
color: var(--red-600);
border-color: var(--red-200);
}
.btn-outline-danger:hover { background: var(--red-50); border-color: var(--red-300); color: var(--red-700); }
/* Dezente Bestätigungs-Aktion: grüner Text/Rahmen auf Oberfläche, füllt erst beim Hover leicht */
.btn-outline-success {
background: var(--color-bg);
color: var(--emerald-700);
border-color: var(--emerald-200);
}
.btn-outline-success:hover { background: var(--emerald-50); border-color: var(--emerald-300); color: var(--emerald-800); }
.btn-warning {
background: var(--color-warning);
color: var(--color-on-accent);
border-color: var(--color-warning-dark);
}
.btn-warning:hover { background: var(--color-warning-dark); color: var(--color-on-accent); }
.btn-success {
background: var(--color-success);
color: var(--color-on-accent);
border-color: var(--color-success-dark);
}
.btn-success:hover { background: var(--color-success-dark); color: var(--color-on-accent); }
.btn-info {
background: var(--color-info);
color: var(--color-on-accent);
border-color: var(--color-info-dark);
}
.btn-info:hover { background: var(--color-info-dark); color: var(--color-on-accent); }
.btn-link {
background: none;
color: var(--color-primary);
border-color: transparent;
padding: 0.4375rem 0.5rem;
}
.btn-link:hover { color: var(--color-primary-dark); text-decoration: underline; }
.btn-ghost {
background: none;
color: var(--color-text-muted);
border-color: transparent;
}
.btn-ghost:hover { background: var(--color-bg-hover); color: var(--color-text); }
/* AdminLTE btn-default (alias for btn-secondary outline style) */
.btn-default {
background: var(--color-bg);
color: var(--color-gray-800);
border-color: var(--color-gray-400);
}
.btn-default:hover { background: var(--color-gray-100); border-color: var(--color-gray-500); color: var(--color-gray-800); }
/* btn-outline-primary */
.btn-outline-primary {
background: transparent;
color: var(--color-primary);
border-color: var(--color-primary);
}
.btn-outline-primary:hover { background: var(--color-primary); color: var(--color-on-accent); }
.btn-sm {
padding: 0.25rem 0.5rem;
font-size: 0.8125rem;
border-radius: var(--radius-sm);
}
.btn-xs {
padding: 0.15rem 0.4rem;
font-size: 0.75rem;
border-radius: var(--radius-sm);
}
.btn-lg {
padding: 0.5625rem 1.125rem;
font-size: var(--font-size-base);
}
.btn-icon {
padding: 0.375rem 0.5rem;
min-width: 2rem;
}
.btn-block { width: 100%; }
/* ============================================================
Formulare
============================================================ */
.form-group { margin-bottom: 1.125rem; }
.form-group label {
display: block;
margin-bottom: 0.375rem;
font-size: var(--font-size-sm);
font-weight: 600;
color: var(--color-gray-700);
}
.form-group label.required::after {
content: ' *';
color: var(--color-danger);
}
.form-control {
display: block;
width: 100%;
padding: 0.4375rem 0.75rem;
font-size: var(--font-size-sm);
font-family: inherit;
line-height: 1.6;
color: var(--color-text);
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius);
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
min-height: 2.375rem;
}
.form-control:hover:not(:disabled) { border-color: var(--color-border-dark); }
.form-control:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.2);
}
.form-control:disabled {
background: var(--color-gray-100);
color: var(--color-text-muted);
cursor: not-allowed;
}
textarea.form-control { resize: vertical; min-height: 100px; }
/* Kompakte Eingabefelder, z. B. in Filterleisten und Tabellen */
.form-control-sm {
padding: 0.25rem 0.5rem;
font-size: 0.8125rem;
min-height: 1.9375rem;
border-radius: var(--radius-sm);
}
select.form-control {
appearance: none;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236c757d' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
background-position: right 0.5rem center;
background-repeat: no-repeat;
background-size: 1.2em 1.2em;
padding-right: 2rem;
cursor: pointer;
}
/* .form-text ist das Bootstrap-Pendant zu .form-hint und wird gleich gestylt */
.form-hint,
.form-text {
display: block;
margin-top: 0.25rem;
font-size: var(--font-size-xs);
color: var(--color-text-muted);
}
.form-error {
display: block;
margin-top: 0.25rem;
font-size: var(--font-size-xs);
color: var(--color-danger);
}
/* Alerts / Hinweisboxen */
.alert {
position: relative;
padding: 0.75rem 1rem;
margin-bottom: 1rem;
border: 1px solid transparent;
border-radius: var(--radius-md);
font-size: 0.9rem;
line-height: 1.5;
}
.alert > i,
.alert > .fas,
.alert > .far {
margin-right: 0.4rem;
}
.alert-success {
color: var(--tint-green-text);
background: var(--tint-green-soft-bg);
border-color: var(--tint-green-border);
}
.alert-warning {
color: var(--tint-amber-text);
background: var(--amber-50);
border-color: var(--amber-200);
}
.alert-danger {
color: var(--tint-red-text);
background: var(--tint-red-bg);
border-color: var(--tint-red-border);
}
.alert-info {
color: var(--cyan-800);
background: var(--cyan-50);
border-color: var(--cyan-200);
}
.alert-link {
font-weight: 600;
color: inherit;
text-decoration: underline;
}
/* Checkboxes */
.checkbox-label {
display: flex;
align-items: center;
gap: var(--spacing-sm);
cursor: pointer;
user-select: none;
font-size: var(--font-size-sm);
}
.form-group input[type="checkbox"],
.capability-checkbox input[type="checkbox"],
.settings-toggle input[type="checkbox"],
.checkbox-label input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
width: 1rem;
height: 1rem;
border: 1px solid var(--color-border-dark);
border-radius: 0.2rem;
background: var(--color-bg);
cursor: pointer;
position: relative;
flex-shrink: 0;
transition: background var(--transition-fast), border-color var(--transition-fast);
vertical-align: middle;
}
.form-group input[type="checkbox"]:hover,
.capability-checkbox input[type="checkbox"]:hover,
.settings-toggle input[type="checkbox"]:hover,
.checkbox-label input[type="checkbox"]:hover { border-color: var(--color-primary); }
.form-group input[type="checkbox"]:checked,
.capability-checkbox input[type="checkbox"]:checked,
.settings-toggle input[type="checkbox"]:checked,
.checkbox-label input[type="checkbox"]:checked {
background: var(--color-primary);
border-color: var(--color-primary);
}
.form-group input[type="checkbox"]:checked::after,
.capability-checkbox input[type="checkbox"]:checked::after,
.settings-toggle input[type="checkbox"]:checked::after,
.checkbox-label input[type="checkbox"]:checked::after {
content: '';
position: absolute;
left: 3px;
top: 0px;
width: 5px;
height: 9px;
border: 2px solid var(--color-on-accent);
border-top: none;
border-left: none;
transform: rotate(45deg);
}
.form-group input[type="checkbox"]:indeterminate,
.capability-checkbox input[type="checkbox"]:indeterminate {
background: var(--color-primary);
border-color: var(--color-primary);
}
.form-group input[type="checkbox"]:indeterminate::after,
.capability-checkbox input[type="checkbox"]:indeterminate::after {
content: '';
position: absolute;
left: 2px;
top: 5px;
width: 8px;
height: 2px;
background: var(--color-bg);
border: none;
transform: none;
}
.form-group input[type="checkbox"]:focus,
.capability-checkbox input[type="checkbox"]:focus,
.settings-toggle input[type="checkbox"]:focus,
.checkbox-label input[type="checkbox"]:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.2);
}
/* Zweispaltige Formularzeile – generisch, damit sie auch außerhalb des
Admin-Layouts (das eigene admin.css) im Frontend greift. */
.form-row-2,
.form-row-2-inner {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
@media (max-width: 640px) {
.form-row-2,
.form-row-2-inner { grid-template-columns: 1fr; }
}
/* Rückweg über einer Bearbeitungsseite. */
.page-back-nav { margin-bottom: 1rem; }
/* Aktionsleiste am Fuß eines Formulars; ein Element mit `margin-left:auto`
rückt darin nach rechts. */
.form-actions-bar {
display: flex;
gap: 0.75rem;
align-items: center;
flex-wrap: wrap;
margin-top: 1rem;
}
/* Beschriftung mit vorangestelltem Kontrollkästchen auf einer Zeile. */
.checkbox-inline {
display: inline-flex;
align-items: center;
gap: 0.4rem;
cursor: pointer;
}
/* Vertikaler Container für mehrere .settings-toggle (Umschalter-Liste). */
.settings-toggles {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
/* Umschalter-Zeile: Checkbox + zweizeiliger Text (fett + Hinweis). Generisch,
damit sie auch außerhalb des Admin-Layouts im Frontend greift. */
.settings-toggle {
display: flex;
align-items: flex-start;
gap: 0.5rem;
cursor: pointer;
}
.settings-toggle input[type="checkbox"] { margin-top: 0.2em; }
.settings-toggle .toggle-text strong {
display: block;
font-size: var(--font-size-sm);
}
.settings-toggle .toggle-text small {
display: block;
color: var(--color-text-muted);
font-size: var(--font-size-xs);
}
/* ============================================================
Tabellen
============================================================ */
.table-wrapper {
overflow-x: auto;
background: var(--color-bg);
border-radius: var(--radius);
border: 1px solid var(--color-border);
}
.data-table {
width: 100%;
border-collapse: collapse;
font-size: var(--font-size-sm);
margin: 0;
}
.data-table th,
.data-table td {
padding: 0.625rem 0.875rem;
text-align: left;
border-bottom: 1px solid var(--color-border);
vertical-align: middle;
}
.data-table th {
background: var(--color-gray-50);
font-weight: 600;
color: var(--color-gray-700);
font-size: 0.8125rem;
text-transform: uppercase;
letter-spacing: 0.03em;
white-space: nowrap;
border-bottom: 2px solid var(--color-border);
}
.data-table tbody tr:hover { background: var(--color-gray-100); }
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table .actions-col { width: 1%; white-space: nowrap; }
.data-table-compact th,
.data-table-compact td { padding: 0.375rem 0.625rem; }
.inactive-row { opacity: 0.55; }
.text-right { text-align: right; }
/* Rechtsbündige Spalten (z. B. Beträge) auch innerhalb von .data-table */
.data-table th.text-right,
.data-table td.text-right { text-align: right; }
.nowrap { white-space: nowrap; }
/* ============================================================
Wiederverwendbare UI-Komponenten (Styleguide)
Kanonische Klassen für alle Module – NICHT pro Modul unter
eigenem Präfix neu definieren (siehe STYLEGUIDE.md).
============================================================ */
/* Exakter Zeitpunkt neben einer relativen Zeitangabe
(„vor 2 Tagen · 27.08.2026, 14:32", siehe View::relativeTimeWithDate) */
.time-abs { font-size: 0.92em; opacity: 0.85; white-space: nowrap; }
/* Seiten-Body unterhalb des Content-Headers */
.page-body { padding: 1.25rem 1rem 3rem; background: var(--color-gray-50, var(--gray-50)); flex: 1; }
@media (max-width: 768px) { .page-body { padding: 1rem 0.75rem 2rem; } }
/* Klickbare Tabellenzeilen (data-href via JS) */
.data-table tbody tr.clickable { cursor: pointer; }
/* Tabelle scrollt auf kleinen Screens horizontal statt zu quetschen.
Schmale Tabellen können mit .data-table--fluid aussteigen. */
@media (max-width: 768px) { .table-wrapper .data-table { min-width: 640px; } }
.table-wrapper .data-table--fluid { min-width: 0 !important; }
/* Empty-State innerhalb eines Tabellen-Wrappers: kein Doppelrahmen */
.table-wrapper .empty-state { border: none; background: transparent; }
/* KPI-Zeile: kompakte small-boxes, beliebig viele nebeneinander.
Boxen einer Zeile sind immer gleich hoch (flex-stretch) – leere
Footer als Höhen-Füller sind nicht nötig. */
.kpi-row { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 0.75rem; }
.kpi-col { flex: 1 1 160px; display: flex; }
.kpi-col > a { flex: 1; display: flex; text-decoration: none; }
.kpi-row .small-box { flex: 1; margin-bottom: 0; display: flex; flex-direction: column; }
.kpi-row .small-box > .inner { padding: 7px 10px; flex: 1; }
.kpi-row .small-box h3 { font-size: 1.6rem; margin-bottom: 4px; }
.kpi-row .small-box p { font-size: 0.85rem; }
.kpi-row .small-box > .small-box-footer { margin-top: auto; }
/* Status-Pills (semantische Varianten; Farben als Variablen für Theming) */
:root {
--pill-success-bg: var(--emerald-100); --pill-success-fg: var(--emerald-800);
--pill-info-bg: var(--blue-100); --pill-info-fg: var(--blue-800);
--pill-warning-bg: var(--amber-100); --pill-warning-fg: var(--amber-800);
--pill-caution-bg: var(--yellow-50); --pill-caution-fg: var(--yellow-600);
--pill-orange-bg: var(--orange-100); --pill-orange-fg: var(--orange-700);
--pill-danger-bg: var(--red-100); --pill-danger-fg: var(--red-700);
--pill-neutral-bg: var(--gray-100); --pill-neutral-fg: var(--gray-500);
--pill-purple-bg: var(--violet-100); --pill-purple-fg: var(--violet-800);
}
.status-pill {
display: inline-flex; align-items: center; gap: 0.3rem;
padding: 0.2rem 0.6rem; border-radius: 9999px;
font-size: 0.75rem; font-weight: 600; white-space: nowrap;
}
.status-pill--success { background: var(--pill-success-bg); color: var(--pill-success-fg); }
.status-pill--info { background: var(--pill-info-bg); color: var(--pill-info-fg); }
.status-pill--warning { background: var(--pill-warning-bg); color: var(--pill-warning-fg); }
.status-pill--caution { background: var(--pill-caution-bg); color: var(--pill-caution-fg); }
.status-pill--orange { background: var(--pill-orange-bg); color: var(--pill-orange-fg); }
.status-pill--danger { background: var(--pill-danger-bg); color: var(--pill-danger-fg); }
.status-pill--neutral { background: var(--pill-neutral-bg); color: var(--pill-neutral-fg); }
.status-pill--purple { background: var(--pill-purple-bg); color: var(--pill-purple-fg); }
.pill-row { display: flex; gap: 0.3rem; flex-wrap: wrap; align-items: center; }
/* Links in Tabellenzellen (statt Inline-Farben) */
.table-link { color: var(--color-primary, var(--color-primary)); font-weight: 600; text-decoration: none; }
.table-link:hover { color: var(--color-primary-dark, var(--color-primary-dark)); text-decoration: none; }
/* Einheitliche Button-Größe im Seitenkopf – egal ob btn oder btn-sm gesetzt ist */
.content-header-actions .btn {
padding: 0.45rem 0.875rem;
font-size: 0.85rem;
display: inline-flex; align-items: center; gap: 0.4rem;
}
/* Sub-Navigation (Tab-Leiste innerhalb einer Seite, z. B. VMs/Hosts/Cluster) */
.subnav { display: flex; gap: 0.375rem; margin-bottom: 1.25rem; flex-wrap: wrap; }
.subnav-tab {
display: inline-flex; align-items: center; gap: 0.4rem;
padding: 0.45rem 1.1rem; border-radius: 0.3rem; font-size: 0.85rem; font-weight: 600;
background: var(--color-bg); border: 1px solid var(--color-border, var(--gray-200));
color: var(--color-gray-600, var(--color-gray-700)); text-decoration: none; white-space: nowrap;
}
.subnav-tab:hover { background: var(--gray-100); color: var(--color-gray-900); text-decoration: none; }
.subnav-tab.active { background: var(--color-primary, var(--color-primary)); color: var(--color-on-accent); border-color: var(--color-primary, var(--color-primary)); }
/* Standard-Modal (Overlay + Karte; Sichtbarkeit via Inline-Style oder .open) */
.modal-overlay {
position: fixed; inset: 0;
background: rgba(0,0,0,0.5);
display: flex; align-items: center; justify-content: center;
/* Modals liegen über der fixierten Kopfleiste (z-index 1040) und den
Dropdowns (1050) – gleiche Ebene wie .modal. */
z-index: 1055; padding: 2rem;
}
.modal-card {
background: var(--color-bg);
border-radius: 0.25rem;
box-shadow: 0 4px 16px rgba(0,0,0,0.2);
width: 100%; max-width: 560px;
max-height: 90vh; overflow-y: auto;
position: relative;
}
.modal-header {
display: flex; justify-content: space-between; align-items: center;
padding: 1.25rem 1.5rem;
border-bottom: 1px solid var(--color-border, var(--gray-200));
}
.modal-header h2 { font-size: 1.1rem; font-weight: 600; margin: 0; color: var(--gray-900); }
.modal-close {
background: none; border: none; font-size: 1.5rem; color: var(--gray-400);
cursor: pointer; width: 32px; height: 32px; display: flex;
align-items: center; justify-content: center; border-radius: 0.25rem;
}
.modal-close:hover { background: var(--gray-100); color: var(--gray-700); }
.modal-body { padding: 1.5rem; }
.modal-footer {
padding: 1rem 1.5rem;
border-top: 1px solid var(--color-border, var(--gray-200));
display: flex; justify-content: flex-end; gap: 0.75rem;
}
/* Status-Dot (Ampelpunkt, optional pulsierend) */
.status-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--color-gray-300, var(--gray-300)); }
.status-dot--success { background: var(--emerald-500); }
.status-dot--warning { background: var(--amber-500); }
.status-dot--danger { background: var(--red-500); }
.status-dot--pulse { animation: status-dot-pulse 1.5s infinite; }
@keyframes status-dot-pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.5); }
50% { box-shadow: 0 0 0 5px rgba(239, 68, 68, 0); }
}
/* Wartezeiger – in Schaltflächen und neben Beschriftungen, die auf eine
Antwort warten. Erbt die Schriftfarbe, passt damit auf jede Fläche. */
.spinner {
display: inline-block; width: 0.85em; height: 0.85em;
border: 2px solid currentColor; border-right-color: transparent;
border-radius: 50%; vertical-align: -0.1em;
animation: spinner-dreh 0.7s linear infinite;
}
@keyframes spinner-dreh { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
.spinner { animation-duration: 2.4s; }
}
/* Detail-Karte (Haupt- und Sidebar-Karten auf Detailseiten) */
.detail-card {
background: var(--color-bg);
border: 1px solid var(--color-border, var(--gray-200));
border-radius: 0.25rem;
margin-bottom: 1.25rem;
overflow: hidden;
}
.detail-card:last-child { margin-bottom: 0; }
.detail-card-header {
padding: 1rem 1.25rem;
border-bottom: 1px solid var(--gray-100);
display: flex; align-items: center; justify-content: space-between;
}
.detail-card-title {
font-size: 0.8rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--gray-400);
}
.detail-card-body { padding: 1.25rem; }
@media (max-width: 480px) {
.detail-card-header { padding: 0.75rem 1rem; }
.detail-card-body { padding: 0.875rem; }
}
/* ============================================================
Zeitleiste (Verläufe, Lebensläufe, Aktivitäten)
Senkrechte Schiene mit Punkten; ein Eintrag besteht aus Kopf
(Titel, Urheber, Zeitpunkt) und optionalen Zusatzzeilen.
============================================================ */
.timeline { position: relative; margin: 0; padding: 0 0 0 1.75rem; list-style: none; }
.timeline::before {
content: '';
position: absolute;
left: 0.6rem; top: 0.55rem; bottom: 0.55rem;
width: 2px;
background: var(--gray-200);
}
.timeline-item { position: relative; padding: 0 0 1.1rem 0; }
.timeline-item:last-child { padding-bottom: 0; }
/* Der Punkt sitzt auf der Schiene und trägt das Symbol des Eintrags. */
.timeline-dot {
position: absolute;
left: -1.75rem; top: 0.05rem;
width: 1.5rem; height: 1.5rem;
border-radius: 9999px;
display: flex; align-items: center; justify-content: center;
font-size: 0.62rem;
background: var(--gray-100);
color: var(--gray-500);
box-shadow: 0 0 0 3px var(--color-bg);
}
.timeline-dot.is-info { background: var(--blue-100); color: var(--blue-700); }
.timeline-dot.is-ok { background: var(--emerald-100); color: var(--emerald-700); }
.timeline-dot.is-warn { background: var(--amber-100); color: var(--amber-800); }
.timeline-dot.is-danger { background: var(--red-100); color: var(--red-700); }
.timeline-head {
display: flex; align-items: baseline; gap: 0.5rem;
flex-wrap: wrap;
min-height: 1.5rem;
}
.timeline-title { font-size: 0.85rem; font-weight: 650; color: var(--gray-900); }
a.timeline-title { color: var(--color-primary); }
a.timeline-title:hover { text-decoration: underline; }
.timeline-actor { font-size: 0.76rem; color: var(--gray-500); }
.timeline-time {
margin-left: auto;
font-size: 0.73rem;
color: var(--gray-400);
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
.timeline-detail { font-size: 0.78rem; color: var(--gray-500); margin-top: 0.15rem; }
/* Wertänderungen: je Zeile Feld, alter und neuer Wert. */
.timeline-changes {
margin-top: 0.4rem;
display: flex; flex-direction: column; gap: 1px;
border: 1px solid var(--gray-100);
border-radius: 0.25rem;
overflow: hidden;
}
.timeline-change {
display: flex; align-items: baseline; gap: 0.5rem;
flex-wrap: wrap;
padding: 0.3rem 0.55rem;
font-size: 0.76rem;
background: var(--gray-50);
line-height: 1.45;
}
.timeline-change-field {
flex: 0 0 auto;
min-width: 7.5rem;
font-weight: 600;
color: var(--gray-500);
}
.timeline-change-from { color: var(--gray-400); text-decoration: line-through; }
.timeline-change-arrow { color: var(--gray-300); }
.timeline-change-to { color: var(--gray-900); font-weight: 600; }
.timeline-change-empty { color: var(--gray-300); font-style: italic; }
/* Filterleiste über einer Zeitleiste. */
.timeline-filter { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.timeline-filter-btn {
display: inline-flex; align-items: center; gap: 0.35rem;
padding: 0.28rem 0.7rem;
font-size: 0.75rem; font-weight: 600;
color: var(--gray-500);
background: var(--color-bg);
border: 1px solid var(--gray-200);
border-radius: 9999px;
cursor: pointer;
transition: color 0.12s, border-color 0.12s, background 0.12s;
}
.timeline-filter-btn:hover { color: var(--gray-700); background: var(--gray-50); }
.timeline-filter-btn.active {
color: var(--color-primary);
border-color: var(--color-primary);
background: var(--blue-50);
}
.timeline-filter-count { font-size: 0.68rem; color: var(--gray-400); font-variant-numeric: tabular-nums; }
.timeline-filter-btn.active .timeline-filter-count { color: var(--color-primary); }
.timeline-item.is-hidden { display: none; }
@media (max-width: 560px) {
.timeline-time { margin-left: 0; flex-basis: 100%; }
.timeline-change-field { min-width: 0; flex-basis: 100%; }
}
/* ============================================================
Badges
============================================================ */
.badge {
display: inline-flex;
align-items: center;
padding: 0.2em 0.6em;
font-size: 0.75em;
font-weight: 600;
border-radius: 10rem;
line-height: 1;
white-space: nowrap;
}
.badge-success { background: var(--alert-success-bg); color: var(--alert-success-text); border: 1px solid var(--alert-success-border); }
.badge-warning { background: var(--alert-warning-bg); color: var(--alert-warning-text); border: 1px solid var(--alert-warning-border); }
.badge-danger { background: var(--alert-danger-bg); color: var(--alert-danger-text); border: 1px solid var(--alert-danger-border); }
.badge-info { background: var(--alert-info-bg); color: var(--alert-info-text); border: 1px solid var(--alert-info-border); }
.badge-admin { background: var(--color-primary); color: var(--color-on-accent); border: 1px solid var(--color-primary-dark); }
.badge-role { background: var(--color-gray-200); color: var(--color-gray-700); border: 1px solid var(--color-gray-300); }
.badge-secondary { background: var(--color-gray-200); color: var(--color-gray-600); border: 1px solid var(--color-gray-300); }
/* Datensatz, den ein fremdes System führt (MDM, Verzeichnis, Abgleich). */
.badge-managed { background: var(--alert-info-bg); color: var(--alert-info-text); border: 1px solid var(--alert-info-border); gap: 0.3em; vertical-align: middle; }
/* Severity */
.severity-badge {
padding: 0.2em 0.6em;
border-radius: var(--radius-sm);
font-size: 0.75rem;
font-weight: 600;
}
.severity-critical { background: var(--alert-danger-bg); color: var(--alert-danger-text); }
.severity-high { background: var(--tint-orange-bg); color: var(--tint-orange-text); }
.severity-medium { background: var(--alert-warning-bg); color: var(--alert-warning-text); }
.severity-low { background: var(--alert-info-bg); color: var(--alert-info-text); }
/* Action Badges */
.action-badge {
padding: 0.2em 0.5em;
border-radius: var(--radius-sm);
font-size: 0.75rem;
font-weight: 500;
}
.category-auth { background: var(--alert-info-bg); color: var(--alert-info-text); }
.category-content { background: var(--alert-success-bg); color: var(--alert-success-text); }
.category-admin { background: var(--tint-purple-bg); color: var(--tint-purple-text); }
.category-system { background: var(--color-gray-200); color: var(--color-gray-700); }
.category-permission { background: var(--tint-orange-bg); color: var(--tint-orange-text); }
.category-security { background: var(--alert-danger-bg); color: var(--alert-danger-text); }
.category-file { background: var(--alert-warning-bg); color: var(--alert-warning-text); }
.category-files { background: var(--alert-warning-bg); color: var(--alert-warning-text); }
.category-export { background: var(--alert-primary-bg); color: var(--alert-primary-text); }
.category-contact { background: var(--green-100); color: var(--green-800); }
.category-order { background: var(--orange-100); color: var(--orange-800); }
.category-service { background: var(--blue-100); color: var(--color-primary-deep); }
.category-asset { background: var(--color-primary-pale); color: var(--tint-blue-text); }
.category-assets { background: var(--color-primary-pale); color: var(--tint-blue-text); }
.category-tickets { background: var(--tint-yellow-bg); color: var(--tint-yellow-text); }
.category-vault { background: var(--tint-purple-soft-bg); color: var(--tint-purple-deep-text); }
.category-ipam { background: var(--tint-green-pale-bg); color: var(--tint-green-deep-text); }
.category-ssl { background: var(--tint-red-pale-bg); color: var(--tint-red-deep-text); }
.category-kanban { background: var(--amber-50); color: var(--yellow-600); }
.category-ai_chat { background: var(--blue-50); color: var(--color-primary-deep); }
.category-contract { background: var(--tint-purple-soft-bg); color: var(--tint-purple-deep-text); }
.category-loan { background: var(--color-bg); color: var(--gray-600); }
.category-stock { background: var(--tint-green-soft-bg); color: var(--tint-green-deep-text); }
.category-monitoring { background: var(--tint-yellow-bg); color: var(--tint-yellow-text); }
.category-cve { background: var(--tint-red-pale-bg); color: var(--tint-red-deep-text); }
/* ============================================================
Flash Messages / Alerts
============================================================ */
.flash-messages { margin-bottom: var(--spacing-lg); }
.flash-message {
padding: 0.875rem 1.125rem;
border-radius: var(--radius);
margin-bottom: 0.5rem;
border: 1px solid transparent;
font-size: var(--font-size-sm);
display: flex;
align-items: flex-start;
gap: 0.5rem;
}
.flash-success { background: var(--alert-success-bg); color: var(--alert-success-text); border-color: var(--alert-success-border); }
.flash-error { background: var(--alert-danger-bg); color: var(--alert-danger-text); border-color: var(--alert-danger-border); }
.flash-warning { background: var(--alert-warning-bg); color: var(--alert-warning-text); border-color: var(--alert-warning-border); }
.flash-info { background: var(--alert-info-bg); color: var(--alert-info-text); border-color: var(--alert-info-border); }
/* ============================================================
Cards
============================================================ */
.card {
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius);
box-shadow: var(--shadow-sm);
margin-bottom: var(--spacing-lg);
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.75rem 1.125rem;
background: var(--color-gray-50);
border-bottom: 1px solid var(--color-border);
border-radius: var(--radius) var(--radius) 0 0;
}
.card-title {
margin: 0;
font-size: var(--font-size-base);
font-weight: 600;
color: var(--color-gray-800);
}
.card > .card-header + * { border-radius: 0 0 var(--radius) var(--radius); }
.card > :not(.card-header):first-child { border-radius: var(--radius) var(--radius) 0 0; }
/* Card padding helper */
.card-body { padding: var(--spacing-lg); }
.card-body .card-header { margin: calc(-1 * var(--spacing-lg)) calc(-1 * var(--spacing-lg)) var(--spacing-lg); }
/* When card has just padding */
.card:not(:has(.card-header)) { padding: var(--spacing-lg); }
.card:has(.card-header) > *:not(.card-header) { padding: var(--spacing-lg); }
/* AdminLTE card-outline variants */
.card-outline { box-shadow: none; }
.card-outline.card-primary { border-top: 3px solid var(--color-primary); }
.card-outline.card-success { border-top: 3px solid var(--color-success); }
.card-outline.card-warning { border-top: 3px solid var(--color-warning); }
.card-outline.card-danger { border-top: 3px solid var(--color-danger); }
/* Colored card headers */
.card-header.bg-primary { background: var(--color-primary); color: var(--color-on-accent); border-color: var(--color-primary-dark); }
.card-header.bg-success { background: var(--color-success); color: var(--color-on-accent); border-color: var(--color-success-dark); }
.card-header.bg-warning { background: var(--color-warning); color: var(--color-on-accent); border-color: var(--color-warning-dark); }
.card-header.bg-danger { background: var(--color-danger); color: var(--color-on-accent); border-color: var(--color-danger-dark); }
.card-header.bg-info { background: var(--color-info); color: var(--color-on-accent); border-color: var(--color-info-dark); }
/* ============================================================
Empty State
============================================================ */
.empty-state {
text-align: center;
padding: var(--spacing-2xl) var(--spacing-xl);
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius);
}
.empty-icon { font-size: 3.5rem; margin-bottom: var(--spacing-md); opacity: 0.45; }
.empty-state h2 { margin-bottom: var(--spacing-sm); color: var(--color-gray-700); }
.empty-state p { color: var(--color-text-muted); margin-bottom: var(--spacing-lg); }
/* ============================================================
Pagination
============================================================ */
.pagination {
display: flex;
align-items: center;
justify-content: center;
gap: 0.2rem;
margin-top: var(--spacing-lg);
flex-wrap: wrap;
}
.pagination-link {
display: flex;
align-items: center;
justify-content: center;
min-width: 2rem;
height: 2rem;
padding: 0 0.5rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
font-size: var(--font-size-sm);
color: var(--color-primary);
background: var(--color-bg);
transition: all var(--transition-fast);
}
.pagination-link:hover {
background: var(--color-primary);
color: var(--color-on-accent);
border-color: var(--color-primary);
text-decoration: none;
}
.pagination-link.active {
background: var(--color-primary);
color: var(--color-on-accent);
border-color: var(--color-primary);
font-weight: 600;
}
.pagination-link.disabled { opacity: 0.5; pointer-events: none; color: var(--color-text-muted); }
/* ============================================================
Modals
============================================================ */
.modal {
position: fixed;
inset: 0;
z-index: 1055;
display: flex;
align-items: center;
justify-content: center;
}
.modal[hidden] { display: none; }
.modal-backdrop {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.5);
}
.modal-dialog {
position: relative;
background: var(--color-bg);
border-radius: var(--radius-md);
box-shadow: 0 10px 40px rgba(0,0,0,0.25);
max-width: 600px;
width: 90%;
max-height: 90vh;
overflow: hidden;
display: flex;
flex-direction: column;
border: 1px solid var(--color-border);
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 1.25rem;
border-bottom: 1px solid var(--color-border);
background: var(--color-gray-50);
}
.modal-header h3 { margin: 0; font-size: var(--font-size-lg); }
.modal-close {
background: none;
border: none;
font-size: 1.375rem;
cursor: pointer;
color: var(--color-text-muted);
padding: 0;
line-height: 1;
transition: color var(--transition-fast);
}
.modal-close:hover { color: var(--color-text); }
.modal-body { padding: var(--spacing-lg); overflow-y: auto; }
/* ============================================================
Dropdown
============================================================ */
.dropdown { position: relative; display: inline-block; }
.dropdown-menu {
position: absolute;
top: 100%;
right: 0;
min-width: 200px;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius);
box-shadow: var(--shadow-md);
z-index: 1000;
display: none;
padding: 0.25rem 0;
}
.dropdown.open .dropdown-menu { display: block; }
.dropdown-item {
display: block;
padding: 0.4375rem 1rem;
color: var(--color-text);
font-size: var(--font-size-sm);
transition: background var(--transition-fast);
}
.dropdown-item:hover { background: var(--color-bg-hover); text-decoration: none; }
.dropdown-divider {
margin: 0.25rem 0;
border: none;
border-top: 1px solid var(--color-border);
}
/* ============================================================
Notification Bell
============================================================ */
.notif-bell { position: relative; }
.notif-bell-btn {
position: relative;
}
.notif-bell-icon { font-size: 1.1rem; }
.notif-badge {
position: absolute;
top: 10px;
right: 6px;
min-width: 16px;
height: 16px;
padding: 0 4px;
background: var(--color-danger);
color: var(--color-on-accent);
font-size: 0.65rem;
font-weight: 700;
border-radius: 9999px;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
pointer-events: none;
border: 2px solid var(--navbar-bg);
}
.notif-dropdown {
display: none;
position: absolute;
top: calc(100% + 2px);
right: 0;
width: 360px;
max-height: 460px;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-lg);
z-index: 1050;
overflow: hidden;
}
.notif-dropdown.open { display: block; }
.notif-dropdown-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.625rem 0.875rem;
border-bottom: 1px solid var(--color-border);
background: var(--color-gray-50);
}
.notif-dropdown-header strong { font-size: 0.875rem; }
.notif-header-actions { display: flex; gap: 0.25rem; }
.notif-mark-all, .notif-delete-read {
background: none;
border: none;
color: var(--color-primary);
font-size: 0.7rem;
cursor: pointer;
padding: 0.2rem 0.375rem;
border-radius: var(--radius-sm);
transition: background var(--transition-fast);
white-space: nowrap;
}
.notif-mark-all:hover { background: var(--color-primary-pale); }
.notif-delete-read { color: var(--color-danger); }
.notif-delete-read:hover { background: var(--tint-red-soft-bg); }
.notif-push-toggle { background: none; border: none; color: var(--color-secondary); font-size: 0.7rem; cursor: pointer; padding: 0.2rem 0.375rem; border-radius: var(--radius-sm); transition: background var(--transition-fast), color var(--transition-fast); white-space: nowrap; }
.notif-push-toggle:hover { background: var(--color-gray-100); }
.notif-push-toggle.push-active { color: var(--color-primary); }
.notif-dropdown-body { max-height: 380px; overflow-y: auto; }
.notif-item {
display: flex;
gap: 0.625rem;
padding: 0.625rem 0.875rem;
border-bottom: 1px solid var(--color-gray-50);
cursor: pointer;
transition: background var(--transition-fast);
}
.notif-item:hover { background: var(--color-gray-50); }
.notif-item.unread { background: var(--blue-50); }
.notif-item.unread:hover { background: var(--sky-100); }
.notif-item-icon {
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.875rem;
flex-shrink: 0;
}
.notif-item-icon.type-page_changed { background: var(--alert-info-bg); color: var(--alert-info-text); }
.notif-item-icon.type-review_due { background: var(--alert-warning-bg); color: var(--alert-warning-text); }
.notif-item-icon.type-info { background: var(--tint-purple-bg); color: var(--tint-purple-text); }
.notif-item-content { flex: 1; min-width: 0; }
.notif-item-title {
font-size: 0.8rem;
font-weight: 600;
color: var(--color-gray-900);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.notif-item-message {
font-size: 0.75rem;
color: var(--color-text-muted);
line-height: 1.35;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.notif-item-time { font-size: 0.65rem; color: var(--color-gray-400); margin-top: 0.2rem; }
.notif-empty {
padding: 2rem 1rem;
text-align: center;
color: var(--color-text-muted);
font-size: var(--font-size-sm);
}
.notif-delete-btn {
background: none;
border: none;
color: var(--color-gray-400);
font-size: 1rem;
cursor: pointer;
padding: 0 0.2rem;
flex-shrink: 0;
border-radius: var(--radius-sm);
opacity: 0;
transition: opacity var(--transition-fast), color var(--transition-fast);
}
.notif-item:hover .notif-delete-btn { opacity: 1; }
.notif-delete-btn:hover { color: var(--color-danger); background: var(--tint-red-soft-bg); }
/* ============================================================
Utilities
============================================================ */
.text-muted { color: var(--color-text-muted) !important; }
.text-danger { color: var(--color-danger) !important; }
.text-success { color: var(--color-success) !important; }
.text-warning { color: var(--color-warning) !important; }
.text-info { color: var(--color-info) !important; }
.text-primary { color: var(--color-primary) !important; }
.inline-form { display: inline; }
.action-buttons {
display: flex;
gap: var(--spacing-xs);
align-items: center;
}
.result-count {
margin-top: var(--spacing-md);
font-size: var(--font-size-sm);
color: var(--color-text-muted);
text-align: center;
}
.hash {
font-family: var(--font-family-mono);
font-size: var(--font-size-xs);
word-break: break-all;
}
/* ============================================================
Toast Notifications
============================================================ */
.toast-container {
position: fixed;
top: calc(var(--navbar-height) + 0.75rem);
right: 1rem;
z-index: 9999;
display: flex;
flex-direction: column;
gap: 0.625rem;
max-width: 380px;
pointer-events: none;
}
.toast {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 0.875rem 1rem;
background: var(--color-bg);
border-radius: var(--radius-md);
box-shadow: 0 4px 16px rgba(0,0,0,0.12), 0 2px 6px rgba(0,0,0,0.08);
border-left: 4px solid var(--color-gray-400);
pointer-events: auto;
animation: toastSlideIn 0.25s ease-out;
transition: all 0.25s ease;
}
.toast.toast-hiding { animation: toastSlideOut 0.25s ease-in forwards; }
@keyframes toastSlideIn {
from { opacity: 0; transform: translateX(100%); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes toastSlideOut {
from { opacity: 1; transform: translateX(0); }
to { opacity: 0; transform: translateX(100%); }
}
.toast-success { border-left-color: var(--color-success); }
.toast-success .toast-icon { background: var(--color-success); color: var(--color-on-accent); }
.toast-error { border-left-color: var(--color-danger); }
.toast-error .toast-icon { background: var(--color-danger); color: var(--color-on-accent); }
.toast-warning { border-left-color: var(--color-warning); }
.toast-warning .toast-icon { background: var(--color-warning); color: var(--color-on-accent); }
.toast-info { border-left-color: var(--color-info); }
.toast-info .toast-icon { background: var(--color-info); color: var(--color-on-accent); }
.toast-icon {
display: flex;
align-items: center;
justify-content: center;
width: 26px;
height: 26px;
min-width: 26px;
border-radius: 50%;
font-size: 0.8rem;
font-weight: 700;
}
.toast-content { flex: 1; min-width: 0; }
.toast-message { font-size: var(--font-size-sm); font-weight: 500; color: var(--color-gray-900); line-height: 1.4; }
.toast-close {
display: flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
background: transparent;
border: none;
border-radius: var(--radius-sm);
font-size: 1.1rem;
color: var(--color-gray-400);
cursor: pointer;
transition: all var(--transition-fast);
}
.toast-close:hover { background: rgba(0,0,0,0.05); color: var(--color-text); }
/* ============================================================
Hero Header System
============================================================ */
.hero {
color: var(--color-on-accent);
padding: 1.75rem 2rem;
}
.hero--blue { background: linear-gradient(135deg, var(--tint-blue-strong) 0%, var(--color-primary) 100%); }
.hero--indigo { background: linear-gradient(135deg, var(--indigo-900) 0%, var(--indigo-500) 100%); }
.hero--emerald { background: linear-gradient(135deg, var(--emerald-800) 0%, var(--emerald-600) 100%); }
.hero--amber { background: linear-gradient(135deg, var(--amber-900) 0%, var(--amber-600) 100%); }
.hero--purple { background: linear-gradient(135deg, var(--purple-900) 0%, var(--purple-600) 100%); }
.hero--slate { background: linear-gradient(135deg, var(--color-primary-deep) 0%, var(--color-primary) 100%); }
.hero--teal { background: linear-gradient(135deg, var(--teal-900) 0%, var(--teal-600) 100%); }
.hero--dark { background: linear-gradient(135deg, var(--gray-900) 0%, var(--color-gray-800) 100%); }
.hero--compact { padding: 1.25rem 2rem 1.5rem; }
.hero--no-bottom-pad { padding-bottom: 0; }
.hero__content {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 1.25rem;
}
.hero__text h1 {
font-size: 1.625rem;
font-weight: 700;
letter-spacing: -0.02em;
margin: 0 0 0.2rem;
color: var(--color-on-accent);
line-height: 1.2;
}
.hero__desc { font-size: 0.875rem; margin: 0; color: rgba(255,255,255,0.72); }
.hero__meta {
display: flex;
align-items: center;
gap: 0.625rem;
flex-wrap: wrap;
margin-top: 0.35rem;
}
.hero__badge {
display: inline-flex;
align-items: center;
gap: 0.25rem;
background: rgba(255,255,255,0.18);
padding: 0.175rem 0.55rem;
border-radius: 9999px;
font-size: 0.775rem;
font-weight: 500;
}
.hero__meta-item {
font-size: 0.82rem;
opacity: 0.88;
display: flex;
align-items: center;
gap: 0.3rem;
}
.hero__back {
color: rgba(255,255,255,0.75);
text-decoration: none;
font-size: 0.82rem;
display: inline-flex;
align-items: center;
gap: 0.3rem;
transition: color var(--transition-fast);
margin-bottom: 0.625rem;
}
.hero__back:hover { color: var(--color-on-accent); text-decoration: none; }
.hero__actions {
display: flex;
align-items: flex-start;
gap: 0.5rem;
flex-shrink: 0;
flex-wrap: wrap;
}
/* Hero Buttons */
.hero__btn {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.4375rem 0.875rem;
border-radius: var(--radius);
font-weight: 600;
font-size: 0.825rem;
cursor: pointer;
text-decoration: none;
transition: all var(--transition-fast);
border: 1px solid transparent;
line-height: 1.5;
}
.hero__btn:hover { opacity: 0.88; text-decoration: none; }
.hero__btn--primary {
background: var(--color-bg);
color: var(--tint-blue-strong);
border-color: rgba(255,255,255,0.9);
}
.hero__btn--outline {
background: rgba(255,255,255,0.18);
color: var(--color-on-accent);
border-color: rgba(255,255,255,0.35);
}
.hero__btn--outline:hover { background: rgba(255,255,255,0.28); opacity: 1; }
.hero__btn--danger {
background: rgba(221,75,57,0.2);
color: var(--color-on-accent);
border-color: rgba(221,75,57,0.4);
}
.hero__btn--danger:hover { background: rgba(221,75,57,0.35); opacity: 1; }
.hero__left { display: flex; align-items: center; gap: 1rem; }
/* Hero Breadcrumb */
.hero-breadcrumb {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.82rem;
margin-bottom: 1rem;
opacity: 0.88;
flex-wrap: wrap;
}
.hero-breadcrumb a { color: rgba(255,255,255,0.78); text-decoration: none; }
.hero-breadcrumb a:hover { color: var(--color-on-accent); }
.hero-breadcrumb span { color: rgba(255,255,255,0.45); }
.hero-breadcrumb .current { color: var(--color-on-accent); font-weight: 500; }
/* Hero Search */
.hero__search { margin-top: 0.875rem; margin-bottom: 0.4rem; }
.hero__search form {
display: flex;
align-items: center;
gap: 0.5rem;
max-width: 520px;
}
.hero__search-wrap {
position: relative;
flex: 1;
display: flex;
align-items: center;
}
.hero__search-icon {
position: absolute;
left: 0.7rem;
pointer-events: none;
color: rgba(255,255,255,0.55);
}
.hero__search input[type="search"],
.hero__search input[type="text"] {
width: 100%;
padding: 0.45rem 0.875rem 0.45rem 2.125rem;
border-radius: var(--radius);
border: 1px solid rgba(255,255,255,0.3);
background: rgba(255,255,255,0.14);
color: var(--color-on-accent);
font-size: 0.875rem;
outline: none;
transition: all var(--transition-fast);
}
.hero__search input::placeholder { color: rgba(255,255,255,0.5); }
.hero__search input:focus {
background: rgba(255,255,255,0.22);
border-color: rgba(255,255,255,0.55);
}
.hero__search-btn {
padding: 0.45rem 0.875rem;
border-radius: var(--radius);
background: rgba(255,255,255,0.18);
border: 1px solid rgba(255,255,255,0.3);
color: var(--color-on-accent);
font-size: 0.825rem;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
transition: background var(--transition-fast);
}
.hero__search-btn:hover { background: rgba(255,255,255,0.28); }
.hero__search-reset {
color: rgba(255,255,255,0.65);
font-size: 0.775rem;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 0.3rem;
padding: 0.3rem 0.5rem;
border-radius: var(--radius-sm);
}
.hero__search-reset:hover { color: var(--color-on-accent); text-decoration: none; }
/* Hero Filter Bar */
.hero__filterbar {
margin-top: 0.875rem;
padding-top: 0.75rem;
border-top: 1px solid rgba(255,255,255,0.15);
padding-bottom: 0.875rem;
}
.hero__filterbar form {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
}
.hero__filterbar input[type="search"],
.hero__filterbar input[type="text"] {
flex: 1;
min-width: 180px;
padding: 0.4rem 0.875rem 0.4rem 2.125rem;
border-radius: var(--radius);
border: 1px solid rgba(255,255,255,0.3);
background: rgba(255,255,255,0.14);
color: var(--color-on-accent);
font-size: 0.875rem;
outline: none;
transition: all var(--transition-fast);
}
.hero__filterbar input::placeholder { color: rgba(255,255,255,0.5); }
.hero__filterbar input:focus { background: rgba(255,255,255,0.22); border-color: rgba(255,255,255,0.55); }
.hero__filterbar select {
padding: 0.4rem 0.875rem;
border-radius: var(--radius);
border: 1px solid rgba(255,255,255,0.3);
background: rgba(255,255,255,0.14);
color: var(--color-on-accent);
font-size: 0.875rem;
cursor: pointer;
outline: none;
appearance: none;
}
.hero__filterbar select option { background: var(--color-gray-800); color: var(--color-on-accent); }
.hero__filterbar select:focus { background: rgba(255,255,255,0.22); }
.hero__filterbar-search-wrap {
position: relative;
flex: 1;
min-width: 180px;
}
.hero__filterbar-icon {
position: absolute;
left: 0.65rem;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
color: rgba(255,255,255,0.55);
}
.hero__filterbar-btn {
padding: 0.4rem 0.875rem;
border-radius: var(--radius);
background: rgba(255,255,255,0.18);
border: 1px solid rgba(255,255,255,0.3);
color: var(--color-on-accent);
font-size: 0.825rem;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
transition: background var(--transition-fast);
}
.hero__filterbar-btn:hover { background: rgba(255,255,255,0.28); }
.hero__filterbar-reset {
color: rgba(255,255,255,0.65);
font-size: 0.775rem;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 0.3rem;
padding: 0.3rem 0.5rem;
border-radius: var(--radius-sm);
}
.hero__filterbar-reset:hover { color: var(--color-on-accent); text-decoration: none; }
/* Hero KPI Bar */
.hero__kpi-bar {
display: flex;
align-items: stretch;
background: rgba(0,0,0,0.15);
border-radius: var(--radius);
overflow: hidden;
margin-top: 1rem;
}
.hero__kpi-item {
flex: 1;
padding: 0.625rem 1rem;
display: flex;
flex-direction: column;
gap: 0.1rem;
min-width: 0;
}
.hero__kpi-divider {
width: 1px;
background: rgba(255,255,255,0.18);
align-self: stretch;
margin: 0.4rem 0;
}
.hero__kpi-label {
font-size: 0.68rem;
font-weight: 700;
color: rgba(255,255,255,0.6);
text-transform: uppercase;
letter-spacing: 0.06em;
}
.hero__kpi-value {
font-size: 1.25rem;
font-weight: 800;
color: var(--color-on-accent);
line-height: 1;
}
/* ============================================================
Dashboard
============================================================ */
.dashboard { max-width: var(--max-content-width); margin: 0 auto; }
.dashboard-header { margin-bottom: var(--spacing-xl); }
.dashboard-header h1 { margin-bottom: var(--spacing-xs); }
.dashboard-subtitle { color: var(--color-text-muted); margin: 0; }
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: var(--spacing-lg);
}
.dashboard-card {
background: var(--color-bg);
border-radius: var(--radius);
border: 1px solid var(--color-border);
padding: var(--spacing-lg);
box-shadow: var(--shadow-sm);
}
.dashboard-card h2 {
font-size: var(--font-size-lg);
margin-bottom: var(--spacing-md);
padding-bottom: var(--spacing-sm);
border-bottom: 1px solid var(--color-border);
}
.quick-actions { display: flex; flex-wrap: wrap; gap: var(--spacing-sm); }
.quick-action {
display: flex;
align-items: center;
gap: var(--spacing-sm);
padding: 0.4375rem 0.875rem;
background: var(--color-gray-50);
border: 1px solid var(--color-border);
border-radius: var(--radius);
color: var(--color-text);
text-decoration: none;
font-size: var(--font-size-sm);
transition: all var(--transition-fast);
}
.quick-action:hover {
background: var(--color-primary);
color: var(--color-on-accent);
border-color: var(--color-primary-dark);
text-decoration: none;
}
.quick-icon { font-size: 1.125em; }
.stat-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--spacing-sm); }
.stat-item {
text-align: center;
padding: 0.875rem;
background: var(--color-gray-50);
border: 1px solid var(--color-border);
border-radius: var(--radius);
}
.stat-value { font-size: 1.5rem; font-weight: 700; color: var(--color-primary); }
.stat-label { font-size: var(--font-size-xs); color: var(--color-text-muted); }
.recent-list { list-style: none; padding: 0; margin: 0; }
.recent-item { padding: 0.4375rem 0; border-bottom: 1px solid var(--color-border); }
.recent-item:last-child { border-bottom: none; }
.recent-item a {
display: flex;
justify-content: space-between;
align-items: center;
color: var(--color-text);
font-size: var(--font-size-sm);
}
.recent-item a:hover { color: var(--color-primary); text-decoration: none; }
.recent-date { font-size: var(--font-size-xs); color: var(--color-text-muted); }
/* ============================================================
Searchable Select Component
============================================================ */
/* Standard: kompaktes Inline-Control – passt in Filterleisten/Toolbars, ohne
die Zeile zu sprengen. In Formulargruppen volle Feldbreite (s. u.). */
.ss-wrap { position: relative; display: inline-block; vertical-align: middle; width: auto; min-width: 10rem; max-width: 100%; }
.form-group .ss-wrap { display: block; width: 100%; min-width: 0; }
.tk-filters .ss-wrap, .tc-actions .ss-wrap { width: auto; min-width: 150px; }
/* Kompaktvariante (Trigger eines form-control-sm-Selects): Höhe, Padding,
Schriftgröße und Radius wie .form-control-sm, damit es in Filterleisten
bündig zu den Suchfeldern sitzt. */
.ss-wrap--sm { min-width: 8rem; }
.ss-wrap--sm .ss-trigger {
min-height: 1.9375rem;
padding: 0.25rem 0.5rem;
font-size: 0.8125rem;
border-radius: var(--radius-sm);
}
/* Nativer Select unter der Hülle: unsichtbar, aber fokussierbar (damit die
required-Validierung greift) und ohne Einfluss aufs Layout. */
.ss-native { position: absolute; width: 1px; height: 1px; margin: 0; padding: 0; border: 0; opacity: 0; pointer-events: none; }
.ss-trigger {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 0.4375rem 0.75rem;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius);
font-size: var(--font-size-sm);
color: var(--color-text);
cursor: pointer;
text-align: left;
line-height: 1.5;
min-height: 2.375rem;
font-family: inherit;
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.ss-trigger::after { content: '▾'; font-size: 0.8em; color: var(--color-text-muted); margin-left: 0.4rem; flex-shrink: 0; }
.ss-trigger-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ss-trigger.ss-placeholder .ss-trigger-label { color: var(--color-text-muted); }
.ss-trigger:hover, .ss-trigger:focus {
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.15);
outline: none;
}
.ss-dropdown {
position: fixed;
z-index: 99999;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius);
box-shadow: var(--shadow-lg);
display: none;
flex-direction: column;
min-width: 180px;
}
.ss-dropdown.open { display: flex; }
.ss-search-wrap { padding: 0.4rem; border-bottom: 1px solid var(--color-border); }
.ss-search {
width: 100%;
padding: 0.375rem 0.625rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
font-size: var(--font-size-sm);
color: var(--color-text);
background: var(--color-bg);
outline: none;
box-sizing: border-box;
font-family: inherit;
}
.ss-search:focus { border-color: var(--color-primary); box-shadow: 0 0 0 2px rgba(var(--color-primary-rgb), 0.15); }
.ss-list { max-height: 240px; overflow-y: auto; padding: 0.2rem 0; }
.ss-item {
display: flex;
align-items: center;
gap: 0.375rem;
padding: 0.4rem 0.875rem;
font-size: var(--font-size-sm);
color: var(--color-text);
cursor: pointer;
transition: background var(--transition-fast);
user-select: none;
}
.ss-item:hover { background: var(--color-bg-hover); }
/* Tastatur-Highlight (Pfeiltasten). Deutlicher als Hover, damit Maus + Tastatur
gleichzeitig nutzbar sind ohne Unsicherheit, was "aktiv" ist. */
.ss-item.ss-active { background: rgba(var(--color-primary-rgb), 0.14); box-shadow: inset 2px 0 0 var(--color-primary); }
.ss-item.ss-selected { color: var(--color-primary); font-weight: 500; background: rgba(var(--color-primary-rgb), 0.07); }
.ss-item.ss-empty-opt { color: var(--color-text-muted); font-style: italic; }
/* Freitext-Eintrag (data-allow-custom): als eigener Vorschlag über der Liste. */
.ss-item.ss-item-custom {
color: var(--color-primary);
border-bottom: 1px solid var(--color-border);
}
/* Anlegen-Eintrag (data-create-company): steht wie der Freitext-Vorschlag
über der Liste und hebt sich als Handlung von den Treffern ab. */
.ss-item.ss-item-create {
color: var(--color-primary);
font-weight: 500;
background: var(--color-primary-soft);
border-bottom: 1px solid var(--color-border);
}
.ss-item[data-depth="1"] { padding-left: 1.75rem; }
.ss-item[data-depth="2"] { padding-left: 3rem; }
.ss-item[data-depth="3"] { padding-left: 4.25rem; }
.ss-indent { color: var(--color-text-muted); font-size: 0.82em; flex-shrink: 0; }
.ss-no-results { padding: 0.75rem 0.875rem; font-size: var(--font-size-sm); color: var(--color-text-muted); text-align: center; }
/* ============================================================
AdminLTE Content-Header
Simple page title bar with breadcrumbs
============================================================ */
.content-header {
padding: 15px 20px;
background: var(--color-bg);
border-bottom: 1px solid var(--color-gray-300);
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 0;
width: 100%;
box-sizing: border-box;
}
.content-header h1 {
font-size: 1.4rem;
font-weight: 600;
margin: 0;
color: var(--color-gray-800);
}
.content-header .breadcrumb {
background: transparent;
padding: 0;
margin: 0;
font-size: 0.8rem;
color: var(--color-secondary);
display: flex;
align-items: center;
gap: 0.3rem;
list-style: none;
}
.content-header .breadcrumb-item + .breadcrumb-item::before {
content: "/";
margin-right: 0.3rem;
color: var(--color-gray-500);
}
.content-header .breadcrumb-item.active { color: var(--color-secondary); }
.content-header .breadcrumb-item a { color: var(--color-primary); text-decoration: none; }
.content-header-actions {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
}
/* Standard inner content padding after content-header */
.page-body {
padding: 20px;
}
/* ============================================================
AdminLTE Small-Box (KPI stat cards)
============================================================ */
.small-box {
border-radius: 0.25rem;
position: relative;
display: block;
margin-bottom: 20px;
box-shadow: 0 1px 1px rgba(0,0,0,.1);
overflow: hidden;
}
.small-box > .inner {
padding: 10px;
}
.small-box h3 {
font-size: 2.2rem;
font-weight: 700;
margin: 0 0 10px 0;
white-space: nowrap;
padding: 0;
color: var(--color-on-accent);
}
.small-box p {
font-size: 1rem;
color: rgba(255,255,255,0.85);
margin: 0;
}
.small-box .icon {
position: absolute;
top: -10px;
right: 10px;
z-index: 0;
font-size: 70px;
color: rgba(0,0,0,.15);
line-height: 1;
display: flex;
align-items: center;
height: 100%;
}
.small-box .icon svg {
width: 70px;
height: 70px;
}
.small-box > .small-box-footer {
position: relative;
text-align: center;
padding: 3px 0;
color: rgba(255,255,255,.8);
display: block;
z-index: 10;
background: rgba(0,0,0,.1);
text-decoration: none;
font-size: 0.8rem;
transition: background 0.15s;
}
.small-box > .small-box-footer:hover {
color: var(--color-on-accent);
background: rgba(0,0,0,.15);
}
.small-box.bg-info { background-color: var(--bs-info) !important; }
.small-box.bg-success { background-color: var(--bs-success) !important; }
.small-box.bg-warning { background-color: var(--bs-warning) !important; color: var(--color-gray-800); }
.small-box.bg-warning h3, .small-box.bg-warning p { color: var(--color-gray-800); }
.small-box.bg-warning .small-box-footer { color: rgba(0,0,0,.6); }
.small-box.bg-danger { background-color: var(--bs-danger) !important; }
.small-box.bg-primary { background-color: var(--bs-primary) !important; }
.small-box.bg-secondary { background-color: var(--color-secondary) !important; }
.small-box.bg-teal { background-color: var(--bs-teal) !important; }
.small-box.bg-indigo { background-color: var(--bs-indigo) !important; }
.small-box.bg-purple { background-color: var(--bs-purple) !important; }
.small-box.bg-orange { background-color: var(--bs-orange) !important; }
.small-box.bg-lime { background-color: var(--lime-500) !important; color: var(--color-gray-800); }
.small-box.bg-lime h3, .small-box.bg-lime p { color: var(--color-gray-800); }
@media (max-width: 767.98px) {
.small-box h3 { font-size: 1.6rem; }
.small-box .icon { font-size: 50px; }
}
/* ============================================================
AdminLTE Info-Box (alternative KPI style)
============================================================ */
.info-box {
cursor: default;
display: flex;
min-height: 80px;
background: var(--color-bg);
border-radius: 0.25rem;
margin-bottom: 20px;
box-shadow: 0 0 1px rgba(0,0,0,.125), 0 1px 3px rgba(0,0,0,.2);
overflow: hidden;
}
.info-box-icon {
display: flex;
align-items: center;
justify-content: center;
width: 70px;
font-size: 1.875rem;
flex-shrink: 0;
color: var(--color-on-accent);
}
.info-box-icon svg { width: 32px; height: 32px; }
.info-box-content {
display: flex;
flex-direction: column;
justify-content: center;
padding: 5px 10px;
flex: 1;
min-width: 0;
}
.info-box-text {
display: block;
font-size: 0.875rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-weight: 600;
color: var(--color-secondary);
}
.info-box-number {
display: block;
font-weight: 700;
font-size: 1.5rem;
line-height: 1.2;
}
/* ============================================================
Module filter card (replaces hero__filterbar)
============================================================ */
.filter-card {
background: var(--color-bg);
border-radius: 0.25rem;
border: 1px solid rgba(0,0,0,.125);
box-shadow: 0 0 1px rgba(0,0,0,.125), 0 1px 3px rgba(0,0,0,.1);
padding: 0.75rem 1rem;
margin-bottom: 1.25rem;
}
.filter-card-body {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
padding: 0.1rem 1rem;
}
.filter-card .form-control,
.filter-card select {
display: inline-block;
width: auto;
}
/* Einheitliche Feldgröße in ALLEN Such-/Filterkarten: kompakte (-sm)
Steuerelemente werden auf die volle Standardhöhe gehoben, damit Suchfeld,
Dropdowns und Buttons modulübergreifend gleich hoch sind. Horizontales
Padding der Inputs bleibt unangetastet (Platz für das Lupen-Icon). */
.filter-card-body .form-control-sm {
min-height: 2.375rem;
padding-top: 0.4375rem;
padding-bottom: 0.4375rem;
font-size: var(--font-size-sm);
border-radius: var(--radius);
}
.filter-card-body .ss-wrap--sm .ss-trigger {
min-height: 2.375rem;
padding: 0.4375rem 0.75rem;
font-size: var(--font-size-sm);
border-radius: var(--radius);
}
.filter-card-body .btn-sm {
padding: 0.4375rem 0.875rem;
font-size: var(--font-size-sm);
border-radius: var(--radius);
}
/* Einheitlicher vertikaler Abstand der Filterkarte über alle Module: kein
Abstand oben, 1rem darunter – überschreibt uneinheitliche Utilities
(mb-2/mb-3/keine) und modul-eigene Margen. Horizontaler Abstand bleibt den
Modul-Layouts überlassen. */
.card:has(> .filter-card-body) {
margin-bottom: 1rem !important;
}
.filter-input-wrap {
position: relative;
display: inline-flex;
align-items: center;
flex: 1;
min-width: 180px;
max-width: 300px;
}
.filter-input-wrap .filter-search-icon {
position: absolute;
left: 0.6rem;
color: var(--color-gray-500);
pointer-events: none;
}
.filter-input-wrap input[type="search"],
.filter-input-wrap input[type="text"] {
padding-left: 2rem;
width: 100%;
}
/* Einheitliche Lupe in JEDEM Filter-Suchfeld – zentral als Hintergrundbild,
damit kein Modul eigenes Icon-Markup braucht. Vorhandene Inline-Icons in
Filterkarten werden ausgeblendet (sonst doppelt). */
.filter-card-body input[type="search"],
.filter-card-body input[type="text"][name="q"],
.filter-card-body input[type="text"][name="search"],
.filter-card-body input[type="text"][name="search_query"],
.filter-card-body .filter-input-wrap input {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: 0.65rem center;
background-size: 15px 15px;
padding-left: 2rem;
}
.filter-card-body .filter-search-icon,
.filter-card-body .cb-search-icon,
.filter-card-body .ssl-search-icon { display: none; }
/* ============================================================
Old Layout Classes (Backwards Compatibility)
These were used in the previous top-nav layout.
Kept for any inline usage in module templates.
============================================================ */
.app-layout { display: flex; min-height: 100vh; }
.app-sidebar {
position: fixed; top: 0; left: 0;
width: var(--sidebar-width); height: 100vh;
background: var(--sidebar-bg); color: var(--sidebar-text);
overflow-y: auto; z-index: 1035;
}
.app-main { flex: 1; margin-left: var(--sidebar-width); display: flex; flex-direction: column; min-height: 100vh; }
.app-header {
position: sticky; top: 0; height: var(--navbar-height);
background: var(--navbar-bg); border-bottom: 1px solid rgba(0,0,0,0.2);
display: flex; align-items: center; padding: 0 var(--spacing-xl); z-index: 1030;
}
.app-content { flex: 1; padding: var(--spacing-xl); max-width: var(--max-content-width); width: 100%; margin: 0 auto; }
/* ============================================================
Bootstrap-compatible Grid & Utilities
(minimal subset used by module templates)
============================================================ */
.row {
display: flex;
flex-wrap: wrap;
margin-right: -7px;
margin-left: -7px;
}
[class^="col-"], [class*=" col-"] {
position: relative;
width: 100%;
padding-right: 7px;
padding-left: 7px;
box-sizing: border-box;
}
/* Default columns (mobile-first = 100%) */
.col-6 { flex: 0 0 50%; max-width: 50%; }
.col-12 { flex: 0 0 100%; max-width: 100%; }
/* lg: >= 992px */
@media (min-width: 992px) {
.col-lg-2 { flex: 0 0 16.6667%; max-width: 16.6667%; }
.col-lg-3 { flex: 0 0 25%; max-width: 25%; }
.col-lg-4 { flex: 0 0 33.3333%; max-width: 33.3333%; }
.col-lg-6 { flex: 0 0 50%; max-width: 50%; }
.col-lg-8 { flex: 0 0 66.6667%; max-width: 66.6667%; }
.col-lg-9 { flex: 0 0 75%; max-width: 75%; }
.col-lg-12 { flex: 0 0 100%; max-width: 100%; }
}
/* input-group */
.input-group {
position: relative;
display: flex;
flex-wrap: nowrap;
align-items: stretch;
width: 100%;
}
.input-group > .form-control {
position: relative;
flex: 1 1 auto;
width: 1%;
min-width: 0;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group-append {
display: flex;
align-items: stretch;
}
.input-group-append .btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
display: inline-flex;
align-items: center;
}
/* Spacing utilities */
.mb-0 { margin-bottom: 0 !important; }
.mb-1 { margin-bottom: 0.25rem !important; }
.mb-2 { margin-bottom: 0.5rem !important; }
.mb-3 { margin-bottom: 1rem !important; }
.mb-4 { margin-bottom: 1.5rem !important; }
.mt-0 { margin-top: 0 !important; }
.mt-1 { margin-top: 0.25rem !important; }
.mt-2 { margin-top: 0.5rem !important; }
.mt-3 { margin-top: 1rem !important; }
.mt-4 { margin-top: 1.5rem !important; }
.mr-0 { margin-right: 0 !important; }
.mr-1 { margin-right: 0.25rem !important; }
.mr-2 { margin-right: 0.5rem !important; }
.mr-3 { margin-right: 1rem !important; }
.ml-0 { margin-left: 0 !important; }
.ml-1 { margin-left: 0.25rem !important; }
.ml-2 { margin-left: 0.5rem !important; }
.ml-3 { margin-left: 1rem !important; }
.mr-auto { margin-right: auto !important; }
.ml-auto { margin-left: auto !important; }
.me-2 { margin-right: 0.5rem !important; }
.ms-auto { margin-left: auto !important; }
.p-0 { padding: 0 !important; }
.p-1 { padding: 0.25rem !important; }
.p-2 { padding: 0.5rem !important; }
.p-3 { padding: 1rem !important; }
.px-3 { padding-left: 1rem !important; padding-right: 1rem !important; }
.py-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; }
.d-flex { display: flex !important; }
.align-items-center { align-items: center !important; }
.justify-content-between { justify-content: space-between !important; }
.flex-wrap { flex-wrap: wrap !important; }
.gap-2 { gap: 0.5rem !important; }
.text-muted { color: var(--color-secondary) !important; }
.text-center { text-align: center !important; }
.fw-bold { font-weight: 700 !important; }
.small { font-size: 0.875em !important; }
.w-100 { width: 100% !important; }
/* ============================================ */
/* Adressbuch / Telefonbuch (cb-) Styles */
/* Shared between /contacts and /phonebook */
/* ============================================ */
.cb-fullwidth {}
.cb-content {
padding: 0.75rem 1rem 3rem;
}
.cb-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
gap: 1rem;
}
.cb-card {
background: var(--color-bg);
border: 1px solid var(--gray-200);
border-radius: 0.25rem;
padding: 1.25rem;
display: flex;
flex-direction: column;
gap: 0.75rem;
transition: all 0.15s;
text-decoration: none;
color: inherit;
cursor: pointer;
}
.cb-card:hover {
border-color: var(--blue-300);
box-shadow: 0 4px 16px rgba(var(--color-primary-rgb), 0.15);
text-decoration: none;
}
.cb-card-header { display: flex; align-items: flex-start; gap: 0.75rem; }
.cb-card-avatar {
width: 72px; height: 72px; min-width: 72px;
border-radius: 0.25rem; color: var(--color-on-accent);
display: flex; align-items: center; justify-content: center;
font-size: 1.6rem; font-weight: 700;
}
.cb-card-title { flex: 1; min-width: 0; }
.cb-card-name {
font-weight: 600; font-size: 0.95rem; color: var(--gray-900);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cb-card-custnr { font-size: 0.75rem; color: var(--gray-400); margin-top: 0.15rem; font-weight: 500; }
.cb-card-address {
font-size: 0.8rem; color: var(--gray-500); margin-top: 0.15rem;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cb-card-details { display: flex; flex-direction: column; gap: 0.35rem; padding-left: 0.25rem; }
.cb-card-detail { display: flex; align-items: center; gap: 0.5rem; font-size: 0.8rem; color: var(--gray-500); }
.cb-card-detail svg { flex-shrink: 0; color: var(--gray-400); }
.cb-card-detail span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cb-card-detail-link { text-decoration: none; color: var(--gray-500); transition: color 0.15s; cursor: pointer; }
.cb-card-detail-link:hover { color: var(--color-primary); text-decoration: none; }
.cb-person-detail { color: var(--gray-500); font-size: 0.75rem; }
.cb-card-footer {
display: flex; align-items: center; justify-content: space-between;
padding-top: 0.5rem; border-top: 1px solid var(--gray-100); margin-top: auto;
}
.cb-card-contacts-badge {
display: inline-flex; align-items: center; gap: 0.375rem;
font-size: 0.75rem; font-weight: 500; color: var(--gray-500);
background: var(--gray-100); padding: 0.2rem 0.6rem; border-radius: 9999px;
}
.cb-card-contacts-badge svg { color: var(--gray-400); }
.cb-card-arrow { color: var(--gray-300); display: flex; align-items: center; transition: color 0.15s, transform 0.15s; }
.cb-card:hover .cb-card-arrow { color: var(--color-primary); transform: translateX(2px); }
.cb-empty-state { text-align: center; padding: 4rem 1rem; color: var(--gray-400); }
.cb-empty-state svg { margin-bottom: 1rem; opacity: 0.4; }
.cb-empty-state p { font-size: 0.95rem; margin: 0 0 1.25rem; color: var(--gray-500); }
.cb-btn {
display: inline-flex; align-items: center; gap: 0.5rem;
padding: 0.5rem 1rem; font-size: 0.875rem; font-weight: 500;
border-radius: 0.5rem; border: 1px solid transparent;
cursor: pointer; text-decoration: none; transition: all 0.15s;
}
.cb-btn-primary { background: var(--color-primary); color: var(--color-on-accent); border-color: var(--color-primary); }
.cb-btn-primary:hover { background: var(--color-primary-dark); border-color: var(--color-primary-dark); }
.cb-btn-secondary { background: var(--gray-100); color: var(--gray-700); border-color: var(--gray-300); }
.cb-btn-secondary:hover { background: var(--gray-200); }
.cb-section-title { font-size: 1rem; font-weight: 600; color: var(--gray-700); margin: 0 0 1rem 0; }
.cb-card-avatar-img { width: 72px; height: 72px; min-width: 72px; border-radius: 0.25rem; object-fit: cover; }
/* Person cards grid */
.cb-contacts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 0.75rem;
}
.cb-person-card {
display: flex; align-items: center; gap: 0.75rem;
padding: 0.875rem 1rem;
background: var(--color-bg); border: 1px solid var(--gray-200); border-radius: 0.25rem;
text-decoration: none; color: inherit; transition: all 0.15s;
}
.cb-person-card:hover {
border-color: var(--blue-300);
box-shadow: 0 2px 8px rgba(var(--color-primary-rgb), 0.15);
text-decoration: none;
}
.cb-person-avatar {
width: 60px; height: 60px; min-width: 60px; border-radius: 50%;
background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
color: var(--color-on-accent); display: flex; align-items: center; justify-content: center;
font-size: 1rem; font-weight: 700;
}
.cb-person-avatar-img { width: 60px; height: 60px; min-width: 60px; border-radius: 50%; object-fit: cover; }
.cb-person-info { flex: 1; min-width: 0; }
.cb-person-name {
font-weight: 600; font-size: 0.9rem; color: var(--gray-900);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cb-person-position { font-size: 0.8rem; color: var(--gray-500); }
.cb-person-company { font-size: 0.75rem; color: var(--color-primary); font-weight: 500; }
.cb-person-contacts {
display: flex; flex-direction: column; gap: 0.15rem;
font-size: 0.75rem; color: var(--gray-500); flex-shrink: 0; text-align: right;
}
@media (max-width: 768px) {
.cb-fullwidth { overflow-x: hidden; }
.cb-content { padding: 1rem; }
.cb-grid { grid-template-columns: 1fr; }
.cb-contacts-grid { grid-template-columns: 1fr; }
.cb-person-card { flex-wrap: wrap; }
.cb-person-contacts {
width: 100%; flex-direction: row; gap: 0.75rem;
text-align: left; padding-left: calc(60px + 0.75rem);
}
}
@media (max-width: 480px) {
.cb-content { padding: 0.75rem; }
.cb-card { padding: 1rem; }
.cb-person-card { padding: 0.75rem; }
}
/* Emoji-Icon-Ersatz (globaler Icon-Umschalter, Emoji-Modus) – verhält sich
wie ein Inline-Icon an Stelle eines <i class="fa-…">. */
.emoji-icon {
font-style: normal;
font-weight: 400;
line-height: 1;
display: inline-block;
text-align: center;
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
}
/* ── Datei-Auswahl (zentral, Styleguide) ─────────────────────────────
Der native „Datei auswählen"-Knopf aller Datei-Eingabefelder folgt dem
zentralen Button-Stil – einheitlich in allen Modulen, ohne dass Templates
dafür eine eigene Klasse brauchen. */
input[type="file"] {
font-size: 0.85rem;
font-family: inherit;
color: var(--color-gray-700);
max-width: 100%;
}
input[type="file"]::file-selector-button {
margin-right: 0.6rem;
padding: 0.25rem 0.625rem;
font-size: 0.8125rem;
font-family: inherit;
line-height: 1.5;
color: var(--color-gray-800);
background: var(--color-bg);
border: 1px solid var(--color-gray-400);
border-radius: var(--radius-sm);
cursor: pointer;
transition: background-color 0.15s ease, border-color 0.15s ease;
}
input[type="file"]::file-selector-button:hover { background: var(--color-gray-100); }
input[type="file"]::-webkit-file-upload-button {
margin-right: 0.6rem;
padding: 0.25rem 0.625rem;
font-size: 0.8125rem;
font-family: inherit;
line-height: 1.5;
color: var(--color-gray-800);
background: var(--color-bg);
border: 1px solid var(--color-gray-400);
border-radius: var(--radius-sm);
cursor: pointer;
transition: background-color 0.15s ease, border-color 0.15s ease;
}
input[type="file"]::-webkit-file-upload-button:hover { background: var(--color-gray-100); }
/* ============================================================
Barrierefreiheit (Styleguide Abschnitt „Bedienbarkeit")
------------------------------------------------------------
Gilt für alle Module. Die Regeln stehen bewusst am Ende der
Datei: Der Tastaturfokus muss sichtbar bleiben, auch wenn ein
Modul seine eigene Schaltfläche gestaltet hat.
============================================================ */
/* Nur für Vorlese-Software: liegt im Baum, nimmt aber keinen Platz ein. */
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0 0 0 0);
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
/* Sprungmarke zum Inhalt – erscheint, sobald sie den Fokus bekommt. */
.skip-link {
position: absolute;
top: 0;
left: 0;
z-index: 10000;
padding: 0.6rem 1rem;
font-size: var(--font-size-sm);
font-weight: 600;
color: var(--color-on-accent);
background: var(--color-primary-deep);
border-radius: 0 0 var(--radius) 0;
transform: translateY(-120%);
transition: transform var(--transition-fast);
}
.skip-link:focus {
transform: translateY(0);
}
/* Der Fokusring. `:focus-visible` zeigt ihn der Tastatur und lässt ihn beim
Klicken mit der Maus weg – so stört er niemanden, der ihn nicht braucht. */
:focus-visible {
outline: var(--focus-ring-width) solid var(--focus-ring-color);
outline-offset: var(--focus-ring-offset);
box-shadow: 0 0 0 calc(var(--focus-ring-width) + var(--focus-ring-offset)) var(--focus-ring-contrast);
border-radius: var(--radius-sm);
}
/* Auf dunklem Grund kehren sich Ring und Kontrastfarbe um. */
.main-header :focus-visible,
.sidebar :focus-visible,
.admin-sidebar :focus-visible,
.navbar :focus-visible,
.modal-card-header :focus-visible {
outline-color: var(--focus-ring-contrast);
box-shadow: 0 0 0 calc(var(--focus-ring-width) + var(--focus-ring-offset)) var(--focus-ring-color);
}
/* Browser ohne `:focus-visible` bekommen weiterhin einen Ring; Browser mit
Unterstützung nehmen den Fallback wieder zurück. */
:focus {
outline: var(--focus-ring-width) solid var(--focus-ring-color);
outline-offset: var(--focus-ring-offset);
}
:focus:not(:focus-visible) {
outline: none;
box-shadow: none;
}
/* Ein Element, das erst durch ein Skript fokussierbar wird (Dialoge), soll
den Ring nicht tragen – der Fokus dient dort nur der Ansage. */
[tabindex="-1"]:focus,
[tabindex="-1"]:focus-visible {
outline: none;
box-shadow: none;
}
/* Dialoge: der Hintergrund bleibt für die Maus, aber nicht für die Tastatur
erreichbar – den Rest erledigt die Fokusfalle in dialog.js. */
.modal-overlay[aria-hidden="true"] {
display: none !important;
}
/* Wer Bewegung im Betriebssystem abbestellt hat, bekommt keine. */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* Im Kontrastmodus von Windows zeichnet das System die Farben; der Ring muss
dort die Systemfarbe nutzen, sonst verschwindet er. */
@media (forced-colors: active) {
:focus-visible {
outline-color: Highlight;
box-shadow: none;
}
}