:root {
  /* Palette matches www.adeo-it.de's corporate design (their :root custom
     properties + accent colors, read directly from their stylesheet). */
  --bg: #f7f8f6;
  --surface: #ffffff;
  --border: #eceeea;
  --text: #262b27;
  --text-muted: #6b6f6c;
  --primary: #8cc63f;
  --primary-hover: #2f3a33;
  --danger: #c0533f;
  --danger-bg: color-mix(in srgb, #c0533f 12%, white);
  --radius: 10px;
  --shadow: 0 4px 18px rgba(27, 33, 29, 0.08);
  /* Dedicated (not just var(--primary)) so badge text stays readable: the
     brand green is too light for AA contrast as small text on its own
     light tint — navy text on the light tint reads clearly instead. */
  --badge-active-bg: color-mix(in srgb, #8cc63f 18%, transparent);
  --badge-active-text: #2f3a33;
  /* Status-light colors for the Nebenstellen tiles — deliberately plain
     red/green (not the brand palette), since these mirror a literal
     hardware-style status light convention (rot = Störung, grün = ok). */
  --status-bad-bg: #ffd6d6;
  --status-bad-border: #ffb3b3;
  --status-good-bg: #d3f5d0;
  --status-good-border: #a9e6a3;
  --status-warn-bg: #fff2b3;
  --status-warn-border: #f5d76e;
  --status-warn-glow: rgba(245, 200, 20, 0.65);
  --status-offline-idle-bg: #d3e8ff;
  --status-offline-idle-border: #a9cdf5;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* adeo-it.de has no dark mode; these are derived from the same
       palette (navy tones for surfaces, the lighter accent green for
       better contrast on dark backgrounds). */
    --bg: #1b211d;
    --surface: #2f3a33;
    --border: rgba(255, 255, 255, 0.12);
    --text: #f7f8f6;
    --text-muted: #a7a9ac;
    --primary: #a4d65e;
    --primary-hover: #8cc63f;
    --danger: #c0533f;
    --danger-bg: rgba(192, 83, 63, 0.18);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.35);
    /* Light green text now, not navy — navy would vanish against a dark
       tinted background instead of the light one used in light mode. */
    --badge-active-bg: color-mix(in srgb, #a4d65e 18%, transparent);
    --badge-active-text: #a4d65e;
    --status-bad-bg: rgba(255, 90, 90, 0.28);
    --status-bad-border: rgba(255, 90, 90, 0.5);
    --status-good-bg: rgba(90, 220, 100, 0.22);
    --status-good-border: rgba(90, 220, 100, 0.45);
    --status-warn-bg: rgba(245, 200, 20, 0.25);
    --status-warn-border: rgba(245, 200, 20, 0.5);
    --status-warn-glow: rgba(245, 200, 20, 0.55);
    --status-offline-idle-bg: rgba(90, 160, 240, 0.22);
    --status-offline-idle-border: rgba(90, 160, 240, 0.45);
  }
}

/* ---- Skins (pro Benutzer, siehe assets/skin.js / Benutzereinstellungen) ----
   Ohne data-skin gilt der Standard-Skin oben (inkl. automatischem
   Dunkelmodus). html[data-skin] ist spezifischer als :root und gewinnt
   daher auch gegen den prefers-color-scheme-Block. */
html[data-skin="standard-hell"] {
  color-scheme: light;
  --bg: #f7f8f6;
  --surface: #ffffff;
  --border: #eceeea;
  --text: #262b27;
  --text-muted: #6b6f6c;
  --primary: #8cc63f;
  --primary-hover: #2f3a33;
  --danger: #c0533f;
  --danger-bg: color-mix(in srgb, #c0533f 12%, white);
  --shadow: 0 4px 18px rgba(27, 33, 29, 0.08);
  --badge-active-bg: color-mix(in srgb, #8cc63f 18%, transparent);
  --badge-active-text: #2f3a33;
  --status-bad-bg: #ffd6d6;
  --status-bad-border: #ffb3b3;
  --status-good-bg: #d3f5d0;
  --status-good-border: #a9e6a3;
  --status-warn-bg: #fff2b3;
  --status-warn-border: #f5d76e;
  --status-warn-glow: rgba(245, 200, 20, 0.65);
  --status-offline-idle-bg: #d3e8ff;
  --status-offline-idle-border: #a9cdf5;
}

/* Gemeinsame Status-/Fehlerfarben aller dunklen Skins */
html[data-skin="standard-dunkel"],
html[data-skin="nacht"],
html[data-skin="graphit"] {
  color-scheme: dark;
  --danger: #e06a55;
  --danger-bg: rgba(224, 106, 85, 0.18);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.35);
  --border: rgba(255, 255, 255, 0.12);
  --status-bad-bg: rgba(255, 90, 90, 0.28);
  --status-bad-border: rgba(255, 90, 90, 0.5);
  --status-good-bg: rgba(90, 220, 100, 0.22);
  --status-good-border: rgba(90, 220, 100, 0.45);
  --status-warn-bg: rgba(245, 200, 20, 0.25);
  --status-warn-border: rgba(245, 200, 20, 0.5);
  --status-warn-glow: rgba(245, 200, 20, 0.55);
  --status-offline-idle-bg: rgba(90, 160, 240, 0.22);
  --status-offline-idle-border: rgba(90, 160, 240, 0.45);
}

html[data-skin="standard-dunkel"] {
  --bg: #1b211d;
  --surface: #2f3a33;
  --text: #f7f8f6;
  --text-muted: #a7a9ac;
  --primary: #a4d65e;
  --primary-hover: #8cc63f;
  --danger: #c0533f;
  --danger-bg: rgba(192, 83, 63, 0.18);
  --badge-active-bg: color-mix(in srgb, #a4d65e 18%, transparent);
  --badge-active-text: #a4d65e;
}

html[data-skin="nacht"] {
  --bg: #0f172a;
  --surface: #1e293b;
  --border: rgba(148, 163, 184, 0.18);
  --text: #e2e8f0;
  --text-muted: #94a3b8;
  --primary: #3b82f6;
  --primary-hover: #60a5fa;
  --badge-active-bg: color-mix(in srgb, #60a5fa 20%, transparent);
  --badge-active-text: #93c5fd;
}

html[data-skin="graphit"] {
  --bg: #18181b;
  --surface: #27272a;
  --border: rgba(255, 255, 255, 0.1);
  --text: #f4f4f5;
  --text-muted: #a1a1aa;
  --primary: #e07a1f;
  --primary-hover: #f59e0b;
  --badge-active-bg: color-mix(in srgb, #f59e0b 20%, transparent);
  --badge-active-text: #fbbf24;
}

/* Gemeinsame Status-/Fehlerfarben der hellen Zusatz-Skins */
html[data-skin="ozean"],
html[data-skin="sand"],
html[data-skin="kontrast"] {
  color-scheme: light;
  --danger: #c0392b;
  --danger-bg: color-mix(in srgb, #c0392b 12%, white);
  --status-bad-bg: #ffd6d6;
  --status-bad-border: #ffb3b3;
  --status-good-bg: #d3f5d0;
  --status-good-border: #a9e6a3;
  --status-warn-bg: #fff2b3;
  --status-warn-border: #f5d76e;
  --status-warn-glow: rgba(245, 200, 20, 0.65);
  --status-offline-idle-bg: #d3e8ff;
  --status-offline-idle-border: #a9cdf5;
}

html[data-skin="ozean"] {
  --bg: #f3f7fb;
  --surface: #ffffff;
  --border: #dde6ef;
  --text: #1c2a3a;
  --text-muted: #5f7186;
  --primary: #1f6fb2;
  --primary-hover: #154e7e;
  --shadow: 0 4px 18px rgba(20, 50, 90, 0.08);
  --badge-active-bg: color-mix(in srgb, #1f6fb2 14%, transparent);
  --badge-active-text: #154e7e;
}

html[data-skin="sand"] {
  --bg: #faf6ef;
  --surface: #fffdf9;
  --border: #ece3d4;
  --text: #3a2e22;
  --text-muted: #7a6a58;
  --primary: #b8552b;
  --primary-hover: #8a3c1c;
  --shadow: 0 4px 18px rgba(80, 50, 20, 0.08);
  --badge-active-bg: color-mix(in srgb, #b8552b 14%, transparent);
  --badge-active-text: #8a3c1c;
}

html[data-skin="kontrast"] {
  --bg: #ffffff;
  --surface: #ffffff;
  --border: #000000;
  --text: #000000;
  --text-muted: #333333;
  --primary: #0b3d91;
  --primary-hover: #000000;
  --danger: #a00000;
  --danger-bg: #ffe5e5;
  --shadow: none;
  --badge-active-bg: #0b3d91;
  --badge-active-text: #ffffff;
}
html[data-skin="kontrast"] a {
  text-decoration: underline;
}
html[data-skin="kontrast"] :focus-visible {
  outline: 3px solid #ff9900;
  outline-offset: 2px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.center-screen {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.card {
  width: 100%;
  max-width: 380px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 32px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 24px;
}

.brand-mark {
  width: 36px;
  height: 36px;
  border-radius: 8px;
  background: var(--primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 15px;
}

.brand-name {
  font-weight: 600;
  font-size: 15px;
}

.brand-sub {
  color: var(--text-muted);
  font-size: 12px;
}

h1 {
  font-size: 20px;
  margin: 0 0 4px;
}

.subtitle {
  color: var(--text-muted);
  font-size: 14px;
  margin: 0 0 24px;
}

label {
  display: block;
  font-size: 13px;
  font-weight: 500;
  margin-bottom: 6px;
}

.field {
  margin-bottom: 16px;
  position: relative;
}

/* Custom Kunde-search dropdown (replaces native <input list="datalist">,
   whose suggestion popup position/width is entirely up to the browser and
   in practice opened misaligned to the right of the field in some
   browsers) — anchored to the search input's own .field via position:
   relative above, filtered client-side as the user types instead of
   relying on the datalist's inconsistent cross-browser matching. */
.autocomplete-suggestions {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 20;
  max-height: 220px;
  overflow-y: auto;
  margin-top: 4px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.autocomplete-suggestions.visible {
  display: block;
}

.autocomplete-suggestions .suggestion-item {
  padding: 8px 12px;
  font-size: 14px;
  cursor: pointer;
}

.autocomplete-suggestions .suggestion-item:hover {
  background: var(--primary);
  color: #fff;
}

input[type="email"],
input[type="password"],
input[type="text"],
input[type="number"],
input[type="date"],
input[type="datetime-local"],
input[type="tel"],
.field select,
.field textarea,
.field-grid select,
.field-grid textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  outline: none;
  transition: border-color 0.15s ease;
}

.field textarea,
.field-grid textarea {
  font-family: inherit;
  resize: vertical;
}

/* Vanilla-JS WYSIWYG (contenteditable + execCommand) für HTML-Vorlagentexte
   (Mandanten → Microsoft 365 → HTML-Signatur; Systemeinstellungen →
   E-Mail-Vorlagentexte) — kein externes Editor-Paket, siehe
   systemeinstellungen.js/mandanten.js initHtmlEditors(). Die eigentliche
   versteckte <textarea> bleibt die Quelle der Wahrheit für Laden/Speichern,
   der Editor spiegelt nur ihren Inhalt. */
.html-editor {
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}

.html-editor-toolbar {
  display: flex;
  gap: 4px;
  padding: 6px;
  background: var(--bg-muted, #f3f4f6);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}

.html-editor-toolbar button {
  /* Überschreibt das globale "button { width: 100% }" (siehe oben) —
     sonst zwingt flex-wrap jeden Button mangels Breitenbegrenzung in eine
     eigene Zeile, statt sie nebeneinander anzuordnen. */
  width: auto;
  flex: 0 0 auto;
  padding: 4px 10px;
  font-size: 13px;
  font-weight: 400;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  color: var(--text);
  cursor: pointer;
}

.html-editor-toolbar button:hover {
  background: var(--bg-muted, #f3f4f6);
}

.html-editor-body {
  min-height: 140px;
  max-height: 320px;
  overflow-y: auto;
  padding: 10px 12px;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  outline: none;
}

.html-editor-body ul,
.html-editor-body ol {
  margin: 0 0 0 20px;
  padding: 0;
}

/* Read-only raw text blocks (api-anfragen.html's request detail modal:
   full rawcommand/headers/content) — monospace, wraps instead of
   overflowing horizontally, scrolls internally past a certain height
   rather than growing the modal indefinitely for very long header lists. */
.raw-block {
  width: 100%;
  max-height: 240px;
  /* Only ever scrolls vertically (long header lists) — overflow-wrap:
     anywhere forces even one continuous unbroken token (e.g. a long
     rawcommand URL with no spaces) to break and wrap instead of causing
     horizontal overflow, so nothing is ever cut off to the side. */
  overflow-y: auto;
  overflow-x: hidden;
  margin: 0;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: break-word;
}

input:focus,
.field select:focus,
.field textarea:focus,
.field-grid select:focus,
.field-grid textarea:focus {
  border-color: var(--primary);
}

.password-input-wrap {
  position: relative;
}

.password-input-wrap input {
  padding-right: 42px;
}

.password-toggle {
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  width: auto;
  background: transparent;
  border: none;
  padding: 6px 8px;
  font-size: 15px;
  line-height: 1;
  color: var(--text-muted);
  cursor: pointer;
}

.password-toggle:hover {
  color: var(--text);
}

button {
  width: 100%;
  padding: 11px 12px;
  border: none;
  border-radius: 8px;
  background: var(--primary);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, opacity 0.15s ease;
}

button:hover:not(:disabled) {
  background: var(--primary-hover);
}

button:disabled {
  opacity: 0.6;
  cursor: default;
}

.error-banner {
  display: none;
  background: var(--danger-bg);
  color: var(--danger);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 13px;
  margin-bottom: 16px;
}

.error-banner.visible {
  display: block;
}

/* Dashboard */
.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 24px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  /* Always fixed at the top on every page while scrolling. */
  position: sticky;
  top: 0;
  z-index: 20;
}

.app-main {
  padding: 32px 24px;
  /* Standing rule: every form/page uses the full browser width so nothing
     is ever clipped (see .app-main--table-page's note) — no cap here by
     default. A page that genuinely wants a narrow centered layout (none
     currently do) can still add a modifier class with its own max-width. */
  max-width: none;
  margin: 0 auto;
}

.user-chip {
  display: flex;
  align-items: center;
  gap: 10px;
}

.avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 600;
}

.logout-link {
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
  width: auto;
  padding: 7px 14px;
  font-weight: 500;
}

.logout-link:hover:not(:disabled) {
  background: var(--bg);
  color: var(--text);
}

.status-line {
  color: var(--text-muted);
  font-size: 13px;
}

.info-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 24px;
  max-width: 460px;
}

.info-panel h2 {
  font-size: 15px;
  margin: 0 0 14px;
}

.info-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 14px;
  color: var(--text);
}

.info-value {
  font-size: 22px;
  font-weight: 700;
  color: var(--primary);
}

.dashboard-row {
  display: flex;
  align-items: flex-start;
  gap: 24px;
  flex-wrap: wrap;
}

.dashboard-row__right {
  /* Grow to fill whatever width remains next to the Info panel, so the
     tile count below can respond to the actual browser width instead of
     staying fixed at 5. Override .info-panel's 460px cap, which would
     otherwise block that growth. */
  flex: 1 1 480px;
  min-width: 0;
  max-width: none;
}

.dashboard-col {
  display: flex;
  flex-direction: column;
  gap: 24px;
  /* align-items: stretch (the flex default) so Zeiterfassung and Info
     both take the width of the wider of the two, instead of each
     shrink-wrapping to its own (different) content width. */
  align-items: stretch;
}

.zeiterfassung-panel .info-row {
  margin-bottom: 10px;
}

.zeiterfassung-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  margin-top: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
}

.zeiterfassung-btn:hover:not(:disabled) {
  background: var(--bg);
}

.zeiterfassung-icon {
  display: inline-block;
  width: 14px;
  height: 14px;
}

.zeiterfassung-icon--start {
  /* Green triangle pointing right — "play"/Start. */
  width: 0;
  height: 0;
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  border-left: 13px solid var(--primary);
}

.zeiterfassung-icon--stop {
  /* Red square — "stop". */
  background: var(--danger);
  border-radius: 2px;
}

.peer-grid {
  display: grid;
  /* auto-fit + 1fr: as many 240px-min columns as fit the panel's width,
     stretched to fill it completely; columns are added/removed
     automatically as the browser window is resized. */
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
}

/* Gruppen-Sub-Panels auf dem Dashboard-Nebenstellenpanel (siehe
   dashboard.js buildPeerGridHtml()) — einfach untereinander im normalen
   Blockfluss, keine eigene Umrahmung (die Gruppierung macht allein die
   Überschrift plus der Abstand zum nächsten Sub-Panel). */
.peer-subpanel + .peer-subpanel {
  margin-top: 20px;
}

.peer-subpanel-title {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--text-muted);
}

/* Klickbarer Header, der das Sub-Panel ein-/ausklappt (siehe
   dashboard.js togglePeerGroupCollapse()) — <button> statt <h3> allein,
   damit die ganze Zeile (nicht nur der Text) klickbar ist. */
.peer-subpanel-header {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 0 0 8px;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
}

.peer-subpanel-chevron {
  font-size: 11px;
  color: var(--text-muted);
  width: 10px;
  flex-shrink: 0;
}

.peer-subpanel--collapsed .peer-subpanel-body {
  display: none;
}

.peer-subpanel-empty {
  font-size: 13px;
  color: var(--text-muted);
  font-style: italic;
}

.peer-tile {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  background: var(--bg);
  cursor: pointer;
  position: relative;
}

.peer-dnd-badge {
  position: absolute;
  top: 6px;
  right: 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--status-bad-bg);
  border: 1px solid var(--status-bad-border);
  color: var(--text);
}

.peer-desc {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.peer-number {
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
  margin-top: 4px;
}

.peer-tile--bad {
  background: var(--status-bad-bg);
  border-color: var(--status-bad-border);
}

.peer-tile--good {
  background: var(--status-good-bg);
  border-color: var(--status-good-border);
}

.peer-tile--ringing {
  border-color: var(--status-good-border);
  animation: peer-blink-green 1s step-start infinite;
}

.peer-tile--talking {
  background: var(--status-warn-bg);
  border-color: var(--status-warn-border);
  box-shadow: 0 0 12px 2px var(--status-warn-glow);
}

.peer-tile--offline-idle {
  background: var(--status-offline-idle-bg);
  border-color: var(--status-offline-idle-border);
}

.peer-context-menu {
  position: fixed;
  z-index: 1000;
  min-width: 160px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow);
  padding: 6px;
}

.peer-context-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 12px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
}

.peer-context-menu-item:hover:not(:disabled) {
  background: var(--bg);
}

@keyframes peer-blink-green {
  0%, 49% {
    background: var(--status-good-bg);
  }
  50%, 100% {
    background: var(--surface);
  }
}

.call-direction-icon {
  display: inline-block;
  font-weight: 900;
  font-size: 1.3em;
  color: #e8c547;
  animation: call-direction-blink 1s step-start infinite;
}

@keyframes call-direction-blink {
  0%, 49% {
    opacity: 1;
  }
  50%, 100% {
    opacity: 0.2;
  }
}

/* Nav */
.app-nav {
  display: flex;
  gap: 4px;
  flex: 1;
  margin-left: 24px;
}

.nav-link {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 13px;
  font-weight: 500;
  padding: 7px 12px;
  border-radius: 8px;
}

.nav-link:hover {
  background: var(--bg);
  color: var(--text);
}

.nav-link.active {
  background: var(--bg);
  color: var(--text);
}

.nav-dropdown {
  position: relative;
}

.nav-dropdown-toggle {
  width: auto;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  padding: 7px 12px;
  border-radius: 8px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.nav-dropdown-toggle:hover,
.nav-dropdown.open .nav-dropdown-toggle,
.nav-dropdown-toggle.active {
  background: var(--bg);
  color: var(--text);
}

.nav-dropdown-menu {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow);
  min-width: 170px;
  padding: 6px;
  z-index: 20;
}

.nav-dropdown.open .nav-dropdown-menu {
  display: block;
}

.nav-dropdown-item {
  display: block;
  padding: 8px 10px;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  font-size: 13px;
}

.nav-dropdown-item:hover {
  background: var(--bg);
}

/* Hidden by default (not just hidden-then-shown via JS) so owner-only nav
   items never flash visible before license-gate.js's isOwner() check
   resolves — assets/license-gate.js reveals this again (removes the class)
   once it confirms the current user is us_isowner. Not currently applied
   to any nav item (see .owner-or-admin-nav below for "Lizenzen"), kept for
   any future nav item that needs owner-only, not owner-or-admin, visibility. */
.owner-only-nav {
  display: none;
}

/* Same idea as .owner-only-nav, for "Lizenzen verwalten" specifically —
   revealed only for adm_user.us_isadmin, not us_isowner (a narrower,
   separate flag, see MandantController::isAdmin()). */
.admin-only-nav {
  display: none;
}

/* Same idea again, for nav items that should be visible to EITHER
   us_isowner OR us_isadmin (currently just "Lizenzen") — distinct from
   .owner-only-nav/.admin-only-nav, which each require their one specific
   flag. */
.owner-or-admin-nav {
  display: none;
}

/* Same "hidden until proven allowed" default as .owner-only-nav, for
   every regular license-gated nav item — the default is that NOTHING is
   licensed until a Mandanten-Inhaber actively subscribes (see
   lizenzen.html), so nav items must never flash visible first.
   assets/license-gate.js removes this class once a link's target is
   confirmed licensed (or isn't gated at all). */
.gated-nav {
  display: none;
}

.nav-dropdown-item.active {
  background: var(--bg);
  font-weight: 600;
}

/* Trennlinie zwischen zwei Gruppen von Einträgen innerhalb eines
   Dropdown-Menüs (aktuell im WaWi-Menü zwischen Angebot/Auftrag/
   Rechnung/Wiederkehrende Vorgänge und Zahlungen/Dokumente/Bestellungen). */
.nav-dropdown-separator {
  margin: 4px 6px;
  border-top: 1px solid var(--border);
}

/* user-chip's "Anmeldename"-Dropdown (users-name/avatar als Toggle,
   enthält "Passwort ändern" + "Abmelden") — sitzt ganz rechts im Header,
   braucht daher ein rechtsbündiges Menü statt des Standard-left:0, und der
   Toggle selbst übernimmt Avatar+Name statt eines Textlabels. */
#user-menu-dropdown .nav-dropdown-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 8px 4px 4px;
  /* Überschreibt .nav-dropdown-toggles color:var(--text-muted) — #user-name
     hat selbst keine eigene color, würde die sonst erben und (statt der
     normalen Textfarbe) gedimmt wirken. */
  color: var(--text);
}

#user-menu-dropdown .nav-dropdown-menu {
  left: auto;
  right: 0;
  min-width: 180px;
}

#user-menu-dropdown .nav-dropdown-item--button {
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  font: inherit;
  cursor: pointer;
}

/* Klickbares Untermenü innerhalb eines Dropdown-Menüs (z. B. "System"/
   "Stammdaten" im WaWi-Menü) — eine zweite Ebene, die erst beim Klick auf
   ihre eigene Toggle-Zeile aufklappt (siehe assets/nav.js), nicht
   automatisch beim Öffnen des übergeordneten Dropdowns. */
.nav-submenu:not(:first-child) {
  margin-top: 4px;
  border-top: 1px solid var(--border);
  padding-top: 4px;
}

.nav-submenu-toggle {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  background: transparent;
  border: none;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
}

.nav-submenu-toggle:hover {
  background: var(--bg);
}

/* Pfeil dreht sich beim Aufklappen (dieselbe ▾-Glyphe wie bei den
   Hauptmenü-Toggles, nur gespiegelt statt ausgetauscht). */
.nav-submenu-toggle span {
  transition: transform 0.15s ease;
}

.nav-submenu.open .nav-submenu-toggle span {
  transform: rotate(180deg);
}

.nav-submenu-items {
  display: none;
  padding-left: 10px;
}

.nav-submenu.open .nav-submenu-items {
  display: block;
}

.app-main--wide {
  /* Legacy name, no longer actually narrower — standing rule is full
     browser width for every form/page (see .app-main--table-page's note),
     this class is kept only so existing pages don't need a markup change. */
  max-width: none;
}

.app-main--anrufe {
  /* Full browser width instead of the standard table pages' 1100px cap —
     the Anrufe table has more columns (inkl. E-Mail-Button) and larger
     row font-size than a fixed-width container comfortably fits. */
  max-width: none;
}

.app-main--kontakte {
  /* Same reasoning as .app-main--anrufe — seven columns don't fit
     comfortably under the standard table pages' 1100px cap. */
  max-width: none;
}

.app-main--m365 {
  /* Full browser width on request — table.data-table's default
     table-layout:auto already sizes columns by content, this just gives
     it the room to do that instead of squeezing under the 1100px cap. */
  max-width: none;
}

.app-main--kunden {
  /* Full browser width — every new form defaults to this now (standing
     request), not just the table-heavy pages above. */
  max-width: none;
}

.app-main--jobzeiten {
  max-width: none;
}

.app-main--besprechungsraeume {
  max-width: none;
}

/* Standard for every new form/page with a table going forward — use this
   instead of adding another one-off .app-main--<page> rule like the ones
   above. Full browser width by default (standing request), see
   .app-main--kunden's note for the same reasoning. */
.app-main--table-page {
  max-width: none;
}

.app-main--mobzeit {
  /* Full browser width, like the site-wide table-page standard —
     the Zeitbuchungen table should use all available width instead of
     being capped to a narrow mobile-card column. */
  max-width: none;
  padding: 16px;
}

/* Scoped to /mobzeit only (body.mobzeit-page) — the shared .app-header
   layout (brand / mandant-select / user-chip in one row) is built for
   desktop widths and overflows badly on a phone. Every other page keeps
   the unscoped desktop layout; this is the one page meant to be used on
   an actual phone, so the breakpoint is deliberately wide (600px, not
   just ~480px) to also catch larger phones and landscape orientation.
   Previous version still let the header wrap to two rows on narrower
   phones (name/email pushing the layout past one line) — net *taller*
   header than the unscoped default it was trying to shrink. Fix: drop
   the redundant "UniMDM" wordmark and the e-mail line entirely on this
   breakpoint (the icon + name + logout are all that's needed on a phone)
   so the whole header reliably fits in one compact, non-wrapping row. */
@media (max-width: 600px) {
  .mobzeit-page .app-header {
    flex-wrap: nowrap;
    padding: 6px 10px;
  }

  .mobzeit-page .brand-name {
    display: none;
  }

  .mobzeit-page .brand-mark,
  .mobzeit-page .avatar {
    width: 24px;
    height: 24px;
    font-size: 11px;
    flex-shrink: 0;
  }

  /* Fills the rest of the header row (only .brand's icon sits to its
     left now, .brand-name is hidden) — min-width:0 lets the name
     truncate with ellipsis instead of forcing the row to wrap/overflow;
     margin-left:auto on .logout-link pushes just that to the far right. */
  .mobzeit-page .user-chip {
    flex: 1 1 auto;
    gap: 6px;
    min-width: 0;
  }

  .mobzeit-page .user-chip > div {
    min-width: 0;
    overflow: hidden;
  }

  .mobzeit-page .user-chip > div > div:first-child {
    font-size: 12px !important;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .mobzeit-page .user-chip .status-line {
    display: none;
  }

  .mobzeit-page .logout-link {
    font-size: 12px;
    margin-left: auto;
    flex-shrink: 0;
  }

  .mobzeit-page .app-main--mobzeit {
    padding: 12px;
  }

  .mobzeit-page .row-actions {
    flex-direction: column;
    align-items: stretch;
  }

  .mobzeit-page .row-actions button {
    width: 100%;
  }
}

.app-main--dashboard {
  /* Wider than the standard table pages so the doubled-width
     Nebenstellen tiles fit next to the Info panel without wrapping. */
  max-width: 1700px;
}

.mandant-select {
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font-size: 13px;
  max-width: 200px;
  margin-right: 16px;
}

/* Toolbar */
.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}

/* A bare <select> dropped directly into .toolbar (filter dropdowns, e.g.
   jobzeiten-verwaltung.html's Abgerechnet/Freigegeben/Kunde filters) had
   no styling of its own — only .field select (inside a modal form) and
   .mandant-select (header) were covered, so these rendered in the raw
   browser-default look instead of matching the rest of the form. */
.toolbar select {
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
}

.toolbar select:focus {
  border-color: var(--primary);
  outline: none;
}

/* A plain <label> inline in .toolbar (e.g. "Abgerechnet" before its
   filter dropdown) — overrides the global label rule's display:block/
   margin-bottom, which would otherwise misalign it against the select
   sitting next to it in the same flex row. */
.toolbar-label {
  display: inline;
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}

/* Groups a .toolbar-label with its select tightly (small gap) — .toolbar
   itself uses a larger gap meant to separate whole filter groups from
   each other, not a label from its own dropdown. */
.toolbar-filter {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Extra spacing specifically between two adjacent filter groups (e.g.
   Freigegeben right after Abgerechnet) — 8px here + .toolbar's own 12px
   gap = 20px total between the groups. */
.toolbar-filter + .toolbar-filter {
  margin-left: 8px;
}

/* m365-kontakte.html only: the toolbar itself no longer needs to be
   sticky — it lives outside .table-card--m365's own bounded scroll box
   (see below), so it's never scrolled away in the first place. */

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 16px;
}

.toolbar input[type="search"] {
  width: 260px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font-size: 14px;
  outline: none;
}

.toolbar-left select {
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font-size: 14px;
  outline: none;
}

.toolbar-left select:focus {
  border-color: var(--primary);
}

.toolbar input[type="search"]:focus {
  border-color: var(--primary);
}

.toolbar-checkbox {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text);
  white-space: nowrap;
  cursor: pointer;
}

.toolbar-checkbox input {
  width: auto;
}

.btn {
  width: auto;
  padding: 9px 16px;
}

.btn-secondary {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
}

.btn-secondary:hover:not(:disabled) {
  background: var(--bg);
}

/* Data table — standard for every table-card on the site (not just one
   page): a bounded height + its own vertical scrollbar makes .table-card
   itself the genuine scroll container for its sticky thead (top:0 below)
   — far more robust than trying to dock a sticky thead under a separately
   sticky toolbar/header stack via JS-measured pixel offsets (that
   approach broke: nested sticky elements at different container levels
   fought each other on reflow/paint). Whatever sits above the table
   (search bar, buttons, filters) never scrolls away since it's outside
   this box; only the rows inside it scroll — first established on
   m365-kontakte.html, now the default for all of them. */
.table-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow-x: auto;
  /* Fills the rest of the browser window below the sticky .app-header,
     toolbar, and page padding (~220px of chrome above .table-card on a
     typical table page) down to the bottom edge, rather than a fixed
     percentage of the window — recalculates automatically on resize,
     pure CSS. */
  max-height: calc(100vh - 220px);
  overflow-y: auto;
}

.table-card--fit {
  /* Shrink-wrap to the table's actual rendered width instead of always
     stretching to the full (now uncapped) app-main--anrufe width — capped
     at 100% so overflow-x:auto still kicks in if the table is wider than
     the viewport, and centered within the page. */
  width: fit-content;
  max-width: 100%;
  margin: 0 auto;
}

/* anrufe.html: wraps the date-filter row together with .table-card--fit so
   both shrink-wrap and center as one unit — without this, the filter row
   (naturally left-aligned, full-width parent) drifts away from the
   .table-card--fit table beneath it (shrink-wrapped, centered) once
   .app-main--anrufe removes the page's max-width. The nested .field-row
   width:100% then resolves against this wrapper's fit-content width, i.e.
   the table's own rendered width, so the date fields sit flush above it. */
.anrufe-content {
  width: fit-content;
  max-width: 100%;
  margin: 0 auto;
}

.anrufe-content .field-row {
  width: 100%;
}

table.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.data-table th,
.data-table td {
  text-align: left;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

/* bestellungen.html's Positionen-Ansicht (#positions-view-table): eine
   lange Artikelbezeichnung sprengt sonst per white-space:nowrap die
   Tabellenbreite über den Viewport hinaus (die Spalte wird einfach immer
   breiter statt umzubrechen) — das erzwingt horizontales Scrollen trotz
   .modal--wide, da dessen max-width:none nur die OBERGRENZE aufhebt,
   nicht den Inhalt selbst schmaler macht. Umbruch statt einer Zeile löst
   das: lange Texte wachsen nach unten (mehr Zeilenhöhe), nicht mehr nach
   rechts (mehr Tabellenbreite). */
#positions-view-table th,
#positions-view-table td {
  white-space: normal;
  word-break: break-word;
}

/* Art.Nr. (erste Spalte) bleibt immer einzeilig — anders als die
   Artikelbezeichnung ist sie kurz und soll nicht mitten im Code umbrechen. */
#positions-view-table th:first-child,
#positions-view-table td:first-child {
  white-space: nowrap;
}

.data-table th {
  color: var(--text-muted);
  font-weight: 500;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  /* Standard for every data-table: stays pinned to .table-card's own
     scrollport (see .table-card above) while the rows beneath scroll. */
  position: sticky;
  top: 0;
  z-index: 14;
  background: var(--surface);
}

.data-table tbody tr:last-child td {
  border-bottom: none;
}

.data-table th.sortable {
  cursor: pointer;
  user-select: none;
}

.data-table th.sortable:hover {
  color: var(--text);
}

.data-table th.sortable .sort-arrow {
  display: inline-block;
  margin-left: 4px;
  opacity: 0.6;
}

/* Zweite thead-Zeile mit Filter-Inputs/-Selects direkt über ihrer Spalte
   (siehe zahlungen.html) — ebenfalls sticky, aber NICHT auf top:0 wie die
   normale th-Kopfzeile: zwei unabhängig auf denselben top-Wert fixierte
   Zeilen würden sich beim Scrollen gegenseitig überlagern statt sich zu
   stapeln. --filter-row-top wird daher von zahlungen.js aus der
   tatsächlich gerenderten Höhe der ersten Kopfzeile gesetzt (siehe
   updateFilterRowStickyOffset()) statt hier einen Pixelwert zu raten, der
   bei abweichender Schriftdarstellung/Zoom nicht mehr passt. */
.filter-row th {
  position: sticky;
  top: var(--filter-row-top, 42px);
  z-index: 13;
  background: var(--surface);
  padding: 6px 16px;
  text-transform: none;
}

.filter-row select,
.filter-row input {
  width: 100%;
  font-size: 13px;
  font-weight: normal;
}

.data-table tbody tr:hover {
  background: var(--bg);
}

.data-table--large {
  font-size: 38px;
}

.data-table--large th {
  font-size: 15px;
}

.data-table--kontakte {
  /* Double the row text size on request — kontakte.html's own modifier,
     kept separate from .data-table--large (anrufe.html) so tuning one
     doesn't affect the other. */
  font-size: 76px;
}

.data-table--kontakte th {
  font-size: 15px;
}

.data-table--jobzeiten th:nth-child(3),
.data-table--jobzeiten td:nth-child(3) {
  /* Beschreibung-Spalte auf Wunsch fest auf 700px — kombiniert mit
     .data-table td.wrap (white-space:normal), sonst würde die nowrap
     Textzeile die Spalte trotz width breiter aufziehen. */
  width: 700px;
}

.data-table--posteingang {
  /* Fixed layout so the table always fills .table-card's full width
     instead of shrink-wrapping to content (the default table-layout:auto
     behavior) — the narrow columns get an explicit width and Betreff
     (the 4th column, no width set) absorbs all remaining space. */
  table-layout: fixed;
}

.data-table--posteingang th:nth-child(1),
.data-table--posteingang td:nth-child(1) {
  width: 32px;
}

.data-table--posteingang th:nth-child(2),
.data-table--posteingang td:nth-child(2),
.data-table--posteingang th:nth-child(3),
.data-table--posteingang td:nth-child(3) {
  width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.data-table--posteingang th:nth-child(4),
.data-table--posteingang td:nth-child(4) {
  overflow: hidden;
  text-overflow: ellipsis;
}

.data-table--posteingang th:nth-child(5),
.data-table--posteingang td:nth-child(5) {
  width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.data-table--posteingang th:nth-child(6),
.data-table--posteingang td:nth-child(6) {
  width: 120px;
}

.data-table--posteingang th:nth-child(7),
.data-table--posteingang td:nth-child(7) {
  /* Wider than the other action columns in the app — this one holds four
     buttons ("Öffnen" / "Als EML exportieren" / "Erledigt" / "Löschen"),
     not one. .row-actions wraps to a second line if they still don't fit. */
  width: 260px;
}

.kontakt-mailto,
.kontakt-mailto:visited {
  color: #e0b400;
}

.kontakt-call,
.kontakt-call:visited {
  color: #90ee90;
}

.kontakt-whatsapp {
  text-decoration: none;
  filter: grayscale(0%);
}

.row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.row-actions button {
  width: auto;
  padding: 5px 10px;
  font-size: 12px;
}

/* Icon-only Aktionsbuttons (Bearbeiten/Druck/Mail/Wiederkehrend/
   Stornieren in Angebote/Aufträge/Rechnungen/Gutschriften) — größere
   Schrift als .row-actions button's 12px, damit das Emoji selbst gut
   erkennbar bleibt, engerer Innenabstand, da kein Textlabel mehr
   Breite braucht. Der Tooltip (title-Attribut) trägt weiterhin die
   Beschriftung für Barrierefreiheit/Klarheit. */
.row-actions button.icon-btn {
  padding: 4px 10px;
  font-size: 22px;
  line-height: 1;
}

/* Two-<tr>-per-record layout (booking tables) — action buttons sit in
   their own full-width row directly below the data row instead of a
   cramped trailing column. No border between the pair so they read as
   one record; the border after .booking-actions-row (inherited from the
   default td/th rule) separates one record from the next. */
.booking-content-row td {
  border-bottom: none;
  padding-bottom: 6px;
}

.booking-actions-row td {
  padding-top: 0;
}

.badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
}

.badge-active {
  background: var(--badge-active-bg);
  color: var(--badge-active-text);
}

.badge-inactive {
  background: color-mix(in srgb, var(--text-muted) 18%, transparent);
  color: var(--text-muted);
}

/* Badge als klickbarer <button> statt <span> — gleiche Optik, aber mit
   Cursor/Hover-Hinweis, dass ein Klick etwas auslöst (siehe sip-accounts.js
   Status-Spalte für TAPI-Nebenstellen: direktes Umschalten Aktiv/Inaktiv). */
.badge-button {
  border: none;
  font-family: inherit;
  cursor: pointer;
  transition: filter 0.1s ease;
}

.badge-button:hover {
  filter: brightness(0.92);
}

.badge-button:disabled {
  cursor: default;
  filter: none;
  opacity: 0.7;
}

.price-trend {
  font-size: 12px;
  margin-left: 2px;
}

.price-trend-up {
  color: #d1453b;
}

.price-trend-down {
  color: #2e7d32;
}

.category-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.category-badge-remove {
  cursor: pointer;
}

.category-badge-remove:hover {
  filter: brightness(0.92);
}

.empty-state {
  padding: 40px 16px;
  text-align: center;
  color: var(--text-muted);
  font-size: 14px;
}

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 16px;
  border-top: 1px solid var(--border);
}

.pagination button {
  width: auto;
}

.pagination button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Modal */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(16, 20, 28, 0.5);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px;
  /* Above .app-header (now sticky, z-index:20 — see below) so the modal
     dims/covers it too, not just the page content beneath the header. */
  z-index: 50;
}

.modal-overlay.visible {
  display: flex;
}

.modal {
  width: 100%;
  /* Standing rule: forms should always be wide enough that nothing is
     cramped into one narrow column — was a fixed 440px, which every
     multi-field edit form on the site (users, mandanten, telefonaccounts,
     relay-agenten, besprechungsraeume, displays, lizenzen, zahlungen, ...)
     inherited by default since only a handful of pages had ever gotten
     their own wider override. Went 440 -> 900 -> 1800 -> settled at
     1200px on explicit request. min(92vw, 1200px) keeps it from
     overflowing on narrow viewports while giving every modal room for a
     .field-row-2 two-column layout instead of one cramped column. Pages
     with heavier content (CSV-Mapping-Tabelle, Bestellpositionen, ...)
     still set their own id-/class-scoped override above/below this. */
  max-width: min(92vw, 1200px);
  max-height: 90vh;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 28px;
}

#mail-modal-overlay .modal {
  /* Double the standard 440px modal width on request — the "E-Mail zum
     Anruf" form's Text textarea felt cramped at the default width. */
  max-width: 880px;
}

#edit-modal-overlay .modal {
  /* jobzeiten-verwaltung.html's Start/Stop datetime-local pair
     (.field-row-2) needs more than half of the standard 440px width each
     to show "DD.MM.YYYY, --:--" without clipping. */
  max-width: 560px;
}

.modal--mail-detail {
  /* Same doubling for the Posteingang detail modal's HTML body iframe. */
  max-width: 880px;
}

#csv-modal-overlay .modal {
  /* Mapping-Tabelle braucht deutlich mehr Breite als das
     Standard-440px-Formular — bei 720/900px wurden lange Feldlabels
     ("Gesamtbetrag (Bestellkopf)" etc.) und die Select-Werte abgeschnitten
     bzw. quetschten sich zusammen. */
  max-width: 1100px;
}

#bestellung-modal-overlay .modal {
  /* Die Positionstabelle hat mit Steuersatz jetzt 6 Spalten + Entfernen-
     Button — bei 720/1040px liefen die Eingabefelder ineinander/wurden
     abgeschnitten. Deutlich breiter, damit die ganze Zeile (inkl. Artikel-
     und Artikelnummer-Spalte, die den restlichen Platz bekommen) ohne
     horizontales Scrollen sichtbar ist. */
  max-width: 1300px;
}

#positions-modal-overlay .modal {
  /* Auf Wunsch begrenzt auf 2/3 des gesamten Browserfensters, statt
     (wie modal--wide es sonst täte) auf die volle Breite zu gehen. */
  max-width: 66.666vw;
}

.data-table--positions th,
.data-table--positions td {
  padding: 6px 4px;
}

.data-table--mapping th,
.data-table--mapping td {
  padding: 6px 8px;
}

.data-table--positions input {
  width: 100%;
  box-sizing: border-box;
}

/* bestellungen.html's USt-Feld (pos-steuersatz) ist bei 45px zu schmal für
   die nativen Auf/Ab-Pfeile eines number-Inputs — die nehmen dort fast die
   halbe Breite ein und lassen für die Ziffern kaum Platz. */
.pos-steuersatz {
  -moz-appearance: textfield;
}

.pos-steuersatz::-webkit-outer-spin-button,
.pos-steuersatz::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Mengenfelder (bestellungen.html/angebote.html/auftraege.html) — gleiche
   Begründung wie .pos-steuersatz oben, nur hier zusätzlich, weil die
   Pfeile bei einer Menge (meist einstellig/zweistellig) ohnehin kaum
   gebraucht werden. */
.pos-menge {
  -moz-appearance: textfield;
}

.pos-menge::-webkit-outer-spin-button,
.pos-menge::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* EK-/VK-Felder (angebote.html/auftraege.html) — gleiche Begründung wie
   .pos-menge/.pos-steuersatz oben. */
.pos-ek,
.pos-vk {
  -moz-appearance: textfield;
}

.pos-ek::-webkit-outer-spin-button,
.pos-ek::-webkit-inner-spin-button,
.pos-vk::-webkit-outer-spin-button,
.pos-vk::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.data-table--mapping select {
  width: 100%;
}

.data-table--mapping td:first-child {
  /* Feste Breite für die Feldnamen-Spalte, damit lange Labels wie
     "Gesamtbetrag (Bestellkopf)" nicht mehr umbrechen und die Select-
     Spalte (CSV-Spaltenname) den restlichen Platz zur vollen Lesbarkeit
     bekommt. */
  width: 260px;
  white-space: nowrap;
}

/* kunden.html and lieferanten-verwaltung.html previously had their own
   body-scoped .modal width overrides (1120px / 880px) for forms with
   several .field-row-2 pairs that clipped at the old 440px default —
   both removed since the site-wide .modal default above (now 1800px) is
   already wider than either needed. */

/* kontakte.html's Kontakt-Formular on request: fills the site width
   instead of the standard narrow centered modal — .modal-overlay's own
   24px padding is the only remaining margin. */
.modal--wide {
  max-width: none;
}

.modal--wide #kontakt-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0 20px;
}

.modal--wide #kontakt-form #account-field,
.modal--wide #kontakt-form .field-hint,
.modal--wide #kontakt-form .modal-actions {
  grid-column: 1 / -1;
}

/* artikel-verwaltung.html's Artikel-Formular on request: same side-by-side
   grid as #kontakt-form above, but scoped to #artikel-form so it doesn't
   affect any other .modal--wide form. Wide enough that even with two
   36-40ch-label fields per row (e.g. "Alternative Artikelnummer" /
   "Mindestbestellmenge") nothing clips — same reasoning as
   #edit-modal-overlay/body.kunden-page above, just via the reusable
   .modal--wide class instead of a page-specific id/body-class override. */
.modal--wide #artikel-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0 20px;
}

.modal--wide #artikel-form .field-full,
.modal--wide #artikel-form .checkbox-field,
.modal--wide #artikel-form .modal-actions {
  grid-column: 1 / -1;
}

/* kontakte.html: the table-card fills the rest of the browser window
   below the sticky .app-header, and its pagination footer lives *inside*
   that box (not a separate element below it) so it's always visible —
   never pushed below the fold by however many rows are showing, and
   never scrolled away with them. Only app-header's own height (~70px,
   the one number that's genuinely constant across every page) is
   hardcoded; everything else sizes itself via flex. */
.app-main--fill {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 70px);
}

.app-main--api-anfragen {
  /* Full browser width on request, same reasoning as .app-main--anrufe/
     .app-main--kontakte — the standard 1100px cap left the Befehl column
     too cramped. */
  max-width: none;
}

/* api-anfragen.html's Befehl column: wraps instead of forcing horizontal
   scroll, unlike every other data-table column (base .data-table td is
   white-space:nowrap) — a long request line should grow the row's height,
   not the table's width. */
.data-table td.wrap {
  white-space: normal;
  word-break: break-word;
}

/* displays.html's Bild-Link column — plain yellow instead of the browser's
   default blue/underlined link color. */
#bild-rows a {
  color: #f5c518;
}

.table-card--paginated {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  /* Overrides the base .table-card's own overflow/max-height — this
     variant's inner .table-scroll manages scrolling instead. hidden (not
     visible) keeps the card's own rounded corners clean; .table-scroll's
     own overflow:auto is what actually lets rows scroll, and the
     pagination footer below sits outside .table-scroll so hidden here
     never clips it. */
  max-height: none;
  overflow: hidden;
}

.table-card--paginated .table-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
}

.table-card--paginated .pagination {
  flex: 0 0 auto;
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
}

.modal-header h2 {
  font-size: 16px;
  margin: 0;
}

.modal-close {
  width: auto;
  background: transparent;
  color: var(--text-muted);
  padding: 4px 8px;
  font-size: 18px;
  line-height: 1;
}

.modal-close:hover {
  background: var(--bg);
  color: var(--text);
}

.modal-actions {
  display: flex;
  gap: 10px;
  margin-top: 8px;
}

.modal-actions button {
  flex: 1;
}

.field-hint {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 4px;
}

.checkbox-field {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
}

.checkbox-field input {
  width: auto;
}

/* Einklappbarer Formularabschnitt (z. B. "Integrationen" in
   mandanten.html) — natives <details>, gleiche Pfeil-Mechanik wie
   .faq-category, aber ohne Card-Schatten/Hintergrund, da bereits in einem
   Modal/einer Karte verschachtelt. */
.form-section {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 16px;
  padding: 4px 16px;
}

.form-section > summary {
  cursor: pointer;
  font-weight: 600;
  padding: 12px 0;
  list-style: none;
}

.form-section > summary::-webkit-details-marker {
  display: none;
}

.form-section > summary::before {
  content: "▸";
  display: inline-block;
  width: 1em;
  color: var(--text-muted);
}

.form-section[open] > summary::before {
  content: "▾";
}

.form-section-body {
  padding-bottom: 8px;
}

/* artikel-verwaltung.html's Preise/Menge & Lagerbestand/Abmessungen &
   Gewicht-Panels: Label links neben dem Feld statt darüber (auf Wunsch),
   UND alle Eingabefelder innerhalb eines Panels gleich eingerückt — die
   Label-Spalte (max-content) richtet sich automatisch an der breitesten
   Bezeichnung des Panels aus (CSS Grid statt einzelner Flexboxen pro
   Feld, da Grid-Spaltenbreiten über mehrere "Zeilen" hinweg geteilt
   werden, einzelne Flexboxen das nicht können). Zusatzelemente wie
   Hinweistexte/Trend-Badge nehmen per grid-column:1/-1 eine eigene volle
   Zeile ein. */
.field-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 8px;
  row-gap: 10px;
  align-items: center;
}

.field-grid label {
  margin-bottom: 0;
  white-space: nowrap;
}

.field-grid .field-hint,
.field-grid .field-full-row {
  grid-column: 1 / -1;
}

/* Wie .field-grid, aber zwei Label+Feld-Paare pro "Zeile" (z. B. Firma /
   Vorname+Nachname / Straße / PLZ+Ort, siehe angebote.html/auftraege.html)
   — 4 Grid-Spalten (max-content 1fr max-content 1fr) statt zweier
   unabhängiger .field-grid-Instanzen pro Paarzeile, deren Label-Spalten
   sonst unterschiedlich breit wären (z. B. "Firma" schmaler als
   "Vorname") und die Eingabefelder dadurch gegeneinander versetzt
   stünden, obwohl sie untereinanderstehen sollen. Ein Feld, das die
   ganze Zeile einnehmen soll (z. B. Firma, Straße), bekommt
   grid-column:2/-1. */
.field-grid-pairs {
  display: grid;
  grid-template-columns: max-content 1fr max-content 1fr;
  column-gap: 8px;
  row-gap: 10px;
  align-items: center;
}

.field-grid-pairs label {
  margin-bottom: 0;
  white-space: nowrap;
}

/* mandanten.html "E-Mailempfang": vier gleich aufgebaute Zeilen
   (Checkbox + erzeugte Adresse + Beschreibung + Original-Adresse)
   innerhalb eines .form-section. */
.mailadresse-row + .mailadresse-row {
  border-top: 1px solid var(--border);
  padding-top: 12px;
  margin-top: 12px;
}

/* mail-eingang.html: ganze Zeile klickbar (öffnet die Detailansicht). */
.clickable-row {
  cursor: pointer;
}

.clickable-row:hover {
  background: var(--surface-hover, rgba(0, 0, 0, 0.03));
}

/* mail-eingang.html Detailansicht: einfache Label/Wert-Liste. */
.detail-list {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: 4px 12px;
  margin: 0 0 12px;
}

.detail-list dt {
  color: var(--text-muted);
  font-weight: 600;
}

.detail-list dd {
  margin: 0;
}

/* faq.html: one <details> per topic, containing one nested <details> per
   question — native disclosure widgets, so expand/collapse and keyboard
   handling come for free, no JS state needed beyond search filtering. */
.faq-category {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  margin-bottom: 16px;
  padding: 4px 16px;
}

.faq-category > summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 16px;
  padding: 12px 0;
  list-style: none;
}

.faq-category > summary::-webkit-details-marker {
  display: none;
}

.faq-category > summary::before {
  content: "▸";
  display: inline-block;
  width: 1em;
  color: var(--text-muted);
}

.faq-category[open] > summary::before {
  content: "▾";
}

.faq-articles {
  padding-bottom: 8px;
}

.faq-article {
  border-top: 1px solid var(--border);
  padding: 10px 0 10px 1.4em;
}

.faq-article > summary {
  cursor: pointer;
  list-style: none;
}

.faq-article > summary::-webkit-details-marker {
  display: none;
}

.faq-article-body {
  margin-top: 8px;
  color: var(--text-muted);
  line-height: 1.5;
  white-space: pre-line;
}

/* faq-verwaltung.html: one card per Kategorie, its Artikel listed as a
   normal .data-table inside — same visual language as the rest of the
   admin CRUD pages instead of a bespoke layout. */
.faq-kategorie-card {
  margin-bottom: 20px;
  max-height: none;
  overflow: visible;
}

.faq-kategorie-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 15px;
}

.checkbox-field label {
  margin: 0;
}

/* raum-buchen.html: same unauthenticated .center-screen/.card shell as
   index.html's login form, just wider — two side-by-side columns
   (booking details, contact details) don't fit .card's 380px
   login-form width. */
.card--split {
  max-width: 880px;
}

.field-row-2 {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 16px;
}

/* angebote.html/auftraege.html's Kundendaten-Schnappschuss: viele kurze
   .field-row-2/.field-grid-Zeilen hintereinander (Firma/Vorname,
   Nachname/Straße, PLZ/Ort, Mail/Telefon) — auf Wunsch enger als der
   sonst übliche 16px-Spaltenabstand, da diese Felder jeweils ohnehin
   schon schmal sind. */
#angebot-form .field-row-2,
#auftrag-form .field-row-2 {
  gap: 8px;
}

#angebot-form .field-grid,
#auftrag-form .field-grid {
  column-gap: 6px;
  row-gap: 6px;
}

/* Wie .field-row-2, nur drei statt zwei Spalten — z. B. artikel-
   verwaltung.html's breites Kopfdaten-Panel (Lieferant/Artikelnummer/
   Bezeichnung, darunter EAN/Hersteller/Herstellernummer). */
.field-row-3 {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 16px;
}

/* Wie .field-row-3, nur vier statt drei Spalten — artikel-verwaltung.html's
   EAN/Hersteller/Herstellernummer-Zeile samt "Hersteller per EAN
   suchen"-Button als vierte Spalte. */
.field-row-4 {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 16px;
}

/* m365-kontakte.html's edit form: Graph keeps businessPhones/homePhones/
   emailAddresses as arrays, so the form shows one row per existing value
   (not just the first) and lets the user add/remove rows to match. */
.multi-value-row {
  display: flex;
  gap: 8px;
  margin-bottom: 8px;
}

.multi-value-row .multi-value-input {
  flex: 1;
}

.multi-value-remove {
  width: auto;
  padding: 10px 14px;
  flex-shrink: 0;
}

.multi-value-add {
  width: auto;
  margin-bottom: 16px;
}

/* Groups a long form (kunden.html's ~19 fields, was one flat list) into
   labeled, color-set-off panels — var(--bg) (the page background) against
   the modal's own var(--surface) gives a visible panel without a second
   color needing to be introduced, and works in dark mode the same way
   since --bg/--surface already diverge there too. */
.form-section {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 20px 4px;
  margin-bottom: 20px;
}

.form-section:last-of-type {
  margin-bottom: 0;
}

.form-section-title {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--text-muted);
  margin: 0 0 12px;
}

/* Booking details left, a vertical rule, contact details right — stacks
   back to one column with a horizontal rule below .card--split's own
   width on a narrow/mobile viewport. */
.booking-columns {
  display: grid;
  /* minmax(0, 1fr), not bare 1fr — a plain 1fr track won't shrink below
     its content's min-content width, so the column with the longest
     placeholder/value (e.g. Gast's) could end up wider than the other
     even though both are nominally "1fr", making the two sides visibly
     unequal. minmax(0, 1fr) forces both to the same width regardless of
     content, and .field's own width:100% inputs then fill each equally. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: start;
  gap: 24px;
}

.booking-divider {
  width: 1px;
  align-self: stretch;
  background: var(--border);
}

/* raum-buchen.html: one checkbox per active cal_option row of the room
   behind ?key= — same .checkbox-field look as elsewhere, just stacked
   without each one's own bottom margin (the list itself carries that). */
.options-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.options-list .checkbox-field {
  margin-bottom: 0;
}

.options-list .option-beschreibung {
  font-size: 12px;
  color: var(--text-muted);
  margin: 2px 0 0 24px;
}

.booking-column-title {
  font-size: 15px;
  font-weight: 600;
  margin: 0 0 14px;
}

/* Live overlap warning shown under the Start/Ende fields as soon as the
   visitor picks a range that clashes with an already-existing booking
   (see raum-buchen.js's checkAvailability()) — same .field-hint base as
   every other hint, just recolored to read as a warning rather than
   neutral guidance. */
.field-hint--warning {
  color: var(--danger);
}

@media (max-width: 640px) {
  .booking-columns {
    grid-template-columns: 1fr;
  }

  .booking-divider {
    width: auto;
    height: 1px;
    margin: 4px 0;
  }
}

.success-banner {
  display: none;
  background: var(--badge-active-bg);
  color: var(--badge-active-text);
  border-radius: var(--radius);
  padding: 14px 16px;
  font-size: 14px;
  line-height: 1.5;
}

.success-banner.visible {
  display: block;
}

.dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  padding: 32px 16px;
  text-align: center;
  cursor: pointer;
  color: var(--text-muted, #6b7568);
  transition: border-color 0.15s ease, background 0.15s ease;
}

.dropzone:hover {
  border-color: var(--primary);
}

.dropzone.dropzone--active {
  border-color: var(--primary);
  background: rgba(140, 198, 63, 0.08);
  color: inherit;
}

.dropzone-filename {
  margin-top: 8px;
  font-weight: 600;
}

/* Anruflisten (anrufe.html + Dashboard-Panel "Anrufe"): Kopfzeile in drei
   Spalten — links Titel/Filter, MITTIG das Wählfeld, rechts optionaler
   Link. 1fr auto 1fr hält die Mitte auch bei ungleich breiten Seiten
   exakt zentriert. */
.call-toolbar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  gap: 16px;
}

.call-toolbar > .call-toolbar-end {
  justify-self: end;
}

.call-dial {
  display: flex;
  gap: 8px;
  align-items: center;
}

.call-dial input[type="tel"] {
  width: 220px;
}

.call-dial button {
  width: auto;
  padding: 9px 16px;
  white-space: nowrap;
}

@media (max-width: 760px) {
  .call-toolbar {
    grid-template-columns: 1fr;
  }
  .call-toolbar > .call-toolbar-end {
    justify-self: start;
  }
  .call-dial input[type="tel"] {
    width: 100%;
  }
}

/* mandanten.html → Microsoft 365 → "Einstellungen testen": Schrittliste */
.m365-test-result {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
  font-size: 13px;
}
.m365-test-result li {
  display: flex;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
}
.m365-test-result li:last-child {
  border-bottom: none;
}
.m365-test-result .m365-test-icon {
  flex: 0 0 auto;
  font-weight: 700;
}
.m365-test-result .m365-test-ok .m365-test-icon {
  color: #2e8b57;
}
.m365-test-result .m365-test-fail .m365-test-icon {
  color: var(--danger);
}
.m365-test-result .m365-test-msg {
  color: var(--text-muted);
}

/* Hilfesymbol "?" (z. B. mandanten.html → Abschnitt Microsoft 365) —
   kleiner runder Button statt des globalen gefüllten button-Stils. */
.help-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  margin-left: 8px;
  border-radius: 50%;
  border: 2px solid var(--primary);
  background: var(--bg);
  color: var(--primary);
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
  vertical-align: middle;
  cursor: pointer;
}
.help-icon:hover:not(:disabled) {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

/* Hilfefenster: liegt über dem Bearbeiten-Modal (steht später im DOM) */
.help-overlay {
  z-index: 60;
}
.help-modal {
  max-width: min(92vw, 820px);
}
.help-content {
  font-size: 14px;
  line-height: 1.55;
}
.help-content h3 {
  font-size: 14px;
  margin: 20px 0 6px;
}
.help-content ul {
  margin: 4px 0 8px;
  padding-left: 20px;
}
.help-content li {
  margin: 3px 0;
}
.help-content code {
  font-size: 12.5px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 5px;
  overflow-wrap: anywhere;
}
.help-content pre {
  font-size: 12.5px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  overflow-x: auto;
  white-space: pre;
  margin: 6px 0 8px;
}
.help-content .help-copy {
  width: auto;
  padding: 3px 10px;
  font-size: 12px;
  margin-left: 6px;
}
.help-content pre + .help-copy {
  margin-left: 0;
}

/* ---- Signage-Bildbibliothek (signage-bilder.html, SignagePicker in displays.html) ---- */

/* Segment-Umschalter (Kategorie, Quelle Datei/URL) */
.seg-tabs {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  flex-wrap: wrap;
}
.seg-tabs .seg-tab {
  width: auto;
  padding: 7px 14px;
  border: none;
  border-radius: 0;
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
}
.seg-tabs .seg-tab + .seg-tab {
  border-left: 1px solid var(--border);
}
.seg-tabs .seg-tab:hover:not(:disabled) {
  background: var(--bg);
}
.seg-tabs .seg-tab.active,
.seg-tabs .seg-tab.active:hover {
  background: var(--primary);
  color: #fff;
}

.badge-neutral {
  background: color-mix(in srgb, #3b82c4 16%, transparent);
  color: #3b82c4;
}

.media-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}
.media-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  min-width: 0;
}
.media-thumb {
  display: block;
  aspect-ratio: 16 / 9;
  background: repeating-conic-gradient(color-mix(in srgb, var(--text-muted) 12%, transparent) 0% 25%, transparent 0% 50%) 50% / 16px 16px;
}
.media-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.media-info {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px 6px;
  min-width: 0;
}
.media-name {
  font-weight: 600;
  font-size: 14px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.media-meta {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  font-size: 12px;
  color: var(--text-muted);
}
.media-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  padding: 6px 12px 12px;
}
.media-actions button {
  width: auto;
  padding: 5px 10px;
  font-size: 12px;
}

/* Auswahl-Dialog: ganze Karte ist ein Button */
.signage-picker-overlay {
  z-index: 60;
}
.media-grid--picker {
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  max-height: 60vh;
  overflow-y: auto;
  padding: 2px;
}
.media-card--pick {
  width: auto;
  padding: 0;
  text-align: left;
  color: var(--text);
  cursor: pointer;
  font: inherit;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.media-card--pick:hover:not(:disabled) {
  background: var(--surface);
  border-color: var(--primary);
  box-shadow: 0 0 0 2px var(--primary);
}
.media-card--pick .media-info {
  padding-bottom: 10px;
}

/* Upload-Fortschritt */
.upload-list {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  font-size: 13px;
  max-height: 220px;
  overflow-y: auto;
}
.upload-item {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr) auto;
  gap: 8px;
  padding: 5px 0;
  border-bottom: 1px solid var(--border);
}
.upload-item .upload-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.upload-item .upload-msg {
  color: var(--text-muted);
  text-align: right;
}
.upload-item--ok .upload-icon {
  color: #2e8b57;
  font-weight: 700;
}
.upload-item--fehler .upload-icon,
.upload-item--fehler .upload-msg {
  color: var(--danger);
  font-weight: 600;
}

.edit-preview {
  display: block;
  max-width: 100%;
  max-height: 220px;
  margin: 0 auto 16px;
  border-radius: 8px;
  border: 1px solid var(--border);
}

/* displays.html: Bild-Feld mit Vorschau + Bibliotheks-Button */
.bild-picker-row {
  display: flex;
  gap: 8px;
  align-items: center;
}
.bild-picker-row input {
  flex: 1 1 auto;
  min-width: 0;
}
.bild-picker-preview {
  width: 72px;
  height: 40px;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--border);
  flex: 0 0 auto;
}
.bild-table-thumb {
  width: 96px;
  height: 54px;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--border);
  display: block;
}
@media (max-width: 640px) {
  .bild-picker-row {
    flex-wrap: wrap;
  }
}

/* signage-bilder.html: Kopfbereich im Fenster "Bild ersetzen" */
.replace-info {
  gap: 12px;
  align-items: center;
  margin-bottom: 16px;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
}
.replace-info img {
  width: 120px;
  height: 68px;
  object-fit: cover;
  border-radius: 6px;
  flex: 0 0 auto;
}


/* ---- Benutzereinstellungen (mein-konto.html) ---- */
.settings-page {
  display: grid;
  gap: 20px;
  max-width: 980px;
  margin: 0 auto;
}
.settings-card {
  padding: 24px 28px;
  /* Abschnitte sind keine Tabellen — keine eigene Scrollbox */
  max-height: none;
  overflow: visible;
}
.settings-card h2 {
  margin: 0 0 4px;
  font-size: 18px;
}
.settings-card > .field-hint:first-of-type {
  margin-top: 0;
  margin-bottom: 16px;
}
.skin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px;
}
.skin-option {
  width: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  text-align: left;
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 2px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
}
.skin-option:hover:not(:disabled) {
  background: var(--surface);
  border-color: var(--primary);
}
.skin-option.active {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px var(--primary);
}
.skin-swatches {
  display: flex;
  height: 34px;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid rgba(0, 0, 0, 0.12);
}
.skin-swatches span {
  flex: 1;
}
.skin-name {
  font-weight: 600;
}
.skin-desc {
  font-size: 12px;
  color: var(--text-muted);
}

/* ---- Logo (assets/img/, aus logo/Überarbeitetes Unimdm-Logo…png) ---- */
/* Kopfzeile: nur das U-Symbol, der Schriftzug steht als .brand-name daneben */
.brand-logo {
  height: 36px;
  width: auto;
  display: block;
  flex: 0 0 auto;
}

/* Anmeldeseiten: komplettes Logo mit Schriftzug, zentriert */
.brand--login {
  flex-direction: column;
  gap: 6px;
  text-align: center;
}
.brand-logo-full {
  height: 120px;
  width: auto;
  display: block;
}

/* Der Schriftzug im Logo ist dunkelblau — auf dunklen Skins hinter eine
   helle Fläche legen, damit er lesbar bleibt. */
@media (prefers-color-scheme: dark) {
  html:not([data-skin]) .brand-logo-full {
    background: #ffffff;
    border-radius: 12px;
    padding: 10px 14px;
  }
}
html[data-skin="standard-dunkel"] .brand-logo-full,
html[data-skin="nacht"] .brand-logo-full,
html[data-skin="graphit"] .brand-logo-full {
  background: #ffffff;
  border-radius: 12px;
  padding: 10px 14px;
}
