/* AUTO-GENERATED — edit partials in app/assets/css/components/, run scripts/build-css.sh */

/* ── [hidden] Override – display:flex/grid überschreibt UA-Stylesheet; !important stellt sicher
      dass ?hidden=${...} in Lit (z.B. Sprach-Toggles in ds-form-row / form-group) korrekt greift. */
[hidden] { display: none !important; }

/* ── Buttons ── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: var(--radius-pill);
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  transition: all var(--transition);
  min-height: 44px;
  white-space: nowrap;
  user-select: none;
  text-decoration: none;
}

.btn:active { transform: scale(0.97); }

/* Disabled-Zustand – gilt für alle Varianten (primary/secondary/ghost/danger/…)
   via Basisklasse .btn. Werte gespiegelt aus bestehender App-Konvention
   (.form-palette-item.disabled / .event-cal-selector-btn:disabled = opacity .45–.5). */
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

.btn-primary {
  background: var(--accent);
  color: #fff;
}
.btn-primary:hover { background: var(--accent-dark); }

.btn-secondary {
  background: var(--bg-tertiary);
  color: var(--text-primary);
  border: 1px solid var(--border);
}
.btn-secondary:hover { background: var(--bg-primary); }

.btn-ghost {
  background: transparent;
  color: var(--text-secondary);
}
.btn-ghost:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}

.btn-danger {
  background: var(--danger-light);
  color: var(--danger);
}
.btn-danger:hover { background: var(--danger); color: #fff; }

.btn-success {
  background: var(--teal);
  color: #fff;
}
.btn-success:hover { background: var(--teal); filter: brightness(0.92); }

.btn-warning {
  background: var(--amber);
  color: #fff;
}
.btn-warning:hover { background: var(--amber); filter: brightness(0.92); }

/* Dark mode: btn-secondary needs a visible border; btn-danger needs readable bg
   (nur expliziter data-theme="dark"-Toggle, keine OS-Media-Query) */
:root[data-theme="dark"] .btn-secondary,
:root[data-theme="dark"] .btn-secondary:hover { color: var(--text-primary); }
:root[data-theme="dark"] .btn-danger  { background: var(--danger-light); }
:root[data-theme="dark"] .btn-danger:hover { background: var(--danger); color: #fff; }

.btn-sm {
  padding: 0.25rem 0.625rem;
  font-size: 0.8125rem;
  min-height: 32px;
}

.btn-icon {
  padding: 0.5rem;
  aspect-ratio: 1;
  justify-content: center;
  min-height: 44px;
  min-width: 44px;
}

/* ── Stern-Button (Standard-Marker, konsistent über alle Module) ───── */
.ds-star-btn {
  padding: 0.35rem !important;
  min-height: 32px;
  min-width:  32px;
  color: var(--text-tertiary);
  transition: color var(--transition), background var(--transition);
}
.ds-star-btn:hover            { color: var(--amber); background: var(--amber-light); }
.ds-star-btn.is-active        { color: var(--amber); }
.ds-star-btn.is-active:hover  { color: var(--amber-dark, var(--amber)); }

/* ── Input-Group: gestapelte Selects/Inputs als visuelle Einheit ──── */
.input-group {
  display: flex;
  width: 100%;
}
.input-group .select,
.input-group .input { flex: 1; min-width: 0; }
/* Stack-Variante: Selects untereinander, oben/unten kombinierte Borders */
.input-group--stack {
  flex-direction: column;
  gap: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--bg-primary);
}
.input-group--stack > .select,
.input-group--stack > .input {
  border: none;
  border-radius: 0;
  background: transparent;
  width: 100%;
}
.input-group--stack > .select + .select,
.input-group--stack > .select + .input,
.input-group--stack > .input  + .select,
.input-group--stack > .input  + .input {
  border-top: 1px solid var(--border);
}
.input-group--stack:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}

/* Desktop: Drag-Handle sichtbar, Up/Down-Buttons aus.
   Mobile: Drag-Handle aus, Up/Down-Buttons sichtbar. */
@media (max-width: 900px) {
  .cred-cal-drag-handle { display: none; }
}
@media (min-width: 901px) {
  .cred-cal-move-btn { display: none; }
}

/* ── Cards ── */
.card {
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border);
}

.card-body { padding: 1.25rem; }

.card-footer {
  padding: 0.75rem 1.25rem;
  border-top: 1px solid var(--border);
  background: var(--bg-secondary);
}

/* ── Card-Kachel (klickbare Karten in Grids/Board-Spalten) ──
   Gemeinsamer Radius/Border/Hover-Stil, extrahiert aus .notes-card
   (_notes.css) für app-weite Wiederverwendung – sonst wichen Board-Karten
   (Todos) und Notiz-Karten optisch voneinander ab (Spec 20260730 Feinschliff,
   Domenico-Feedback). Traegt selbst KEIN Layout (Flex-Richtung/Padding bleibt
   modul-spezifisch) – nur Fläche + Hover-Feedback. */
.ds-card-tile {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: box-shadow var(--transition), border-color var(--transition);
}
.ds-card-tile:hover {
  box-shadow: var(--shadow-sm);
  border-color: var(--accent);
}

/* ── Screen Lock Overlay ── */
.screen-lock-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  /* No backdrop-filter – avoids the WebKit touch-event bug */
}
.screen-lock-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  padding: 2rem 2.5rem;
  box-shadow: var(--shadow-lg);
  min-width: 200px;
  text-align: center;
}
.screen-lock-msg {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--text-primary);
}

/* ── Form Footer (card bottom bar with action buttons) ── */
.form-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem 1.5rem;
  border-top: 1px solid var(--border);
}
/* Left group (e.g. AI-button + quality badge) – replaces inline style="display:flex;…" */
.form-footer-left {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.form-footer-actions {
  display: flex;
  gap: 0.75rem;
  margin-left: auto;
}

@media (max-width: 900px) {
  .form-footer {
    gap: 0.625rem;
    padding: 0.875rem 1rem;
  }
  /* Left group (Hand-me + badge) → full-width own row */
  .form-footer-left {
    flex: 1 1 100%;
  }
  /* Actions row below left group */
  .form-footer-actions {
    flex: 1 1 100%;
    margin-left: 0;
    flex-wrap: wrap;
    gap: 0.5rem;
  }
  /* Secondary actions share width naturally via flex-wrap;
     primary Save button gets full row if it would be too cramped */
  .form-footer-actions .btn {
    flex: 1 1 auto;
    justify-content: center;
    min-height: 48px;
    min-width: 7rem;
  }
  /* Primary button always full width on mobile (clearest tap target) */
  .form-footer-actions .btn-primary {
    flex: 1 1 100%;
  }
}

/* ── Badges ── */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.1875rem 0.5rem;
  border-radius: 99px;
  font-size: 0.75rem;
  font-weight: 500;
}

.badge-purple  { background: var(--accent-light);  color: var(--accent-dark); }
.badge-teal    { background: var(--teal-light);    color: var(--teal); }
.badge-amber   { background: var(--amber-light);   color: var(--amber); }
.badge-coral   { background: var(--coral-light);   color: var(--coral); }
.badge-rose    { background: var(--rose-light);    color: var(--rose); }
.badge-neutral { background: var(--bg-tertiary);   color: var(--text-secondary); }

/* Stage badges */
.stage-lead        { background: var(--bg-tertiary);  color: var(--text-secondary); }
.stage-qualified   { background: var(--teal-light);   color: var(--teal); }
.stage-proposal    { background: var(--accent-light); color: var(--accent-dark); }
.stage-negotiation { background: var(--amber-light);  color: var(--amber); }
.stage-won         { background: var(--teal-light);   color: var(--teal); }
.stage-lost        { background: var(--coral-light);  color: var(--coral); }

/* Priority badges */
.priority-high   { background: var(--coral-light);  color: var(--coral); }
.priority-medium { background: var(--amber-light);  color: var(--amber); }
.priority-low    { background: var(--bg-tertiary);  color: var(--text-secondary); }

/* Status badges */
.status-planning { background: var(--bg-tertiary);  color: var(--text-secondary); }
.status-active   { background: var(--teal-light);   color: var(--teal); }
.status-paused   { background: var(--amber-light);  color: var(--amber); }
.status-done     { background: var(--accent-light); color: var(--accent-dark); }

/* ── Tags ── */
.tag {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem 0.5rem;
  background: var(--accent-light);
  color: var(--accent-dark);
  border-radius: 99px;
  font-size: 0.6875rem;
  font-weight: 500;
}

.tags { display: flex; gap: 0.25rem; flex-wrap: wrap; }

/* ── Ticket-Nummer-Badge (Aufgaben-Modul, Spec 20260730 P4) ──
   Kompakte, monospace Referenz vor dem Aufgaben-Titel – Board-Karte,
   Listenzeile, Backlog, Timeline, Detail-Kopf, Dashboard-Widget. Fehlt die
   Nummer (ticket_number null, z.B. Aufgabe ohne Projekt), wird nichts
   gerendert – kein Platzhalter, keine leere Box. */
.ds-ticket-badge {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-tertiary);
  white-space: nowrap;
  flex-shrink: 0;
}
/* Größere Variante für den Detail-Kopf (deutlich lesbar neben dem Titel) */
.ds-ticket-badge--lg {
  font-size: 0.8125rem;
  padding: 0.1rem 0.4rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
}

/* ── Inputs ── */
.input, .select, .textarea {
  width: 100%;
  padding: 0.5625rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: 0.9375rem;
  font-family: inherit;
  transition: border-color var(--transition);
  min-height: 44px;
}

.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}

.input::placeholder, .textarea::placeholder { color: var(--text-tertiary); }

.textarea {
  resize: vertical;
  min-height: 100px;
  line-height: 1.5;
}

.select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  padding-right: 1.75rem;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 0.6rem center;
  background-size: 12px;
}

.form-group {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.form-label {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
}

.form-error {
  font-size: 0.875rem;
  color: var(--danger);
  padding: 0.625rem 0.75rem;
  background: var(--danger-light);
  border-radius: var(--radius-md);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

@media (max-width: 600px) {
  .form-row { grid-template-columns: 1fr; }
}

/* ── Avatar ── */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-weight: 600;
  flex-shrink: 0;
  background: var(--accent-light);
  color: var(--accent-dark);
  font-size: 0.875rem;
}

.avatar-sm  { width: 32px;  height: 32px;  font-size: 0.75rem; }
.avatar-md  { width: 40px;  height: 40px;  font-size: 0.875rem; }
.avatar-lg  { width: 56px;  height: 56px;  font-size: 1.125rem; }
.avatar-xl  { width: 72px;  height: 72px;  font-size: 1.5rem; }

.avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }

/* ── Avatar Upload Widget ── */
.avatar-wrap {
  position: relative;
  display: inline-flex;
}

.avatar-upload-wrap {
  position: relative;
  display: inline-flex;
  cursor: pointer;
}

.avatar-upload-wrap input[type="file"] {
  display: none;
}

.avatar-overlay {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity var(--transition);
  pointer-events: none;
}

.avatar-upload-wrap:hover .avatar-overlay {
  opacity: 1;
}

.avatar-overlay svg {
  color: #fff;
}

.avatar-delete-btn {
  position: absolute;
  top: -4px;
  right: -4px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--coral);
  color: #fff;
  border: 2px solid var(--bg-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  transition: background var(--transition);
}

.avatar-delete-btn:hover {
  background: #b84a24;
}

/* ── QR-Button (Avatar-Badge unten rechts) ── */
ds-qr-button {
  display: contents; /* kein eigenes Layout-Element */
}

.ds-qr-btn {
  position: absolute;
  bottom: -4px;
  right: -4px;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-secondary);
  border: 1.5px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
  z-index: 2;
  line-height: 0;
}

/* Unsichtbarer Touch-Target-Bereich – mindestens 44×44px */
.ds-qr-btn::after {
  content: '';
  position: absolute;
  inset: -9px;
}

.ds-qr-btn:hover {
  background: var(--accent-light);
  border-color: var(--accent);
  color: var(--accent);
}

/* ── Progress Bar ── */
.progress-bar {
  width: 100%;
  height: 6px;
  background: var(--bg-tertiary);
  border-radius: 99px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 99px;
  transition: width 0.4s ease;
}

.progress-fill.high   { background: var(--teal); }
.progress-fill.medium { background: var(--accent); }
.progress-fill.low    { background: var(--amber); }

/* ── Divider ── */
.divider {
  height: 1px;
  background: var(--border);
  margin: 1rem 0;
}

/* ── Empty State ── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 3rem 2rem;
  text-align: center;
  gap: 1rem;
}

.empty-state svg {
  width: 80px;
  height: 80px;
  opacity: 0.4;
  color: var(--accent);
}

.empty-state h3 { color: var(--text-primary); }
.empty-state p  { color: var(--text-secondary); max-width: 280px; font-size: 0.875rem; }

/* ── Spinner ── */
.spinner {
  width: 24px;
  height: 24px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

.loading-center {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 3rem;
}

/* ── Table ── */
.table-wrap { overflow-x: auto; }

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.table th, .table td {
  padding: 0.75rem 1rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
}

.table th {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
  background: var(--bg-secondary);
}

.table tbody tr:hover { background: var(--bg-secondary); }
.table tbody tr { cursor: pointer; transition: background var(--transition); }

/* ── Activity Type Icons ── */
.activity-icon {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 0.875rem;
}

.activity-icon.call     { background: var(--teal-light);   color: var(--teal); }
.activity-icon.email    { background: var(--accent-light); color: var(--accent-dark); }
.activity-icon.meeting  { background: var(--amber-light);  color: var(--amber); }
.activity-icon.note     { background: var(--bg-tertiary);  color: var(--text-secondary); }
.activity-icon.task     { background: var(--rose-light);   color: var(--rose); }
.activity-icon.added    { background: var(--green-light, #E6F9F0); color: var(--green, #1A9E5A); font-weight: 700; }

/* ── Unified Activity Timeline (Spec 20260416_1300) ── */
.contact-activity-timeline {
  display: flex;
  flex-direction: column;
  padding: 0.5rem 0.75rem 0.75rem;
}

.activity-item {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.625rem 0.5rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition);
}
.activity-item:hover { background: var(--bg-tertiary); }

.activity-item .activity-icon {
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.activity-item.activity-type-calendar_event .activity-icon { background: var(--amber-light);  color: var(--amber); }
.activity-item.activity-type-email          .activity-icon { background: var(--accent-light); color: var(--accent-dark); }
.activity-item.activity-type-todo           .activity-icon { background: var(--rose-light);   color: var(--rose); }
.activity-item.activity-sub-followup        .activity-icon { background: var(--teal-light);   color: var(--teal); }

.activity-body  { flex: 1; min-width: 0; }
.activity-title {
  font-weight: 500;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.activity-date  { font-size: 0.8125rem; color: var(--text-tertiary); margin-top: 0.125rem; }
.activity-meta  { font-size: 0.8125rem; color: var(--text-secondary); margin-top: 0.125rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Sublabel für firmenweit aggregierte Timeline: zeigt den zugehörigen Kontaktnamen */
.activity-contact-label { font-size: 0.75rem; color: var(--accent); margin-top: 0.125rem; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.contact-activity-create-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  z-index: 50;
  min-width: 180px;
  padding: 0.25rem;
}
.contact-activity-create-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.5rem 0.75rem;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  font-size: 0.875rem;
  color: var(--text-primary);
  cursor: pointer;
  text-align: left;
}
.contact-activity-create-item:hover { background: var(--bg-tertiary); }

/* ── Skill Pills ── */
.skill-pills-wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  padding: 0.75rem 1.25rem 1rem;
}

.skill-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.3rem 0.625rem;
  border-radius: 2rem;
  font-size: 0.8125rem;
  font-weight: 500;
  border: none;
  cursor: default;
  transition: all var(--transition);
}

.skill-pill-item {
  background: var(--accent-light);
  color: var(--accent-dark);
}

.skill-pill-add {
  background: transparent;
  border: 1.5px dashed var(--border);
  color: var(--text-tertiary);
  cursor: pointer;
  font-weight: 400;
}
.skill-pill-add:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-light); }

.skill-pill-edit,
.skill-pill-del {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  cursor: pointer;
  padding: 1px;
  border-radius: 50%;
  opacity: 0.5;
  transition: opacity var(--transition), color var(--transition);
  color: inherit;
}
.skill-pill-edit:hover { opacity: 1; }
.skill-pill-del:hover  { opacity: 1; color: var(--coral); }

.skill-cat-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
}

/* Contact detail skill read-only pills */
.skill-pill-ro {
  display: inline-flex;
  align-items: center;
  padding: 0.25rem 0.625rem;
  border-radius: 2rem;
  font-size: 0.8rem;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  border: 1px solid var(--border);
  font-weight: 500;
}
.skill-pill-ro.assigned {
  background: var(--accent-light);
  color: var(--accent-dark);
  border-color: transparent;
}

/* ── Drag & Drop ── */
.drag-ghost {
  opacity: 0.4;
}

.skill-category-card.drag-over-top {
  box-shadow: 0 -3px 0 0 var(--accent);
}
.skill-category-card.drag-over-bot {
  box-shadow: 0 3px 0 0 var(--accent);
}

.skill-pill-item.drag-over-top {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.skill-pill-item.drag-over-bot {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.drag-handle:hover { color: var(--text-secondary); }
.drag-handle:active { cursor: grabbing; }

/* ── Branchen-Katalog (Partner-Selbstauskunft Phase 1, Spec 20260720) ──
   page-industries.js – Admin-CRUD-Seite, Muster pages/skills.js aber via
   Slide-In-Panel statt Modal. Generisch/reusable, deshalb in _core.css statt
   einem eigenen Modul-Partial (kein Eintrag in der CLAUDE.md-Partial-Tabelle
   nötig – analog Skills, die ebenfalls in _core.css leben). */
.ds-industries-hint {
  color: var(--text-secondary);
  font-size: .875rem;
  margin: 0 0 1.25rem;
}
.ds-industries-panel-actions {
  display: flex;
  gap: .5rem;
  margin-top: 1rem;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.ds-industries-panel-actions .btn { flex: 1; }
.ds-industries-panel-danger {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .375rem;
  width: 100%;
  margin-top: .75rem;
  color: var(--coral);
}
.ds-industries-panel-danger:hover { background: var(--coral-light); color: var(--coral); }
.ds-industries-sort-col { width: 4.5rem; }
.ds-industries-actions-col { width: 5rem; text-align: right; }
.ds-industries-row-actions { display: flex; align-items: center; gap: .375rem; justify-content: flex-end; }
.ds-industries-del-btn { color: var(--coral); }
.ds-industries-del-btn:hover { background: var(--coral-light); color: var(--coral); }

/* Ziehen-Sortierung (Ticket 3.382) – ersetzt die vorherigen Pfeil-Buttons
   (s. page-industries.js Modul-Kommentar). Griff bewusst IMMER sichtbar
   (kein Hover-Reveal wie .tbc-drag/.todo-list-drag-handle) – diese Liste ist
   eine schmale Admin-Tabelle, kein dichtes Karten-Raster; ohne Hover-Reveal
   entfällt auch die frontend.md-Reihenfolge-Falle "Media-Query nach
   Basisregel" (Ticket 3.163.12) komplett, da keine opacity:0/pointer-
   events:none-Basisregel existiert, die ein @media(pointer:coarse)-Block
   überschreiben müsste. */
.ds-industries-drag-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  color: var(--text-tertiary);
  cursor: grab;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
  /* Seiten-Scroll während des Ziehens unterdrücken (core/touch-drag.js
     ruft zusätzlich e.preventDefault() im touchmove – touch-action ist die
     CSS-seitige Ergänzung dazu, verhindert den anfaenglichen Scroll-Jitter
     vor Erreichen der Bewegungs-Schwelle). */
  touch-action: none;
}
.ds-industries-drag-handle:hover { color: var(--text-secondary); background: var(--bg-tertiary); }
.ds-industries-drag-handle:active { cursor: grabbing; }
/* Gezogene Zeile: gedaempft (analog .todo-list-row.dnd-dragging). */
.ds-industries-row.dnd-dragging,
.ds-industries-native-row.dnd-dragging { opacity: .4; }
/* Einfügemarke während des Ziehens – Tabellenzeile: box-shadow auf <tr>
   selbst wird bei border-collapse:collapse (s. .table) teils abgeschnitten,
   daher auf die Zellen gescopt. Mobile-Zeile (.native-row, ein <div>) trägt
   den Schatten direkt. */
.ds-industries-row.dnd-over-top td { box-shadow: inset 0 2px 0 0 var(--accent); }
.ds-industries-row.dnd-over-bottom td { box-shadow: inset 0 -2px 0 0 var(--accent); }
.ds-industries-native-row.dnd-over-top { box-shadow: inset 0 2px 0 0 var(--accent); }
.ds-industries-native-row.dnd-over-bottom { box-shadow: inset 0 -2px 0 0 var(--accent); }

/* ── Einheiten-Katalog (Ticket 3.100, Paket B) ──
   page-units.js – Admin-CRUD-Seite, identisches Muster wie die Branchen-
   Klassen oben (Slide-In-Panel, Deaktivieren statt Löschen). Zusätzlich zur
   Branchen-Familie: globale (unveränderliche) vs. eigene Zeilen müssen sich
   optisch unterscheiden – .ds-units-locked/.ds-units-row--locked dafür. */
.ds-units-hint {
  color: var(--text-secondary);
  font-size: .875rem;
  margin: 0 0 1.25rem;
}
.ds-units-field-hint {
  color: var(--text-tertiary);
  font-size: .75rem;
  margin: .25rem 0 0;
}
.ds-units-panel-actions {
  display: flex;
  gap: .5rem;
  margin-top: 1rem;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.ds-units-panel-actions .btn { flex: 1; }
.ds-units-panel-danger {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .375rem;
  width: 100%;
  margin-top: .75rem;
  color: var(--coral);
}
.ds-units-panel-danger:hover { background: var(--coral-light); color: var(--coral); }
.ds-units-code { font-variant-numeric: tabular-nums; }
.ds-units-origin-col { width: 6rem; }
.ds-units-actions-col { width: 5rem; text-align: right; }
.ds-units-row-actions { display: flex; align-items: center; gap: .375rem; justify-content: flex-end; }
.ds-units-del-btn { color: var(--coral); }
.ds-units-del-btn:hover { background: var(--coral-light); color: var(--coral); }
.ds-units-locked {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  color: var(--text-tertiary);
}
/* Mobile: globale Zeile ist nicht klickbar – .native-row erbt sonst cursor:pointer + :active-BG. */
.ds-units-row--locked { cursor: default; }
.ds-units-row--locked:active { background: var(--bg-primary); }

/* ── Sortable Table Headers ── */
.th-sort {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.th-sort:hover { color: var(--accent); }

.th-sort-inner {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.sort-icon {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
  opacity: 0.3;
  flex-shrink: 0;
}
.sort-icon span {
  display: block;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
}
.sort-icon span.arrow-up   { border-bottom: 4px solid currentColor; }
.sort-icon span.arrow-down { border-top:    4px solid currentColor; }

.th-sort.sort-asc  .sort-icon,
.th-sort.sort-desc .sort-icon { opacity: 1; color: var(--accent); }

.th-sort.sort-asc  .arrow-down { opacity: 0.25; }
.th-sort.sort-desc .arrow-up   { opacity: 0.25; }

@media (max-width: 900px) {
  /* [MED] Touch-Target für Sortier-Header – offers.js .th-sort auf Mobile (HIG 44px) */
  .th-sort {
    min-height: 44px;
    vertical-align: middle;
  }
  .th-sort-inner {
    min-height: 44px;
    align-items: center;
  }
}

/* ── Favorite Star Button ── */
.btn-favorite {
  background: none;
  border: none;
  padding: 0.25rem;
  cursor: pointer;
  color: var(--text-tertiary);
  line-height: 0;
  flex-shrink: 0;
  transition: color 120ms, transform 120ms;
}
.btn-favorite:hover               { color: var(--amber); transform: scale(1.15); }
.btn-favorite.is-favorite         { color: var(--amber); }
.btn-favorite.is-favorite svg     { fill: var(--amber); }

/* ── Tab Filter (contact type etc.) ── */
.tab-filter {
  display: flex;
  gap: 0.25rem;
  padding: 0.25rem;
  background: var(--bg-tertiary);
  border-radius: var(--radius-md);
  flex-shrink: 0;
}
.tab-filter-btn {
  padding: 0.375rem 0.875rem;
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
  cursor: pointer;
  border: none;
  background: transparent;
  transition: all var(--transition);
  min-height: 36px;
}
.tab-filter-btn:hover  { color: var(--text-primary); }
.tab-filter-btn.active {
  background: var(--bg-primary);
  color: var(--text-primary);
  box-shadow: var(--shadow-sm);
}

@media (max-width: 900px) {
  /* Scrollable tab-filter on mobile – long labels (e.g. Firmenadresse/Versandadresse/Rechnungsadresse)
     would overflow without scroll. overflow-x:auto only activates when content exceeds container width. */
  .tab-filter {
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .tab-filter::-webkit-scrollbar { display: none; }
  .tab-filter-btn {
    flex-shrink: 0;
    white-space: nowrap;
  }
}

/* ── Search Bar ── */
.search-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0 0.75rem;
  min-height: 44px;
  /* box-sizing:border-box hält die tatsaechliche Gesamthoehe bei exakt 44px
     (Border wurde vorher ON TOP von min-height addiert -> 46px total) – damit
     deckungsgleich mit .contact-filter-btn (height:44px, ebenfalls border-box). */
  box-sizing: border-box;
}

.search-bar input {
  border: none;
  outline: none;
  background: transparent;
  color: var(--text-primary);
  font-size: 0.9375rem;
  font-family: inherit;
  flex: 1;
  min-width: 0;
}

.search-bar input::placeholder { color: var(--text-tertiary); }

.search-bar svg { color: var(--text-tertiary); flex-shrink: 0; }

/* ── Filter Tabs ── */
.filter-tabs {
  display: flex;
  gap: 0.25rem;
  padding: 0.25rem;
  background: var(--bg-tertiary);
  border-radius: var(--radius-md);
}

.filter-tab {
  padding: 0.375rem 0.875rem;
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all var(--transition);
  border: none;
  background: none;
  min-height: 36px;
}

.filter-tab:hover { color: var(--text-primary); }
.filter-tab.active {
  background: var(--bg-primary);
  color: var(--text-primary);
  box-shadow: var(--shadow-sm);
}

/* ── Modal ── */
/* Rechtsklick auf diese Fläche schließt sie ebenfalls, obwohl kein CSS-Zeichen
   das ausdrückt: der Klassenname endet auf "-backdrop", und dafür greift ein
   zentraler app-weiter Listener (Ticket 3.392). Details, Wirkungsweise und die
   volle Klassenliste: core/_backdrop-right-click.js, .claude/rules/frontend.md. */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.4);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 1rem;
  animation: fadeIn 120ms ease;
}

.modal {
  background: var(--bg-primary);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 560px;
  max-height: 90dvh;
  display: flex;
  flex-direction: column;
  animation: modalIn 120ms ease;
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.25rem 1.5rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.modal-body {
  padding: 1.5rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.modal-footer {
  padding: 1rem 1.5rem;
  border-top: 1px solid var(--border);
  display: flex;
  gap: 0.75rem;
  justify-content: flex-end;
  flex-shrink: 0;
}

@keyframes fadeIn  { from { opacity: 0; } to { opacity: 1; } }
@keyframes modalIn { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }

/* ── Toast ── */
.toast-root {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  z-index: 2000;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  font-size: 0.875rem;
  font-weight: 500;
  pointer-events: all;
  animation: toastIn 200ms ease-out;
  max-width: 360px;
}

.toast.success { border-color: var(--teal); }
.toast.success .toast-dot { background: var(--teal); }
.toast.error   { border-color: var(--danger); }
.toast.error   .toast-dot { background: var(--danger); }
.toast.info    { border-color: var(--accent); }
.toast.info    .toast-dot { background: var(--accent); }

/* Sorte "Erklärung" (Ticket 3.175) – bleibt stehen bis der Nutzer sie per
   Kreuz schließt. Amber-Ton wie .ds-info-box--amber (dieselbe Semantik:
   ein Hinweis, der eine kurze Nutzeraktion nahelegt). align-items:flex-start
   + Dot-Nudge, weil der Text hier mehrzeilig sein kann (Serverbegründung). */
.toast.explain { border-color: var(--amber); align-items: flex-start; max-width: 400px; }
.toast.explain .toast-dot { background: var(--amber); margin-top: .3rem; }

.toast-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

.toast.leaving { animation: toastOut 200ms ease-in forwards; }

/* Inline-Aktion im Toast (z.B. Rückgängig nach Löschen) */
.toast-action {
  margin-left: auto;
  flex-shrink: 0;
  padding: 0.25rem 0.625rem;
  min-height: 2rem;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--accent);
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
  white-space: nowrap;
}
.toast-action:hover {
  background: var(--accent-light);
  border-color: var(--accent);
}

/* Schließen-Kreuz – seit Ticket-3.175-Nachtrag (12.08.) bei JEDER Toast-Sorte
   gerendert (vorher nur .toast.explain): der Körper-Klick allein erwies sich
   im echten Test als nicht verlässlich genug. Größe 36px wie das etablierte
   Icon-Close-Muster (Modal-Close-Button). */
.toast-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  margin-left: auto;
  min-width: 36px;
  min-height: 36px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text-tertiary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
/* Folgt das Kreuz direkt auf die Inline-Aktion (z.B. "Rückgängig"), zieht es
   NICHT nochmal per margin-left:auto nach rechts – sonst verteilt Flexbox den
   Freiraum auf beide auto-Margins und reißt eine Lücke zwischen die Buttons
   statt sie zusammenstehen zu lassen. */
.toast-action + .toast-close { margin-left: 0; }
.toast-close:hover,
.toast-close:focus-visible {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.toast-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

@keyframes toastIn  { from { opacity: 0; transform: translateX(110%); } to { opacity: 1; transform: translateX(0); } }
@keyframes toastOut { from { opacity: 1; transform: translateX(0); }    to { opacity: 0; transform: translateX(110%); } }

/* ── Command Palette ── */
.command-palette {
  position: fixed;
  top: 5rem;
  left: 50%;
  transform: translateX(-50%);
  width: min(640px, calc(100vw - 2rem));
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  z-index: 1500;
  overflow: hidden;
  animation: modalIn 120ms ease;
}

.command-input-wrap {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border);
}

.command-input {
  flex: 1;
  border: none;
  outline: none;
  background: transparent;
  font-size: 1rem;
  color: var(--text-primary);
  font-family: inherit;
}

.command-results { max-height: 380px; overflow-y: auto; }

.command-section-title {
  padding: 0.5rem 1.25rem 0.25rem;
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
}

.command-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.625rem 1.25rem;
  cursor: pointer;
  transition: background var(--transition);
}

.command-item:hover, .command-item.selected {
  background: var(--accent-light);
}

.command-item-icon {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  background: var(--bg-tertiary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--text-secondary);
  font-size: 0.875rem;
}

/* Ticket 3.295 (Paket 1, Rückläufer) – Modul-Sprung-Treffer zeigen seit
   diesem Rückläufer die ECHTEN nav-config.js-Icons (20x20 nativ) statt
   ausschließlich der 16x16 CP_ICON_*-Konstanten. Erzwingt einheitliche
   Symbolgröße über beide Icon-Quellen hinweg – die viewBox skaliert sauber
   auf 16px. Greift kaskadierend auch innerhalb `.command-item--related`
   (deren Icons sind bereits nativ 16x16 CP_ICON_*-Strings, s. _relatedEntry()
   in components.js – keine sichtbare Änderung dort, nur Konsistenz). */
.command-item-icon svg {
  width: 16px;
  height: 16px;
}

.command-item-label { font-size: 0.9375rem; color: var(--text-primary); }
.command-item-sub   { font-size: 0.8125rem; color: var(--text-secondary); }

/* Ticket 3.295 (Paket 4) – "Verwandtes" unter einem Firmen-/Kontakt-Treffer:
   eingerückte Unterzeile mit kleinerem, rahmenlosem Icon statt der vollen
   32px-Icon-Box der Hauptzeile. Bleibt Teil derselben `.command-item`-Liste
   (keine neue Struktur) – nur ein Modifier für Einzug + Größe. */
.command-item--related {
  padding-left: 3rem;
}

.command-item--related .command-item-icon {
  width: 22px;
  height: 22px;
  background: transparent;
  color: var(--text-tertiary);
}

.command-item--related .command-item-label { font-size: 0.8125rem; color: var(--text-secondary); }
.command-item--related .command-item-sub   { font-size: 0.75rem; }

/* Ticket 3.295 (Paket 5) – "In neuem Tab öffnen"-Icon rechts an jeder
   navigierenden Ergebniszeile (Modul-Sprünge + Datensatz-Treffer). Desktop
   only (Workspace-Tabs sind ein Desktop-Konzept, s. isMobile()-Gate in
   _renderResults()). Eigener stopPropagation-Klick, isoliert von der
   Zeilen-Navigation. */
.command-item-new-tab-btn {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}

.command-item-new-tab-btn:hover,
.command-item-new-tab-btn:focus-visible {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}

.command-footer {
  padding: 0.5rem 1.25rem;
  border-top: 1px solid var(--border);
  display: flex;
  gap: 1rem;
  font-size: 0.75rem;
  color: var(--text-tertiary);
}

.command-footer kbd {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem 0.375rem;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
  font-size: 0.6875rem;
  font-family: inherit;
}

/* ── Checkbox ── */
.checkbox-wrap {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  cursor: pointer;
}

.checkbox-wrap input[type="checkbox"] {
  appearance: none;
  width: 18px;
  height: 18px;
  border: 2px solid var(--border);
  border-radius: 4px;
  cursor: pointer;
  transition: all var(--transition);
  flex-shrink: 0;
}

.checkbox-wrap input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent);
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 14 14' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M2 7l4 4 6-6' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 10px;
}

/* ── Metric Card ── */
.metric-card {
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  transition: box-shadow var(--transition), transform var(--transition);
}

.metric-card[style*="cursor:pointer"]:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.metric-card .metric-icon {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.125rem;
}

.metric-card .metric-value {
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1;
}

.metric-card .metric-label {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

/* ── Detail Panel ── */
.detail-panel {
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  overflow: hidden;
}

.detail-header {
  padding: 1.5rem;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  flex-wrap: wrap;
}

.detail-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

@media (max-width: 600px) {
  .detail-actions {
    width: 100%;
    border-top: 1px solid var(--border);
    padding-top: 0.75rem;
    margin-top: 0.25rem;
  }
  .detail-actions .btn {
    flex: 1;
    justify-content: center;
    min-height: 44px;
  }
}

.detail-body { padding: 1.5rem; }

.detail-field {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.875rem 0;
  border-bottom: 1px solid var(--border);
}

.detail-field:last-child { border-bottom: none; }
.detail-field-label { font-size: 0.75rem; font-weight: 500; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: 0.04em; }
.detail-field-value { font-size: 0.9375rem; color: var(--text-primary); }

/* ── Kanban ── */
.kanban-board {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  padding-bottom: 1rem;
  min-height: calc(100vh - 180px);
}

.kanban-col {
  min-width: 280px;
  max-width: 280px;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.kanban-col-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0;
}

.kanban-col-title {
  font-size: 0.8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.kanban-col-count {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  background: var(--bg-tertiary);
  padding: 0.125rem 0.5rem;
  border-radius: 99px;
}

.kanban-cards {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  min-height: 100px;
  border-radius: var(--radius-md);
  padding: 0.25rem;
  transition: background var(--transition);
}

.kanban-cards.drag-over {
  background: var(--accent-light);
  border: 2px dashed var(--accent);
}

.kanban-card {
  background: var(--bg-primary);
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  padding: 0.875rem;
  cursor: grab;
  transition: all var(--transition);
  box-shadow: var(--shadow-sm);
}

.kanban-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}

.kanban-card.dragging {
  opacity: 0.5;
  cursor: grabbing;
}

/* ── Timeline ── */
.timeline {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.timeline-item {
  display: flex;
  gap: 1rem;
  padding-bottom: 1.25rem;
  position: relative;
}

.timeline-item::before {
  content: '';
  position: absolute;
  left: 15px;
  top: 32px;
  bottom: 0;
  width: 2px;
  background: var(--border);
}

.timeline-item:last-child::before { display: none; }

.timeline-body { flex: 1; padding-top: 0.25rem; }
.timeline-title { font-size: 0.9375rem; font-weight: 500; }
.timeline-sub   { font-size: 0.8125rem; color: var(--text-secondary); margin-top: 0.125rem; }
.timeline-time  { font-size: 0.75rem; color: var(--text-tertiary); margin-top: 0.25rem; }

/* ── Searchable Select ── */
.ss-wrap {
  position: relative;
}

.ss-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  cursor: pointer;
  user-select: none;
}

.ss-display { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.ss-arrow {
  flex-shrink: 0;
  color: var(--text-tertiary);
  transition: transform var(--transition);
}

.ss-wrap:has(.ss-dropdown:not([hidden])) .ss-arrow {
  transform: rotate(180deg);
}

.ss-dropdown {
  position: absolute;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  z-index: 9999;
  overflow: hidden;
}

.ss-search-wrap {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border);
  color: var(--text-tertiary);
}

.ss-search {
  border: none;
  outline: none;
  background: transparent;
  font-size: 0.875rem;
  color: var(--text-primary);
  font-family: inherit;
  width: 100%;
}

.ss-list {
  max-height: 220px;
  overflow-y: auto;
  padding: 0.25rem;
}

.ss-option {
  padding: 0.5rem 0.625rem;
  border-radius: var(--radius-sm);
  font-size: 0.875rem;
  cursor: pointer;
  transition: background var(--transition);
}

.ss-option:hover,
.ss-option.is-active  { background: var(--bg-secondary); }
.ss-option.ss-selected { background: var(--accent-light); color: var(--accent-dark); font-weight: 500; }
.ss-option[hidden]    { display: none; }

/* Gruppen-Kopfzeile (optionales `group`-Feld je Option) – nicht-interaktiv,
   analog <optgroup label> im nativen Select. */
.ss-group-label {
  padding: 0.375rem 0.625rem 0.25rem;
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-tertiary);
}
.ss-group-label:not(:first-child) { margin-top: 0.25rem; }
.ss-group-label[hidden] { display: none; }

/* „Keine Treffer" – sichtbar statt leerer Fläche bei 0 gefilterten Optionen. */
.ss-empty {
  padding: 0.75rem 0.625rem;
  font-size: 0.8125rem;
  color: var(--text-tertiary);
  text-align: center;
}

/* ── Card Scanner Overlay ── */
.csc-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.55);
  z-index: 1200;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0;
  animation: fadeIn 180ms ease;
}

@media (min-width: 640px) {
  .csc-overlay { align-items: center; padding: 1rem; }
}

.csc-panel {
  background: var(--bg-primary);
  width: 100%;
  max-width: 520px;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  overflow: hidden;
  animation: slideUp 220ms cubic-bezier(.22,.68,0,1.2);
  max-height: 92dvh;
  display: flex;
  flex-direction: column;
}

@media (min-width: 640px) {
  .csc-panel {
    border-radius: var(--radius-lg);
    max-height: 90vh;
    animation: scaleIn 180ms ease;
  }
}

@keyframes slideUp {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}
@keyframes scaleIn {
  from { transform: scale(.95); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}

.csc-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.25rem 0.75rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.csc-title {
  font-size: 1rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.csc-body {
  padding: 1.25rem;
  overflow-y: auto;
  flex: 1;
}
.csc-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.625rem;
  padding: 0.875rem 1.25rem;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

/* Slots */
.csc-slots {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.csc-slot {
  border: 2px dashed var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--bg-secondary);
  transition: border-color var(--transition);
  min-height: 140px;
  display: flex;
  flex-direction: column;
}
.csc-slot:focus-within { border-color: var(--accent); }

/* Empty state */
.csc-slot-empty {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 1rem 0.75rem;
}
.csc-slot-label { font-size: 0.8125rem; font-weight: 600; color: var(--text-primary); text-align: center; }

.csc-slot-btns {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: 100%;
  padding: 0 0.25rem;
}
.csc-slot-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  padding: 0.6rem 1rem;
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  background: var(--accent);
  color: #fff;
  transition: background var(--transition), transform var(--transition);
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  min-height: 44px;
  width: 100%;
}
.csc-slot-btn:hover   { background: var(--accent-dark); }
.csc-slot-btn:active  { transform: scale(.96); }
.csc-slot-btn-secondary {
  background: var(--bg-tertiary);
  color: var(--text-primary);
  border: 1px solid var(--border);
}
.csc-slot-btn-secondary:hover { background: var(--bg-secondary); border-color: var(--accent); color: var(--accent); }
.csc-slot-btn input[type="file"] {
  position: absolute;
  inset: 0;
  opacity: 0;
  width: 100%;
  height: 100%;
  cursor: pointer;
  font-size: 0;
}

/* Preview state */
.csc-slot-preview {
  flex: 1;
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 140px;
}
.csc-slot-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  flex: 1;
  display: block;
}
.csc-slot-preview-bar {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  background: rgba(0,0,0,.55);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.3rem 0.5rem;
}
.csc-slot-check {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: #fff;
}
.csc-slot-action-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border-radius: var(--radius-sm);
  background: rgba(255,255,255,.15);
  color: #fff;
  border: none;
  cursor: pointer;
  transition: background var(--transition);
  -webkit-tap-highlight-color: transparent;
}
.csc-slot-action-btn:hover   { background: rgba(255,255,255,.3); }
.csc-slot-action-btn input[type="file"] {
  position: absolute;
  inset: 0;
  opacity: 0;
  width: 100%;
  height: 100%;
  cursor: pointer;
  font-size: 0;
}
.csc-slot-action-danger:hover { background: rgba(239,68,68,.5); }

/* Scanning step */
.csc-scanning {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
  padding: 0.5rem 0 0.25rem;
}
.csc-scan-preview {
  position: relative;
  width: 240px;
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(0,0,0,.15);
}
.csc-scan-preview img { width: 100%; display: block; }
.csc-scan-line {
  position: absolute;
  left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  box-shadow: 0 0 10px var(--accent), 0 0 4px var(--accent);
  animation: scan-sweep 1.6s ease-in-out infinite;
}
@keyframes scan-sweep {
  0%   { top: 0%; opacity: 1; }
  48%  { opacity: 1; }
  50%  { top: 100%; opacity: 0; }
  50.01% { top: 0%; opacity: 0; }
  52%  { opacity: 1; }
  100% { top: 100%; opacity: 1; }
}
.csc-scanning-label {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Results step */
.csc-result-grid {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
}
.csc-result-row {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 0.5rem;
  align-items: baseline;
  padding: 0.375rem 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.875rem;
}
.csc-result-row:last-child { border-bottom: none; }
.csc-result-key   { color: var(--text-secondary); font-size: 0.8125rem; }
.csc-result-value { font-weight: 500; color: var(--text-primary); word-break: break-word; }
.csc-result-empty { color: var(--text-tertiary); font-style: italic; font-weight: 400; }

.csc-company-hint {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.625rem 0.75rem;
  background: var(--accent-light);
  border-radius: var(--radius-md);
  margin-top: 0.75rem;
  font-size: 0.8125rem;
  color: var(--accent-dark);
}

/* Scan-trigger button in form */
.csc-trigger-banner {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.875rem 1.125rem;
  background: linear-gradient(135deg, var(--accent-light) 0%, var(--bg-secondary) 100%);
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: all var(--transition);
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  margin-bottom: 0.25rem;
}
.csc-trigger-banner:hover { background: linear-gradient(135deg, var(--accent-light) 0%, var(--accent-light) 100%); }
.csc-trigger-banner:active { transform: scale(.98); }
.csc-trigger-icon {
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.csc-trigger-text strong { display: block; font-size: 0.9375rem; font-weight: 600; color: var(--text-primary); }
.csc-trigger-text span   { font-size: 0.8125rem; color: var(--text-secondary); }

/* Divider */
.csc-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--text-tertiary);
  font-size: 0.75rem;
  margin: 0.5rem 0;
}
.csc-divider::before, .csc-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* ── Text-Extract Trigger (neutral variant of .csc-trigger-banner) ── */
/* Same structure/size as .csc-trigger-banner; bg-secondary + border instead of accent gradient */
.csc-trigger-banner--text {
  background: var(--bg-secondary);
  border-color: var(--border);
}
.csc-trigger-banner--text:hover {
  background: var(--bg-tertiary);
  border-color: var(--border);
}
.csc-trigger-banner--text .csc-trigger-icon {
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}

/* ── Trigger-Row: Scan-Banner + Text-Extract-Banner nebeneinander (Kontakt) ── */
.csc-trigger-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.625rem;
  margin-bottom: 0;
}
/* Einzelner Trigger (gleiche Optik wie .csc-trigger-banner, aber kleiner wenn im Row-Kontext) */
.csc-trigger-row .csc-trigger-banner {
  margin-bottom: 0;
}
@media (max-width: 600px) {
  .csc-trigger-row {
    grid-template-columns: 1fr;
  }
}

/* ── Text-Extract Overlay (Textarea + Validation-Hint) ── */
/* Overlay-Markup reused: .csc-overlay / .csc-panel / .csc-header / .csc-footer – no new overlay CSS needed */
.cte-textarea {
  width: 100%;
  resize: vertical;
  min-height: 9rem;
  font-size: 0.875rem;
  line-height: 1.6;
  display: block;
}
.cte-validation-hint {
  font-size: 0.8125rem;
  color: var(--coral);
  margin-top: 0.375rem;
}

/* ── Followup Cards ── */
.followup-card {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.875rem 1rem;
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  transition: background var(--transition), border-color var(--transition);
}
.followup-card:hover { border-color: var(--accent); }
.followup-card.is-done { opacity: 0.55; }
.followup-card.is-overdue { border-left: 3px solid var(--danger); }
.followup-card.is-today   { border-left: 3px solid var(--warning, #f59e0b); }
.followup-card.is-upcoming { border-left: 3px solid var(--success, #10b981); }

.followup-check {
  flex-shrink: 0;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  border: 2px solid var(--border);
  cursor: pointer;
  margin-top: 0.125rem;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all var(--transition);
}
.followup-check:hover   { border-color: var(--accent); background: var(--accent-alpha, rgba(99,102,241,.1)); }
.followup-check.checked { background: var(--accent); border-color: var(--accent); }
.followup-check.checked::after { content: ''; display: block; width: 6px; height: 6px; border-radius: 50%; background: #fff; }

.followup-body    { flex: 1; min-width: 0; }
.followup-title   { font-size: 0.9375rem; font-weight: 500; color: var(--text-primary); margin-bottom: 0.25rem; }
.followup-meta    { font-size: 0.8125rem; color: var(--text-secondary); display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }
.followup-date    { font-size: 0.8125rem; font-weight: 500; }
.followup-date.red    { color: var(--danger); }
.followup-date.amber  { color: var(--warning, #f59e0b); }
.followup-date.green  { color: var(--success, #10b981); }

.followup-priority { font-size: 0.75rem; padding: 0.125rem 0.375rem; border-radius: var(--radius-sm); font-weight: 500; }
.followup-priority.high   { background: rgba(239,68,68,.12);  color: var(--danger); }
.followup-priority.medium { background: rgba(245,158,11,.12); color: var(--warning, #f59e0b); }
.followup-priority.low    { background: rgba(99,102,241,.12); color: var(--accent); }

.followup-actions { flex-shrink: 0; display: flex; gap: 0.25rem; }

/* Detail-Kopfzeile (.detail-header in dieser Datei, Konsument: pages/followups.js _renderDetail):
   Ticket 3.377.8 – KEIN min-width:0 auf dem Titel-Container. Mit min-width:0 darf der Flex-Item
   unter seine automatische Mindestgröße (Content-based Minimum, siehe CSS Flexbox 4.5) schrumpfen --
   auf schmalen Breiten (v.a. 375px) nimmt die Knopfgruppe dann fast die gesamte Zeile ein, der Titel
   bleibt nur ein paar Pixel breit und bricht zeichenweise um (kein word-break/overflow-wrap nötig,
   das war nie das Problem). Ohne min-width:0 (Default: auto) verweigert der Titel-Container das
   Schrumpfen unter seine Wortbreite – der Header bricht dann stattdessen auf zwei Zeilen um
   (Titel oben, Knopfgruppe darunter), Titel wickelt normal an Leerzeichen. */
.followup-detail-title   { flex: 1 1 0%; }
.followup-detail-actions { display: flex; gap: 0.5rem; flex-shrink: 0; }

/* Stats chips on followups page */
.followup-stats { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 1.25rem; }
.followup-stat-chip {
  display: flex; flex-direction: column; align-items: center;
  padding: 0.75rem 1.25rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  min-width: 6rem;
  cursor: pointer;
  transition: border-color var(--transition);
}
.followup-stat-chip:hover  { border-color: var(--accent); }
.followup-stat-chip.active { border-color: var(--accent); background: rgba(99,102,241,.06); }
.followup-stat-chip .stat-num   { font-size: 1.5rem; font-weight: 700; line-height: 1; }
.followup-stat-chip .stat-label { font-size: 0.75rem; color: var(--text-secondary); margin-top: 0.25rem; }
.followup-stat-chip.danger .stat-num { color: var(--danger); }
.followup-stat-chip.amber  .stat-num { color: var(--warning, #f59e0b); }

/* Nav badge */
.nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.125rem;
  height: 1.125rem;
  padding: 0 0.25rem;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  margin-left: auto;
}

/* Bottom-nav badge (positioned over icon) */
.bottom-nav-item { position: relative; }
.bottom-nav-badge {
  position: absolute;
  top: 4px;
  right: calc(50% - 20px);
  min-width: 1rem;
  height: 1rem;
  padding: 0 0.2rem;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 700;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

/* ── Skeleton Loading ── */
@keyframes shimmer {
  from { background-position: -200% 0; }
  to   { background-position:  200% 0; }
}
.skeleton {
  background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--bg-secondary) 50%, var(--bg-tertiary) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.4s infinite linear;
  border-radius: var(--radius-sm);
}
.skeleton-text   { height: 0.875rem; border-radius: 4px; }
.skeleton-avatar { border-radius: 50%; }
.skeleton-card   { height: 72px; border-radius: var(--radius-md); }

/* ── Bottom Sheet (modal on mobile) ── */
@keyframes sheetIn {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

@media (max-width: 900px) {
  /* 16px input font-size prevents iOS auto-zoom on focus */
  .input, .select, .textarea {
    font-size: 1rem;
  }

  /* Toast above bottom nav */
  .toast-root {
    bottom: calc(72px + env(safe-area-inset-bottom) + 0.5rem);
    left: 1rem;
    right: 1rem;
    align-items: stretch;
  }
  .toast {
    max-width: 100%;
    width: 100%;
  }

  /* Modal → Bottom Sheet */
  .modal-backdrop {
    align-items: flex-end;
    padding: 0;
  }
  .modal {
    max-width: 100%;
    width: 100%;
    max-height: 92dvh;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    animation: sheetIn 280ms cubic-bezier(0.32, 0.72, 0, 1);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .modal::before {
    content: '';
    display: block;
    width: 36px;
    height: 4px;
    background: var(--bg-tertiary);
    border-radius: 2px;
    margin: 0.75rem auto 0;
    flex-shrink: 0;
    pointer-events: none;
  }
}

/* ── Kanban mobile: stack columns vertically ── */
@media (max-width: 600px) {
  .kanban-board {
    flex-direction: column;
    overflow-x: visible;
    min-height: auto;
    padding-bottom: 0.5rem;
  }
  .kanban-col {
    min-width: 100%;
    max-width: 100%;
  }
}

/* ── Swipe action overlay (followup cards) ── */
.swipe-wrap {
  position: relative;
  overflow: hidden;
}
.swipe-action {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  font-size: 0.8125rem;
  font-weight: 600;
  color: #fff;
  padding: 0 1.25rem;
  pointer-events: none;
  opacity: 0;
  transition: opacity 150ms ease;
}
.swipe-action.done-action  { background: var(--teal);  justify-content: flex-end;  }
.swipe-action.snooze-action{ background: var(--amber); justify-content: flex-start;}
.swipe-action.visible      { opacity: 1; }

/* ── Pagination ── */
.pagination-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--border);
}
.pagination-info {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
  flex: 1;
  white-space: nowrap;
}
.pagination-controls {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
.pagination-controls .btn.active {
  background: var(--accent);
  color: #fff;
  pointer-events: none;
  border-color: transparent;
}
.pagination-ellipsis {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
  padding: 0 0.25rem;
}
.pagination-perpage {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
@media (max-width: 600px) {
  .pagination-bar { gap: 0.5rem; padding: 0.625rem 0.75rem; }
  .pagination-info { flex: 0 0 100%; }
  .pagination-ellipsis { display: none; }
}

/* ── Quality Popover (detail action bar) ── */
.quality-popover-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.quality-popover-trigger {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
}
.quality-popover {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 280px;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 1rem;
  z-index: 200;
  text-align: left;
}
.quality-popover-wrap.open .quality-popover { display: block; }
.quality-popover-title {
  font-weight: 600;
  font-size: 0.875rem;
  margin-bottom: 0.75rem;
  color: var(--text-primary);
}

/* ── Quality Sidebar in Edit Form ── */
.form-quality-grid { /* override: no max-width */ }
.form-quality-inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  align-items: start;
}
.form-quality-grid .form-quality-inner {
  grid-template-columns: 1fr 260px;
}
.quality-edit-sidebar { position: sticky; top: 1rem; }
@media (max-width: 900px) {
  .form-quality-grid .form-quality-inner { grid-template-columns: 1fr; }
  .quality-edit-sidebar { position: static; width: 100%; max-width: 100%; }
}

/* ── Quality Breakdown (detail view) ── */
.quality-breakdown-wrap {
  margin-top: 0.5rem;
}
.quality-progress-wrap {
  height: 6px;
  background: var(--bg-tertiary);
  border-radius: 999px;
  overflow: hidden;
  margin-bottom: 0.75rem;
}
.quality-progress-bar {
  height: 100%;
  border-radius: 999px;
  transition: width 0.4s ease;
}
.quality-progress-bar.quality-high { background: var(--teal, #009688); }
.quality-progress-bar.quality-med  { background: #f59e0b; }
.quality-progress-bar.quality-low  { background: var(--coral, #e53e3e); }
.quality-breakdown-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.25rem 1rem;
}
.quality-breakdown-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.8125rem;
  padding: 0.2rem 0;
}
.quality-breakdown-label {
  color: var(--text-secondary);
}
.quality-pts-filled {
  font-weight: 600;
  color: var(--text-primary);
}
.quality-pts-empty {
  color: var(--text-tertiary);
}
.quality-pts-invalid {
  font-weight: 500;
  color: #f59e0b;
}

/* ── AI Suggestions Modal ── */
.ai-suggestions-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.ai-suggestion-row {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.625rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background 0.15s;
}
.ai-suggestion-row:hover {
  background: var(--bg-secondary);
}
.ai-suggestion-row input[type="checkbox"] {
  margin-top: 0.2rem;
  flex-shrink: 0;
  accent-color: var(--accent);
  width: 15px;
  height: 15px;
}
.ai-suggestion-content {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}
.ai-suggestion-label {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.ai-suggestion-value {
  font-size: 0.875rem;
  color: var(--text-primary);
  word-break: break-all;
}

/* ── Hand-wave button icon ── */
@keyframes hand-wave {
  0%   { transform: rotate(0deg); }
  15%  { transform: rotate(14deg); }
  30%  { transform: rotate(-8deg); }
  45%  { transform: rotate(12deg); }
  60%  { transform: rotate(-4deg); }
  75%  { transform: rotate(10deg); }
  100% { transform: rotate(0deg); }
}
.hand-wave-icon {
  display: inline-block;
  vertical-align: middle;
  margin-right: 5px;
  animation: hand-wave 2s ease-in-out infinite;
  transform-origin: 70% 80%;
}

/* ── Live quality score badge ── */
.quality-live-badge {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}
.quality-live-bar-wrap {
  width: 52px;
  height: 5px;
  border-radius: 3px;
  background: var(--border);
  overflow: hidden;
}
.quality-live-bar-fill {
  height: 100%;
  width: 0%;
  border-radius: 3px;
  transition: width 0.25s ease, background-color 0.25s ease;
}
.quality-live-pct {
  font-variant-numeric: tabular-nums;
  min-width: 2.5rem;
}

/* ── Native Mobile List ─────────────────────────────────────── */
/* Structural classes – safe on all screen sizes */
.native-list {
  background: var(--bg-primary);
  overflow: hidden;
}
.native-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  border-bottom: 0.5px solid var(--border);
  min-height: 60px;
  background: var(--bg-primary);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  position: relative;
  overflow: hidden;
  transition: background var(--transition);
}
.native-row:last-child { border-bottom: none; }
.native-row:active { background: var(--bg-secondary); }
.native-row-left  { flex-shrink: 0; }
.native-row-mid   { flex: 1; min-width: 0; }
.native-row-right {
  flex-shrink: 0;
  text-align: right;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.25rem;
}
.native-row-name {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.native-row-sub {
  display: block;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 0.125rem;
}
.native-row-ts {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* Aliasse für E-Mail-Liste (Spec 0900, S2) */
.native-row-avatar    { flex-shrink: 0; }
.native-row-center    { flex: 1; min-width: 0; }
.native-row-title {
  display: block;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.native-row-timestamp {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}
.native-row--unread {
  border-left: 3px solid var(--accent);
  padding-left: calc(1rem - 3px);
}
.native-row--unread .native-row-title { font-weight: 600; }

/* ── FAB-Freiraum für mobile Listen (Ticket 3.303) ──────────────
   #fab (index.php, position:fixed relativ zum Viewport – kein Vorfahre setzt
   transform/contain, also kein eigener Containing-Block) liegt bei bottom:
   calc(72px + safe-area + 1rem), Hoehe 56px (.fab, layout.css) → Oberkante
   144px + safe-area über der Viewport-Unterkante. .ds-content-body (nav.css)
   ist der scrollende Container; ihr eigenes unteres Padding deckt nur die
   Bottom-Nav ab (die im normalen Fluss direkt darunter sitzt, ~56px + safe-
   area hoch) – NICHT den FAB, der oberhalb davon frei über dem Scrollinhalt
   schwebt. Ohne Zusatz-Abstand verschwindet die letzte Listenzeile beim
   Herunterscrollen unter dem Knopf.
   Rechnung: nötiges Padding = FAB-Oberkante (144px+safe) minus Bottom-Nav-
   Hoehe (~56px+safe) = 88px – der Sicherheitsabstand-Anteil kuerzt sich weg,
   da beide Seiten ihn gleichermassen tragen (identischer env()-Ausdruck).
   +1.5rem Puffer, damit die Zeile sichtbar frei liegt statt bündig an den
   FAB anzuschlagen.
   Anker body:has(#fab.visible) statt Pauschal-Padding auf jeder mobilen
   Liste – greift nur wenn tatsaechlich ein FAB sichtbar ist; das @media-Gate
   hält es zusätzlich auf Mobile beschraenkt (der FAB ist ab 901px ohnehin
   display:none, aber .visible kann unabhängig von der Breite gesetzt sein).
   .native-list ist die zentrale Listen-Container-Klasse des Mobile-Patterns
   (.card.native-list-card > .native-list > .native-row, design-system.md) –
   ein Fix hier deckt alle Konsumenten app-weit ab (Kontakte, Firmen, Deals,
   Belege, ...), keine modul-spezifischen Patches nötig.
   🔒 MUSS synchron bleiben, falls sich .fab (layout.css: bottom/Hoehe) oder
   die Bottom-Nav-Hoehe (nav.css .ds-bottom-item min-height) je ändern. */
@media (max-width: 900px) {
  body:has(#fab.visible) .native-list {
    padding-bottom: calc(88px + 1.5rem);
  }
}

/* Sticky alphabetical section header */
.native-section-header {
  position: sticky;
  top: 49px;
  z-index: 10;
  padding: 0.2rem 1rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  background: var(--bg-secondary);
  border-bottom: 0.5px solid var(--border);
  user-select: none;
}

/* Horizontal scrolling filter chips */
.chip-filter-strip {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  padding: 0.625rem 1rem;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  border-bottom: 0.5px solid var(--border);
}
.chip-filter-strip::-webkit-scrollbar { display: none; }

.filter-chip {
  display: inline-flex;
  align-items: center;
  padding: 0.3rem 0.75rem;
  border-radius: 99px;
  font-size: 0.8125rem;
  font-weight: 500;
  white-space: nowrap;
  border: 1.5px solid var(--border);
  background: var(--bg-primary);
  color: var(--text-secondary);
  cursor: pointer;
  min-height: 32px;
  transition: all var(--transition);
  -webkit-tap-highlight-color: transparent;
}
.filter-chip.active {
  background: var(--accent-light);
  color: var(--accent-dark);
  border-color: transparent;
}
.filter-chip.active-teal   { background: var(--teal-light);  color: var(--teal);  border-color: transparent; }
.filter-chip.active-amber  { background: var(--amber-light); color: var(--amber); border-color: transparent; }
.filter-chip.active-coral  { background: var(--coral-light); color: var(--coral); border-color: transparent; }
/* Icon-Span in Filter-Chips und Filter-Tabs: verhindert Baseline-Gap beim SVG */
.filter-chip-icon { display: inline-flex; align-items: center; flex-shrink: 0; }

/* Additional swipe overlays (left-swipe = flex-end, right-swipe = flex-start) */
.swipe-action.delete-action { background: var(--coral);  justify-content: flex-end;   }
.swipe-action.stage-action  { background: var(--accent); justify-content: flex-end;   }

/* ── Gespeicherte Segmente (P7) ── Chip-Leiste über Filterzeile ─── */
/* Neue Komponente: Segment-Strip + Chip + Speichern-Button; analog .chip-filter-strip */
.segment-strip {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding: 0 0 0.625rem 0;
  flex-wrap: nowrap;
  margin-bottom: 0.625rem;
}
.segment-strip::-webkit-scrollbar { display: none; }

.segment-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  padding: 0.25rem 0.5rem 0.25rem 0.75rem;
  border-radius: var(--radius-pill);
  font-size: 0.8125rem;
  font-weight: 500;
  white-space: nowrap;
  border: 1.5px solid var(--border);
  background: var(--bg-primary);
  color: var(--text-secondary);
  cursor: pointer;
  min-height: 30px;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
  -webkit-tap-highlight-color: transparent;
}
.segment-chip:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.segment-chip.active {
  background: var(--accent-light);
  color: var(--accent-dark);
  border-color: transparent;
}
.segment-chip.active:hover {
  background: var(--accent-light);
  color: var(--accent-dark);
}

.segment-chip-del {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: transparent;
  color: var(--text-tertiary);
  transition: background var(--transition), color var(--transition);
  flex-shrink: 0;
  cursor: pointer;
}
.segment-chip-del:hover {
  background: var(--danger-light);
  color: var(--danger);
}

.segment-save-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  padding: 0.25rem 0.625rem;
  border-radius: var(--radius-pill);
  font-size: 0.8125rem;
  font-weight: 500;
  white-space: nowrap;
  border: 1.5px dashed var(--border);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  min-height: 30px;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
  -webkit-tap-highlight-color: transparent;
}
.segment-save-btn:hover {
  background: var(--accent-light);
  color: var(--accent-dark);
  border-color: var(--accent-dark);
  border-style: solid;
}

/* ── ds-rich-editor (Quill v2) ─────────────────────────── */
.ds-rich-editor { display: block; position: relative; }
.ds-rich-editor .ds-rich-editor-body {
  min-height: 120px;
  max-height: 280px;
  overflow-y: auto;
}
/* allowTables: kein internes Scroll-Clipping – quill-table-better positioniert sein
   schwebendes Menü relativ zu diesem Container und reagiert nicht auf dessen internen
   Scroll. Ohne diese Regel landet das Menü weit außerhalb des Viewports (verifiziert). */
.ds-rich-editor.has-tables .ds-rich-editor-body {
  max-height: none;
  overflow-y: visible;
}
.ds-rich-editor .ds-rich-editor-source {
  display: none;
  width: 100%;
  min-height: 160px;
  max-height: 320px;
  padding: 0.625rem 0.75rem;
  font: 0.8125rem/1.5 ui-monospace, Menlo, Consolas, monospace;
  color: var(--text-primary);
  background: var(--bg-primary);
  border: 1px solid var(--border);
  /* Ticket 3.373: kein border-radius – Quelltext-Ansicht ersetzt den (jetzt
     eckigen) Editor-Körper 1:1, muss also dieselbe Kontur tragen. */
  resize: vertical;
}
.ds-rich-editor.is-source-mode .ds-rich-editor-body { display: none; }
.ds-rich-editor.is-source-mode .ds-rich-editor-source { display: block; }
.ds-rich-editor-source-toggle {
  position: absolute;
  top: 4px;
  right: 4px;
  z-index: 2;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
}
.ds-rich-editor-source-toggle:hover {
  color: var(--accent);
  background: var(--bg-secondary);
}
.ds-rich-editor.is-source-mode .ds-rich-editor-source-toggle {
  color: var(--accent);
  border-color: var(--accent);
}
.ds-rich-editor .ql-toolbar.ql-snow,
.ds-rich-editor .ql-container.ql-snow {
  border-color: var(--border);
}
/* Ticket 3.373: Editor-Körper bewusst ECKIG (kein border-radius mehr) – die
   rechteckige Werkzeugleiste fuellte die gerundete Ecke nie aus (heller Fleck
   neben den Toolbar-Buttons, sichtbar v.a. im Mail-Compose). Eckig sieht bei der
   Werkzeugleiste bündig aus, kein Overflow-Kniff nötig. Gilt app-weit für
   JEDE ds-rich-editor-Instanz (P-5, keine Mail-Sonderregel). */
.ds-rich-editor .ql-toolbar.ql-snow {
  background: var(--bg-secondary);
}
.ds-rich-editor .ql-container.ql-snow {
  background: var(--bg-primary);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 0.875rem;
}
.ds-rich-editor .ql-editor { min-height: 120px; }
/* Issue 3: kompakterer Editor für Einleitung/Fußzeile (Invoicing/Offers) */
.invoicing-rich-editor-small .ql-editor { min-height: 72px; }

/* HTML <fieldset> Browser-Quirk: hat per Default min-width:min-content,
   was Quill-Toolbar mit fixed-width Buttons über den Fieldset-Rand zwingt.
   Pflicht-Reset für .ds-fieldset wenn schmal-zwingende Children drin sind. */
.ds-fieldset {
  min-width: 0;
}
/* Rich-Editor innerhalb .ds-fieldset: Containment + Zeilenumbruch.
   Verhindert dass Editor (oder Inhalt) über Fieldset-Rand hinaus läuft. */
.ds-fieldset .ds-rich-editor {
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  width: 100%;
}
.ds-fieldset .ds-rich-editor .ql-toolbar.ql-snow,
.ds-fieldset .ds-rich-editor .ql-container.ql-snow,
.ds-fieldset .ds-rich-editor .ql-editor {
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  word-wrap: break-word;
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* Toolbar darf auf Mobile/schmal wrappen (statt Overflow zu erzwingen). */
.ds-fieldset .ds-rich-editor .ql-toolbar.ql-snow {
  flex-wrap: wrap;
}
/* Form-Row-Content muss schrumpfen können – sonst drücken Quill-Internas
   das Layout auseinander (klassisches flex min-content-Problem). */
.ds-fieldset .ds-form-row-content {
  min-width: 0;
  max-width: 100%;
}
.ds-fieldset .ds-form-row--description {
  min-width: 0;
  max-width: 100%;
}
.ds-rich-editor .ql-editor.ql-blank::before {
  color: var(--text-tertiary);
  font-style: normal;
}
/* Firefox-Fix: `.ds-form-row--description` setzt `display:flex; flex:1` für
   Panel-Hoehe-Auffuellung (Slide-In-Panel-Pattern). Im Invoicing-/Receipts-
   Editor ist der Rich-Editor aber im <fieldset> (Page-as-Editor) – Firefox'
   anonymous fieldset content-box kollidiert mit dem flex-1-Child und der
   Editor springt visuell über den Fieldset-Rand. Im fieldset-Kontext den
   Description-Modifier auf Block-Layout zurücksetzen. */
.ds-fieldset .ds-form-row--description,
.ds-fieldset .ds-form-row--description .ds-form-row-content,
.ds-fieldset .ds-form-row--description ds-rich-editor {
  display: block;
  flex: none;
  min-height: 0;
}
.ds-fieldset .ds-form-row--description ds-rich-editor .ql-editor,
.ds-fieldset .ds-form-row--description ds-rich-editor .ProseMirror,
.ds-fieldset .ds-form-row--description ds-rich-editor [contenteditable] {
  flex: none;
}
.ds-rich-editor:focus-within .ql-toolbar.ql-snow,
.ds-rich-editor:focus-within .ql-container.ql-snow {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}
/* Quill-Toolbar Buttons im Dark Mode */
.ds-rich-editor .ql-snow .ql-stroke { stroke: var(--text-secondary); }
.ds-rich-editor .ql-snow .ql-fill   { fill:   var(--text-secondary); }
.ds-rich-editor .ql-snow .ql-picker { color:  var(--text-secondary); }
.ds-rich-editor .ql-snow .ql-active .ql-stroke,
.ds-rich-editor .ql-snow button:hover .ql-stroke { stroke: var(--accent); }
.ds-rich-editor .ql-snow .ql-active .ql-fill,
.ds-rich-editor .ql-snow button:hover .ql-fill   { fill:   var(--accent); }

/* Header-Picker (opt-in via allowHeaders) – ungestylter Quill-Dropdown an
   den Toolbar-Button-Look angleichen (Höhe/Padding/Hover wie .ql-toolbar button). */
.ds-rich-editor .ql-snow .ql-picker.ql-header {
  height: 24px;
  color: var(--text-secondary);
}
.ds-rich-editor .ql-snow .ql-picker.ql-header .ql-picker-label {
  display: flex;
  align-items: center;
  padding: 0 0.375rem;
  border-radius: var(--radius-sm);
  color: inherit;
}
.ds-rich-editor .ql-snow .ql-picker.ql-header .ql-picker-label:hover,
.ds-rich-editor .ql-snow .ql-picker.ql-header.ql-expanded .ql-picker-label {
  color: var(--accent);
  background: var(--bg-secondary);
}
.ds-rich-editor .ql-snow .ql-picker.ql-header .ql-picker-label .ql-stroke {
  stroke: currentColor;
}
.ds-rich-editor .ql-snow .ql-picker-options {
  background: var(--bg-primary);
  border-color: var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
}
.ds-rich-editor .ql-snow .ql-picker.ql-header .ql-picker-item {
  color: var(--text-secondary);
}
.ds-rich-editor .ql-snow .ql-picker.ql-header .ql-picker-item:hover,
.ds-rich-editor .ql-snow .ql-picker.ql-header .ql-picker-item.ql-selected {
  color: var(--accent);
}

/* ── Toolbar-Zonen (Ticket 3.310) ────────────────────────────────────────
   Loest die vormals auf-/zuklappbare "Mehr Formate"-Zeile 2 (Board-Ticket 595
   Paket C) ab: die Toolbar ist jetzt EINZEILIG mit automatischem Umbruch. Linke
   Zone (`.ql-toolbar-zone-left`) trägt alle Format-/Einfüge-Knöpfe in
   fachlich zusammengehoerigen `.ql-formats`-Clustern und bricht bei wenig
   Platz mehrzeilig um (`flex-wrap:wrap`); rechte Zone (`.ql-toolbar-zone-right`,
   bei diesem Editor aktuell leer/ungenutzt – Struktur-Parität zu
   `.ql-toolbar-zone-right` in `_notes.css`) bleibt IMMER in Zeile 1 stehen
   (`margin-left:auto`, kein Umbruch). Zwischen benachbarten `.ql-formats`-
   Clustern der linken Zone sitzt eine duenne Trennlinie – die Grenze ergibt
   sich automatisch aus der Cluster-Bildung in `ds-rich-editor.js
   _reorganizeToolbar()` (P-5: eine Regel deckt jede Cluster-Grenze ab, keine
   Divider-Sonderfälle pro Knopf-Gruppe). */
.ds-rich-editor .ql-toolbar.ql-snow {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}
.ql-toolbar-zone-left {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  flex: 1 1 auto;
  min-width: 0;
}
.ql-toolbar-zone-right {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  flex: 0 0 auto;
  margin-left: auto;
}
.ql-toolbar-zone-left .ql-formats,
.ql-toolbar-zone-right .ql-formats {
  margin-right: 0 !important; /* Quill-Default 15px-Gap ersetzt durch gap: oben */
}
.ql-toolbar-zone-left > .ql-formats + .ql-formats {
  padding-left: 0.5rem;
  border-left: 1px solid var(--border);
}

/* ── Schriftfarbe (Board-Ticket 595 Paket A, opt-in via allowColors) ─────
   Seit Ticket 3.310 öffnet der Knopf den app-weit geteilten
   `window.ColorPicker` (ds-color-picker.js) – kein eigenes Dropdown mehr,
   daher nur noch der Trigger-Button selbst zu stylen. */
.ds-rich-editor-color-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  cursor: pointer;
}
.ds-rich-editor-color-btn:hover { color: var(--accent); }

/* Tabellen-Darstellung im Editor (opt-in via allowTables) – Border + Padding,
   Dark-Mode automatisch korrekt via CSS-Variablen (kein hardcodiertes Weiß). */
.ds-rich-editor .ql-editor table {
  width: 100%;
  border-collapse: collapse;
  margin: 0.5rem 0;
}
.ds-rich-editor .ql-editor table td,
.ds-rich-editor .ql-editor table th {
  border: 1px solid var(--border);
  padding: 0.375rem 0.5rem;
  vertical-align: top;
}
.ds-rich-editor .ql-editor th {
  background: var(--bg-secondary);
}

/* ── quill-table-better (opt-in via allowTables) ──────────────
   Vendor-Lib (app/assets/js/lib/quill-table-better.js) portalt ihre UI
   (Kontextmenü, Grid-Picker, Properties-Form, Color-Picker) per JS in
   quill.container (= .ql-container), NICHT in document.body – daher hier
   scoped unter .ds-rich-editor statt globalem <link> auf die Vendor-CSS.
   Positionierung/Layout 1:1 aus quill-table-better.css übernommen (fkt.
   notwendig, JS setzt nur top/left inline, position:absolute kommt von hier).
   Farben/Border/Shadow durch App-Tokens ersetzt (Vendor-CSS ist hardcoded hell). */
.ds-rich-editor button.ql-table-better { position: relative; }

/* Toolbar-Icon an bestehenden .ql-toolbar-Button-Look angleichen */
.ds-rich-editor .ql-snow .ql-picker.ql-table-better,
.ds-rich-editor .ql-toolbar .ql-table-better svg .ql-stroke {
  stroke: var(--text-secondary);
}
.ds-rich-editor .ql-toolbar .ql-table-better:hover svg .ql-stroke,
.ds-rich-editor .ql-toolbar .ql-table-better.ql-active svg .ql-stroke {
  stroke: var(--accent);
}

/* Grid-Picker beim Tabellen-Einfügen (N×M Zellen-Auswahl unter dem Toolbar-Button) */
.ds-rich-editor .ql-table-select-container {
  flex-direction: column;
  width: 190px;
  padding: 2px;
  position: absolute;
  top: 24px;
  z-index: 10;
  box-sizing: border-box;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-primary);
  box-shadow: var(--shadow-md);
}
.ds-rich-editor .ql-table-select-container .ql-table-select-list {
  display: flex;
  flex-wrap: wrap;
}
.ds-rich-editor .ql-table-select-container .ql-table-select-label {
  width: 100%;
  line-height: 16px;
  text-align: center;
  color: var(--text-secondary);
  margin-top: 2px;
}
.ds-rich-editor .ql-table-select-container span {
  width: 16px;
  height: 16px;
  border: 1px solid var(--border);
  box-sizing: border-box;
  margin: 1px;
}

/* Kontextmenü (Rechtsklick auf Zelle) – Zeilen/Spalten/Merge/Delete-Buttons */
.ds-rich-editor .ql-table-menus-container {
  position: absolute;
  display: flex;
  align-items: center;
  height: 40px;
  width: fit-content;
  padding: 4px;
  box-sizing: border-box;
  z-index: 20;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-primary);
  box-shadow: var(--shadow-md);
}
.ds-rich-editor .ql-table-menus-container svg .ql-stroke {
  stroke: var(--text-secondary);
}
.ds-rich-editor .ql-table-menus-container svg .ql-fill {
  fill: var(--text-secondary);
}
.ds-rich-editor .ql-table-divider {
  background: var(--border);
  height: 24px;
  width: 1px;
}
.ds-rich-editor .ql-table-dropdown,
.ds-rich-editor .ql-table-dropdown-properties {
  display: flex;
  height: 100%;
  align-items: center;
  position: relative;
  padding: 0 4px;
  cursor: pointer;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
}
.ds-rich-editor .ql-table-dropdown:hover,
.ds-rich-editor .ql-table-dropdown-properties:hover {
  background: var(--bg-secondary);
  color: var(--accent);
}
.ds-rich-editor .ql-table-dropdown-text,
.ds-rich-editor .ql-table-dropdown-properties-text {
  flex: 1;
  height: 100%;
  margin-right: 7px;
  display: flex;
  align-items: center;
}
.ds-rich-editor .ql-table-dropdown-list,
.ds-rich-editor .ql-table-dropdown-properties-list {
  position: absolute;
  left: 0;
  bottom: 0;
  transform: translateY(100%);
  margin: 0;
  padding: 0;
  width: 170px;
  z-index: 21;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-primary);
  box-shadow: var(--shadow-md);
}
.ds-rich-editor .ql-table-dropdown-list li,
.ds-rich-editor .ql-table-dropdown-properties-list li {
  list-style: none;
  line-height: 30px;
  padding: 0 10px;
  cursor: pointer;
  color: var(--text-primary);
}
.ds-rich-editor .ql-table-dropdown-list li:hover,
.ds-rich-editor .ql-table-dropdown-properties-list li:hover {
  background: var(--bg-secondary);
  color: var(--accent);
}
.ds-rich-editor .ql-table-dropdown-list .ql-table-header-row,
.ds-rich-editor .ql-table-dropdown-properties-list .ql-table-header-row {
  display: flex;
  justify-content: space-between;
}
.ds-rich-editor .ql-table-dropdown-label,
.ds-rich-editor .ql-table-dropdown-properties-label {
  width: 100%;
  min-width: 100%;
  line-height: 24px;
  font-weight: 600;
  margin-bottom: 6px;
  display: block;
  color: var(--text-tertiary);
}
.ds-rich-editor .ql-table-dropdown-properties {
  width: 80px;
  height: 30px;
  border: 1px solid var(--border);
  box-sizing: border-box;
}
.ds-rich-editor .ql-table-disabled {
  background: var(--bg-secondary);
  pointer-events: none;
}
.ds-rich-editor .ql-table-button-disabled {
  background: var(--bg-secondary) !important;
  pointer-events: none;
}
.ds-rich-editor .ql-table-button-disabled svg .ql-fill { fill: var(--text-tertiary) !important; }
.ds-rich-editor .ql-table-button-disabled svg .ql-stroke { stroke: var(--text-tertiary) !important; }

/* Zell-/Spalten-Resize-Hilfslinien beim Ziehen */
.ds-rich-editor .ql-operate-line-container { position: absolute; z-index: 10; }
.ds-rich-editor .ql-operate-line-container .ql-operate-line { background: var(--accent); }
.ds-rich-editor .ql-operate-block {
  position: absolute;
  z-index: 10;
  border: 1px solid var(--text-tertiary);
  cursor: nwse-resize;
}
.ds-rich-editor .ql-operate-block-move { cursor: crosshair; border: none; }
.ds-rich-editor .ql-operate-drag-table { border: 1px dashed var(--text-secondary); position: absolute; }

/* Zell-Selektion (Mehrfachauswahl per Drag) */
.ds-rich-editor .ql-cell-focused,
.ds-rich-editor .ql-cell-selected { position: relative; }
.ds-rich-editor .ql-cell-focused::after,
.ds-rich-editor .ql-cell-selected::after {
  content: '';
  pointer-events: none;
  position: absolute;
  inset: 0;
  background-color: color-mix(in srgb, var(--accent) 18%, transparent);
}
.ds-rich-editor .ql-cell-focused::after { border: 1px solid var(--accent); }

/* Tabellen-Eigenschaften-Formular (Rahmen/Hintergrund je Zelle einstellen) */
.ds-rich-editor .ql-table-properties-form {
  width: 320px;
  position: absolute;
  left: 50%;
  padding-bottom: 8px;
  z-index: 21;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-primary);
  box-shadow: var(--shadow-md);
}
.ds-rich-editor .ql-table-properties-form .properties-form-header {
  height: 40px;
  line-height: 40px;
  padding: 0 12px;
  border-bottom: 1px solid var(--border);
  margin: 0;
  box-sizing: border-box;
  color: var(--text-primary);
  font-size: 0.875rem;
  font-weight: 600;
}
.ds-rich-editor .ql-table-properties-form .properties-form-row {
  display: flex;
  flex-wrap: wrap;
  padding: 8px 12px;
  justify-content: space-between;
}
.ds-rich-editor .ql-table-properties-form .properties-form-row .ql-table-check-container {
  display: flex;
  border: 1px solid var(--border);
  align-items: center;
  border-radius: var(--radius-sm);
}
.ds-rich-editor .ql-table-properties-form .properties-form-row .ql-table-check-container .ql-table-tooltip-hover {
  padding: 6px 10px;
  cursor: pointer;
  position: relative;
  display: flex;
}
.ds-rich-editor .ql-table-properties-form .properties-form-row .ql-table-check-container .ql-table-tooltip-hover:hover {
  background: var(--bg-secondary);
}
.ds-rich-editor .ql-table-properties-form .properties-form-row .ql-table-check-container .ql-table-btns-checked {
  background: var(--accent-light);
}
.ds-rich-editor .ql-table-properties-form .properties-form-row .ql-table-check-container .ql-table-btns-checked > svg path {
  stroke: var(--accent);
}
.ds-rich-editor .ql-table-properties-form .properties-form-row-full .ql-table-color-container { width: 100%; }
.ds-rich-editor .ql-table-properties-form .properties-form-row-full .ql-table-color-container .property-input { width: 100%; }
.ds-rich-editor .ql-table-properties-form .properties-form-action-row {
  display: flex;
  justify-content: space-around;
  padding: 0 12px;
}
.ds-rich-editor .ql-table-properties-form .properties-form-action-row > button {
  background: transparent;
  outline: none;
  border: none;
  height: 30px;
  cursor: pointer;
  flex: 1;
  color: var(--text-primary);
  border-radius: var(--radius-sm);
}
.ds-rich-editor .ql-table-properties-form .properties-form-action-row > button > span {
  margin: 0 2px;
  display: flex;
  justify-content: center;
}
.ds-rich-editor .ql-table-properties-form .properties-form-action-row > button:hover {
  background: var(--bg-secondary);
}
.ds-rich-editor .ql-table-properties-form .properties-form-action-row > button[disabled] {
  background: transparent;
  color: var(--text-tertiary);
  cursor: not-allowed;
}

/* Input-Felder im Properties-Formular (Border-Breite/Farbe etc.) */
.ds-rich-editor .ql-table-input,
.ds-rich-editor .ql-table-color-container .label-field-view-color .property-input,
.ds-rich-editor .ql-table-properties-form .property-input {
  width: 80px;
  height: 30px;
  border: 1px solid var(--border);
  outline: none;
  padding-left: 6px;
  background: var(--bg-primary);
  color: var(--text-primary);
  border-radius: var(--radius-sm);
}
.ds-rich-editor .ql-table-input-focus,
.ds-rich-editor .ql-table-input:focus,
.ds-rich-editor .ql-table-color-container .label-field-view-color .property-input:focus,
.ds-rich-editor .ql-table-properties-form .property-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-light);
}
.ds-rich-editor .label-field-view { position: relative; }
.ds-rich-editor .label-field-view-input-wrapper { position: relative; height: 100%; }
.ds-rich-editor .label-field-view-input-wrapper > label {
  position: absolute;
  left: 0;
  top: -50%;
  transform: translateY(50%) scale(0.75);
  color: var(--text-tertiary);
  background: var(--bg-primary);
  display: none;
}
.ds-rich-editor .label-field-view-error > input { border-color: var(--coral) !important; }
.ds-rich-editor .label-field-view-error > label { color: var(--coral); }
.ds-rich-editor .label-field-view-status {
  font-size: 0.75rem;
  min-width: 32px;
  line-height: 20px;
  padding: 6px;
  white-space: pre-wrap;
  color: #fff;
  text-align: center;
  background: var(--coral);
  border-radius: var(--radius-sm);
  position: absolute;
  z-index: 9;
  left: 50%;
  bottom: -10px;
  transform: translate(-50%, 100%);
  max-width: 160px;
  width: max-content;
}

/* Farb-Picker (Rahmen-/Zellfarbe) */
.ds-rich-editor .ql-table-color-container {
  border: 1px solid var(--border);
  height: 30px;
  box-sizing: border-box;
  display: flex;
  border-radius: var(--radius-sm);
}
.ds-rich-editor .ql-table-color-container .label-field-view-color { flex: 1; }
.ds-rich-editor .ql-table-color-container .color-picker {
  width: 30px;
  border-left: 1px solid var(--border);
  box-sizing: border-box;
  position: relative;
}
.ds-rich-editor .ql-table-color-container .color-picker .color-button {
  width: 20px;
  height: 20px;
  border: 1px solid var(--border);
  box-sizing: border-box;
  cursor: pointer;
  position: relative;
}
.ds-rich-editor .ql-table-color-container .color-picker .color-picker-select {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 156px;
  transform: translateY(100%);
  z-index: 10;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-primary);
  box-shadow: var(--shadow-md);
}
.ds-rich-editor .ql-table-color-container .color-picker .color-picker-select .erase-container {
  display: flex;
  height: 30px;
  align-items: center;
  padding: 0 12px;
  cursor: pointer;
  color: var(--text-primary);
}
.ds-rich-editor .ql-table-color-container .color-picker .color-picker-select .erase-container:hover {
  background: var(--bg-secondary);
}
.ds-rich-editor .ql-table-color-container .color-picker .color-picker-select .color-list {
  display: flex;
  flex-wrap: wrap;
  padding: 0 12px;
  margin: 0;
  justify-content: space-between;
}
.ds-rich-editor .ql-table-color-container .color-picker .color-picker-select .color-list > li {
  list-style: none;
  width: 24px;
  height: 24px;
  margin: 2px 0;
  position: relative;
  cursor: pointer;
}
.ds-rich-editor .ql-table-color-container .color-picker .color-picker-select .color-list > li[data-color="#ffffff"] {
  border: 1px solid var(--border);
  box-sizing: border-box;
}

/* Tooltip auf Kontextmenü-Buttons (Hover-Erklärung) */
.ds-rich-editor .ql-table-tooltip-hover { display: flex; position: relative; }
.ds-rich-editor .ql-table-tooltip-hover:hover .ql-table-tooltip { display: block; }
.ds-rich-editor .ql-table-tooltip {
  font-size: 0.75rem;
  min-width: 32px;
  line-height: 20px;
  padding: 6px;
  white-space: nowrap;
  color: #fff;
  text-align: center;
  background: var(--text-primary);
  border-radius: var(--radius-sm);
  position: absolute;
  z-index: 22;
  left: 50%;
  bottom: -10px;
  transform: translate(-50%, 100%);
  display: none;
}
.ds-rich-editor .ql-table-tooltip-hidden { display: none !important; }

/* An/Aus-Schalter im Properties-Formular (z.B. "volle Breite") */
.ds-rich-editor .ql-table-switch { position: relative; display: inline-block; width: 28px; height: 16px; }
.ds-rich-editor .ql-table-switch .ql-table-switch-inner {
  position: absolute;
  cursor: pointer;
  inset: 0;
  background: var(--border);
  transition: 0.2s;
  border-radius: 8px;
}
.ds-rich-editor .ql-table-switch .ql-table-switch-inner::before {
  content: '';
  position: absolute;
  height: 12px;
  width: 12px;
  left: 2px;
  top: 50%;
  transform: translateY(-50%);
  background: #fff;
  transition: 0.2s;
  border-radius: 50%;
}
.ds-rich-editor .ql-table-switch .ql-table-switch-inner[aria-checked="true"] {
  background: var(--accent);
}
.ds-rich-editor .ql-table-switch .ql-table-switch-inner[aria-checked="true"]::before {
  transform: translate(12px, -50%);
}

/* ── Fieldset (modul-agnostisch) ──────────────────────────── */
.ds-fieldset {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .75rem .875rem .625rem;
  margin: 0 0 1rem;
  background: var(--bg-primary);
}
.ds-fieldset-legend {
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  padding: 0 .25rem;
}
.ds-fieldset-hint {
  display: block;
  margin-bottom: .5rem;
}
.ds-fieldset .form-group--compact {
  margin-top: .5rem;
}
.ds-fieldset .form-group--compact:last-child {
  margin-bottom: 0;
}

/* P4 – Mobile: .ds-fieldset Touch-Targets vergrößern (gilt global für alle Module) */
@media (max-width: 900px) {
  .ds-fieldset {
    padding: .875rem 1rem 1.125rem;
  }
  .ds-fieldset .ds-form-row {
    padding-block: .875rem;
  }
  .ds-fieldset .ds-form-row + .ds-form-row {
    margin-top: .25rem;
  }
}

/* ── Panel Toolbar (ds-panel-toolbar) ──────────────────────── */
.ds-panel-toolbar {
  display: flex;
  align-items: center;
  gap: .375rem;
  padding: .5rem .75rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
  flex-wrap: wrap;
}

/* Alle Toolbar-Items: gleiche Höhe (32px), gleicher Stil */
.ds-toolbar-item {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  height: 32px;
  padding: 0 .625rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  font-size: .8rem;
  font-weight: 500;
  color: var(--text-primary);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.ds-toolbar-item:hover {
  background: var(--bg-tertiary);
}
/* Speichern: blau */
.ds-toolbar-item--primary {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.ds-toolbar-item--primary:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
}
/* Aktiver Toggle (z.B. Ereignis/Serie) – dunkles Grau, NICHT blau */
.ds-toolbar-item--active {
  background: var(--text-secondary);
  color: #fff;
  border-color: var(--text-secondary);
}
.ds-toolbar-item--active:hover {
  background: var(--text-primary);
  border-color: var(--text-primary);
}
/* Löschen-Button: rot */
.ds-toolbar-item--danger {
  color: var(--coral);
  border-color: var(--coral-light);
}
.ds-toolbar-item--danger:hover {
  background: var(--coral-light);
  color: var(--coral);
}
/* Trennlinie zwischen Gruppen */
.ds-toolbar-sep {
  width: 1px;
  height: 20px;
  background: var(--border);
  flex-shrink: 0;
}
/* Gesetzter Wert (distinkt von --active Toggle) – accent-farbiger Rand */
.ds-toolbar-item.is-active {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-light);
}
.ds-toolbar-item.is-active:hover {
  background: color-mix(in srgb, var(--accent-light) 80%, var(--bg-tertiary));
}
.event-show-as-dot {
  --color: var(--accent);
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--color);
}

/* Toolbar Spacer → flex:1 */
.ds-toolbar-spacer { flex: 1; }

/* P7 – Destruktive Aktion als Icon-only (Stornieren/Löschen) */
.ds-toolbar-item--icon-only {
  padding: .4rem;
  gap: 0;
  min-width: 40px;
  min-height: 40px;
  justify-content: center;
}
.ds-toolbar-item--icon-only > span {
  display: none; /* Text ausblenden – Tooltip via aria-label/title */
}

/* Bug 6 – Kompakter Save-Button in Invoicing-Toolbars */
.ds-toolbar-item--sm {
  font-size: .8125rem;
  height: 28px;
  padding: 0 .625rem;
}

/* ── ds-rsvp-buttons (Ticket 3.388.1) – EINE Darstellung für Zusagen/
   Vorbehalt/Ablehnen statt zweier divergierender Systeme (Kalender-Flyout/
   -Panel vs. Mail-Anhang-Vorschau, P-5). Component selbst kennt keine
   Fachlogik – nur Optik + ds-rsvp-select-Event. Genutzt von
   pages/calendar/_flyout.js, pages/calendar.js (Termin- + Editor-Panel)
   und pages/mail.js. Icons + Farben identisch zum Kalender-Kontextmenü
   (ICON_CHECK/ICON_QMARK/ICON_XCIRCLE), Icon-Farbe folgt via currentColor
   der Textfarbe des Buttons – Pflicht für den Neutral-Rücksprung unten. */
ds-rsvp-buttons { display: block; width: 100%; }
.ds-rsvp-buttons {
  display: flex;
  gap: .375rem;
  flex-wrap: wrap;
}
.ds-rsvp-btn {
  flex: 1;
  min-width: 80px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .375rem;
  padding: .375rem .5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: .8125rem;
  font-weight: 500;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.ds-rsvp-btn:hover { background: var(--bg-secondary); }
.ds-rsvp-btn:disabled { opacity: .55; cursor: not-allowed; }

/* Noch keine Antwort (status='pending'): alle drei tragen ihre Farbe (Rand
   + Text + Icon via currentColor) – Domenico-Vorgabe Ticket 3.388.1: die
   Farbe zeigt vorab, welcher Button was bedeutet. */
.ds-rsvp-btn--accept    { color: var(--teal);  border-color: var(--teal); }
.ds-rsvp-btn--tentative { color: var(--amber); border-color: var(--amber); }
.ds-rsvp-btn--decline   { color: var(--coral); border-color: var(--coral); }

/* Bereits geantwortet: nur der gewählte Button bleibt farbig – jetzt
   GEFUELLT mit weisser Schrift statt nur umrandet. Die beiden anderen
   fallen auf neutral zurück (kein Rand-/Text-/Icon-Akzent mehr). */
.ds-rsvp-buttons--answered .ds-rsvp-btn:not(.is-active) {
  color: var(--text-primary);
  border-color: var(--border);
}
.ds-rsvp-btn.is-active { color: #fff; }
.ds-rsvp-btn--accept.is-active    { background: var(--teal);  border-color: var(--teal); }
.ds-rsvp-btn--tentative.is-active { background: var(--amber); border-color: var(--amber); }
.ds-rsvp-btn--decline.is-active   { background: var(--coral); border-color: var(--coral); }

/* Ticket 3.388.5: <ds-rsvp-buttons> rendert Light-DOM – im Kalender-Popover hängt
   sie unter .cal-flyout-row, dessen Regel "svg { color: var(--text-tertiary) }"
   direkt auf JEDES Nachfahren-SVG greift und damit die currentColor-Vererbung
   des Buttons überschreibt (Icon blieb grau, Text war schon korrekt teal/amber/
   coral bzw. weiss im aktiven Zustand). Eigene Regel mit höherer Spezifität
   (zwei Klassen statt einer) hält die Komponente unabhängig von der Umgebung
   robust – kein !important nötig. margin-top:0 hebt den 2px-Versatz derselben
   .cal-flyout-row-svg-Regel auf (Icon war sonst 1px tiefer als der Button-Text). */
.ds-rsvp-buttons .ds-rsvp-btn svg { color: inherit; margin-top: 0; }

/* Kategorie-Badge im Event-Block (oben rechts, Mouse-Over zeigt Name) */
.cal-event-cat-badge {
  --color: var(--text-tertiary);
  color: var(--color);
  position: absolute;
  top: 3px;
  right: 3px;
  line-height: 1;
  opacity: .85;
  pointer-events: auto;
}
.cal-event-cat-badge:hover { opacity: 1; }
/* Hinweis: position:absolute am .cal-event-block bildet bereits einen
   Positionierungskontext – kein position:relative-Override nötig. Ein
   früherer Override hat das Overlap-Layout gebrochen (Spalten kaskadierten
   vertikal statt nebeneinander). */
/* In der Titel-Zeile: Badge inline statt absolute (für enge Blöcke) */
.cal-event-block-title {
  display: flex;
  align-items: center;
  gap: .25rem;
}
.cal-event-block-title .cal-event-cat-badge,
.cal-event-bar .cal-event-cat-badge,
.cal-agenda-entry-title .cal-event-cat-badge {
  position: static;
  flex-shrink: 0;
  margin-left: auto;
}

/* Serientermin-Badge (Loop-Icon) */
.cal-event-recur-badge {
  color: currentColor;
  opacity: 0.7;
  line-height: 1;
  flex-shrink: 0;
  pointer-events: none;
}
.cal-event-block-title .cal-event-recur-badge,
.cal-event-bar .cal-event-recur-badge {
  margin-left: auto;
}
.cal-event-block-title .cal-event-recur-badge + .cal-event-cat-badge,
.cal-event-bar .cal-event-recur-badge + .cal-event-cat-badge {
  margin-left: 0;
}
/* Event-Bar: flex-Layout damit Badge inline rechts sitzt */
.cal-event-bar {
  display: flex;
  align-items: center;
  gap: .2rem;
  min-width: 0; /* damit text-overflow im flex-child funktioniert */
}

/* ── Outlook-Style Form-Rows (Icon links + Content rechts) ── */
.ds-form-row {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--border);
}
.ds-form-row:last-child { border-bottom: none; }
.ds-form-row-icon {
  flex-shrink: 0;
  width: 20px;
  color: var(--text-tertiary);
  margin-top: .5rem;
  display: flex;
  justify-content: center;
}
.ds-form-row-content { flex: 1; min-width: 0; }

/* ── Datum-Range-Paare (zwei Inputs nebeneinander in ds-form-row) */
.ds-date-range {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.ds-date-range .input { flex: 1; min-width: 0; }
.ds-date-range-sep {
  flex-shrink: 0;
  color: var(--text-tertiary);
  font-size: .85rem;
}

/* P1 – Mobile: .ds-date-range vertikal stapeln (gilt global für alle Module) */
@media (max-width: 600px) {
  .ds-date-range {
    flex-direction: column;
    align-items: stretch;
    gap: .375rem;
  }
  .ds-date-range-sep { display: none; }
  .ds-date-range > .input { width: 100%; }
}

/* ── Read-only Display (statt "input" mit min-height Inline-Style) */
.invoice-readonly-display {
  min-height: 2rem;
  white-space: pre-wrap;
  height: auto;
  cursor: default;
  padding: .375rem .625rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: .9rem;
  line-height: 1.5;
}
.invoice-readonly-empty { color: var(--text-tertiary); }

/* ── Beschreibungsfeld: rest des Panels ausfüllen ──────────── */
.ds-form-row--description {
  flex: 1;
  min-height: 0;
  border-bottom: none;
  display: flex;          /* überschreibt das default ds-form-row display */
  align-items: stretch;
}
.ds-form-row--description .ds-form-row-content {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  /* overflow: hidden ENTFERNT – clipte Mention-Dropdown im ds-note-editor */
}
.ds-form-row--description .ds-form-row-icon {
  margin-top: .5rem;
}
.ds-form-row--description ds-rich-editor {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* ds-rich-editor intern: Editable-Area soll wachsen */
.ds-form-row--description ds-rich-editor .ProseMirror,
.ds-form-row--description ds-rich-editor .ql-editor,
.ds-form-row--description ds-rich-editor [contenteditable] {
  flex: 1;
  min-height: 120px;
  overflow-y: auto;
}
.ds-form-row--description .textarea {
  flex: 1;
  min-height: 120px;
}

/* ── Beschreibungs-Wrap mit Read/Edit-Toggle ─────────────────
   Read-Mode: graue Toolbar-Leiste oben (mimic Quill-Toolbar) + Plaintext-Body.
   Edit-Mode: nur ds-rich-editor sichtbar, Toggle-Button bleibt absolute oben rechts. */
.cal-event-form-desc-wrap {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.cal-event-form-desc-toggle {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--border);
  background: var(--bg-primary);
  color: var(--text-secondary);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: var(--transition);
}
.cal-event-form-desc-toggle:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}
/* Im Edit-Modus: X-Toggle bleibt ganz rechts, der interne Quellcode-Toggle des
   ds-rich-editor wird nach links verschoben damit er den X nicht überlagert. */
.cal-event-form-desc-wrap.is-edit .ds-rich-editor-source-toggle {
  right: 40px;
}
.cal-event-form-desc-wrap.is-read {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  overflow: hidden;
}
.cal-event-form-desc-wrap.is-read::before {
  content: '';
  display: block;
  height: 42px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.cal-event-form-desc-readonly {
  padding: .75rem;
  flex: 1;
  min-height: 120px;
  overflow-y: auto;
  color: var(--text-primary);
  font-size: .9rem;
  line-height: 1.55;
}
.cal-event-form-desc-readonly.is-empty {
  color: var(--text-tertiary);
  font-style: italic;
}

/* ── Todo Description Editor ───────────────────────────────── */
.todo-desc-editor {
  display: block;
  min-height: 160px;
}
/* Ticket 3.84.010: max-height:400px war ein Rest aus der Zeit VOR dem
   Flex-Fill-Umbau (ds-todo-detail.js "Punkt 9/4.4" – .todo-desc-body
   .ds-rich-editor-body/.ql-container wachsen seither per flex:1 auf die
   volle verfügbare Panel-Hoehe). Quill setzt .ql-editor selbst auf
   height:100% (quill.snow.min.css) – der Cap hier hat das gekappt, obwohl
   der sichtbare (umrandete) .ql-container-Kasten längst hoeher war. Gemessen
   (Puppeteer, echtes Detail-Panel): Container 587px (Lesemodus) / 545px
   (Bearbeitungsmodus) vs. .ql-editor fix 400px – bis zu 187px sichtbarer,
   aber unbeschreibbarer Leerraum. Ohne Cap fuellt .ql-editor via height:100%
   exakt den flex-gewachsenen Container; eigenes overflow-y:auto bleibt für
   sehr lange Texte als interner Scroll-Bereich bestehen. */
.todo-desc-editor .ql-editor,
.todo-desc-editor .ProseMirror {
  min-height: 120px;
  overflow-y: auto;
}

/* ── Shell ── */
page-mail    { display: block; height: 100%; }
ds-mail-shell { display: block; height: 100%; }

.mail-shell {
  display: flex;
  height: 100%; /* fills the available container height (ds-content-body or ds-mail-shell) */
  overflow: hidden;
}

/* ── Folder Sidebar ── */
.mail-sidebar {
  width: 200px;
  flex-shrink: 0;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 0;
  background: var(--bg-secondary);
  overflow-y: auto;
  position: relative; /* Containing Block für den Ziehgriff, Ticket 3.220.2 */
}

.mail-compose-btn {
  margin: 0 0.75rem 0.5rem;
  width: calc(100% - 1.5rem);
  justify-content: center;
}
/* Ohne Umschalter davor (genau 1 Konto) ist der Knopf selbst das erste
   Sidebar-Kind und braucht den oberen Sidebar-Abstand selbst (Ticket 3.368.1). */
.mail-compose-btn:first-child { margin-top: 0.75rem; }

/* Konto-Umschalter (Ticket 3.41/A60, Reihenfolge+Optik Ticket 3.368.1) –
   kompakter Trigger, nur bei >1 aktivem Mail-Konto sichtbar. Desktop: volle
   Sidebar-Breite, steht VOR "Neue E-Mail" und teilt sich Hoehe/Rahmen/Radius/
   Hintergrund 1:1 mit dem Suchfeld (geteilte Regel bei .mail-search-input,
   keine abgeschriebenen Werte). Mobile (--compact): kompakt im .page-header
   der Ordner-Liste, rechtsbündig. */
.mail-account-switch-btn {
  display: flex;
  align-items: center;
  gap: .375rem;
  margin: 0.75rem .75rem .5rem;
  color: var(--text-primary);
  cursor: pointer;
  width: calc(100% - 1.5rem);
  box-sizing: border-box;
  transition: background var(--transition);
}
.mail-account-switch-btn:hover { background: var(--bg-tertiary); }
/* Doppelt-Klassen-Selektor (statt gleicher Spezifität wie die geteilte Regel
   unten) – gewinnt unabhängig von der Quellreihenfolge (frontend.md-Falle:
   gleiche Spezifität + spätere Regel gewinnt sonst unbeabsichtigt). */
.mail-account-switch-btn.mail-account-switch-btn--compact {
  margin: 0;
  width: auto;
  max-width: 45vw;
  height: 44px; /* Touch-Target Mobile – überschreibt die geteilte 32px-Basis */
  flex-shrink: 0;
}
.mail-account-switch-label {
  flex: 1;
  min-width: 0;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mail-folder-list {
  display: flex;
  flex-direction: column;
  padding: 0.25rem 0;
}

.mail-folder-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  margin: 0.125rem 0.375rem;
  font-size: 0.875rem;
  color: var(--text-primary);
  transition: background var(--transition);
  text-align: left;
}
.mail-folder-item:hover { background: var(--bg-tertiary); }
.mail-folder-item.active {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
}
.mail-folder-icon { display: flex; align-items: center; flex-shrink: 0; }
.mail-folder-label { flex: 1; }
/* ── ds-context-menu (shared) ─────────────────────────── */
/* Transparenter Backdrop unter dem Menü (z-index 1099 < Menü 1100).
   Fängt Außen-Klicks inkl. Klicks in sandboxed iframes ab → schließt Menü. */
.ds-context-menu-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1099;
  background: transparent;
}
/* .ds-context-menu / .ds-context-menu-item (+ .ds-context-menu-divider) – kanonische
   Definition liegt in _calendar.css (Z.4643+), matched 1:1 die DOM-Struktur die
   core/ds-context-menu.js tatsächlich rendert (.is-open/.is-closing, .ds-context-menu-list,
   .ds-context-menu-icon/-label/-shortcut/-sep). Diese Legacy-Version war durch
   Build-Reihenfolge immer überschrieben (dead) – B10 CSS-Konsolidierung entfernt sie. */
/* Section-Label im Kontextmenü (nicht klickbar, Uppercase-Beschriftung) */
.ds-context-menu-header {
  padding: .6rem .9rem .2rem;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  pointer-events: none;
  user-select: none;
}
.ds-context-menu-header:first-child { padding-top: .25rem; }

/* ── ds-context-menu: Flyout-Untermenüs + Checked-Markierung (additiv) ──
   Basis-Klassen (.ds-context-menu-item/-icon/-label/-shortcut/-sep) bleiben
   in _calendar.css. Diese Ergänzung ist rein additiv (neue Klassen, keine
   Overrides bestehender Selektoren) – Build-Reihenfolge ist daher egal. */

/* .is-accent – hervorgehobener Menüeintrag, Pendant zu .is-danger (Basis-
   Klasse .ds-context-menu-item + Modifier-Muster in _calendar.css), aber in
   der Akzentfarbe statt Rot (Ticket 3.388.6: "Einladung beantworten" wurde
   bisher zwischen alltäglichen Aktionen übersehen). Gilt für Leaf-Items UND
   Flyout-Parents (.has-submenu) – beide Selektoren-Bausteine sind additiv,
   Cascade-Reihenfolge egal (s.o.). */
.ds-context-menu-item.is-accent {
  color: var(--accent);
  font-weight: 600;
}
.ds-context-menu-item.is-accent:hover {
  background: var(--accent-light);
}
.ds-context-menu-item.is-accent .ds-context-menu-icon,
.ds-context-menu-item.is-accent .ds-context-menu-chevron {
  color: var(--accent);
}

.ds-context-menu-item.has-submenu {
  position: relative; /* Anchor für .ds-context-menu-submenu (Flyout-Kind) */
  /* Ticket 3.209: .ds-context-menu-item ist selbst display:flex (Basisklasse in
     _calendar.css) – ohne flex-wrap bleibt das Inline-Accordion-Kind
     (.ds-context-menu-submenu--inline, position:static) ein Flex-GESCHWISTER von
     Icon/Label/Chevron auf DERSELBEN Zeile statt darunter umzubrechen. Icon/Label/
     Chevron/Hint haben zusammen eine kleine hypothetische Breite (Label selbst hat
     flex-basis:0) und bleiben dadurch immer auf Zeile 1 – erst das Akkordeon
     (flex-basis 100%, s.u.) sprengt die Zeile und rutscht auf Zeile 2. Wirkungslos
     für den Desktop-Flyout: .ds-context-menu-submenu ist position:absolute und
     nimmt an der Flex-Zeilenaufteilung strukturell nicht teil (raus aus dem
     normalen Fluss), Desktop bleibt dadurch unverändert. */
  flex-wrap: wrap;
}
.ds-context-menu-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 14px;
  height: 14px;
  margin-left: .25rem;
  color: var(--text-tertiary);
}
.ds-context-menu-item.is-disabled .ds-context-menu-chevron { opacity: .55; }
.ds-context-menu-hint {
  flex-shrink: 0;
  font-size: .72rem;
  color: var(--text-tertiary);
  margin-left: .35rem;
  max-width: 6rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-context-menu-check {
  display: inline-flex;
  width: 16px;
  height: 16px;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--accent);
}
/* Folgeauftrag zu Ticket 3.234.1: hat ein `checked:true`-Item zusätzlich ein
   `icon`, bleibt das Icon im Icon-Slot stehen und diese Checkmark wird ein
   ZWEITES Mal gerendert – als nachgestelltes Glyph rechts vom Label (s.
   core/ds-context-menu.js _buildItemTemplate()/_buildSubmenuItemTemplate()).
   Bewusst OHNE eigene Regeln hier: die Basis-`.ds-context-menu-check`-Klasse
   (Größe/Farbe/flex-shrink) reicht als zweites Flex-Kind bereits aus, der
   `gap` von `.ds-context-menu-item` (s. _calendar.css) stellt den Abstand
   zum Label automatisch her – visuell verifiziert (Puppeteer-Screenshots,
   Light+Dark). Modifier existiert rein als Markup-Hook für einen künftigen
   Feinschliff, ohne den Basis-Fall (kein Icon → Checkmark im Icon-Slot) zu
   berühren. */
.ds-context-menu-check--trailing { }
.ds-context-menu-item.is-checked { font-weight: 600; }

/* Flyout-Variante: absolut positioniert (Position wird von
   ds-context-menu.js._positionAllSubmenus() als inline top/left überschrieben –
   die Werte hier sind nur der visuelle Default vor der ersten Messung). */
.ds-context-menu-submenu {
  position: absolute;
  top: 0;
  left: calc(100% - 4px);
  z-index: 1101; /* über dem eigenen Root-Menü (1100, _calendar.css) */
  min-width: 180px;
  max-width: min(280px, calc(100vw - 16px));
  list-style: none;
  margin: 0;
  padding: .25rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, .04),
    0 14px 36px rgba(0, 0, 0, .18);
  opacity: 0;
  transform: translateY(-2px) scale(.97);
  transform-origin: top left;
  transition:
    opacity 140ms cubic-bezier(.16, 1, .3, 1),
    transform 140ms cubic-bezier(.16, 1, .3, 1);
}
.ds-context-menu-submenu.is-open {
  opacity: 1;
  transform: translateY(0) scale(1);
}
:root[data-theme="dark"] .ds-context-menu-submenu,
:root:not([data-theme="light"]) .ds-context-menu-submenu {
  box-shadow:
    0 1px 2px rgba(0, 0, 0, .4),
    0 14px 36px rgba(0, 0, 0, .6);
}
/* Inline-Accordion-Variante (Screens ≤480px, s. ds-context-menu.js): klappt im
   normalen Fluss unter dem Parent-Label auf, volle Breite, kein Flyout-Look. */
.ds-context-menu-submenu--inline {
  position: static;
  left: auto;
  top: auto;
  /* Ticket 3.209: `width:100%` allein rechnet nicht den eigenen margin-left
     dieser Zeile mit ein – 100% Breite + 1.5rem Rand (s.u.) ist zwingend
     breiter als der Elternrahmen und lief rechts über den Menü-Rand hinaus.
     calc() zieht exakt den eigenen linken Rand ab; flex-shrink:0 verhindert,
     dass diese bereits exakte Breite durch den Flex-Zeilenumbruch (s. Regel
     oben auf .has-submenu) nochmal angetastet wird. */
  flex-shrink: 0;
  width: calc(100% - 1.5rem);
  max-width: none;
  margin: .125rem 0 .25rem 1.5rem;
  padding: 0 0 0 .25rem;
  border: none;
  border-left: 2px solid var(--border);
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}

/* ── Mail: Multiselect (Spec 1000; Avatar-als-Checkbox seit Ticket 3.245) ──
   Desktop-Avatar ersetzt die frühere native Checkbox als Auswahlfeld –
   role="checkbox" + tabindex im Markup (pages/mail.js), Hover-/Fokus-Zustand
   hier. `.mail-row-avatar-hover-check` nutzt currentColor (kein hartcodiertes
   SVG-Fill) und blendet nur ein solange NICHT ausgewählt – der ausgewählte
   Zustand zeigt bereits sein eigenes Häkchen via `.mail-avatar--selected`
   (kein Doppel-Icon). */
.mail-row-avatar--selectable {
  position: relative;
  cursor: pointer;
  border-radius: 50%;
}
.mail-row-avatar--selectable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.mail-row-avatar-hover-check {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  opacity: 0;
  transition: opacity var(--transition);
  pointer-events: none;
}
.mail-row-avatar--selectable:hover .mail-row-avatar-hover-check,
.mail-row-avatar--selectable:focus-visible .mail-row-avatar-hover-check {
  opacity: 1;
}
.mail-row.is-selected {
  background: var(--bg-tertiary);
  border-left: 3px solid var(--accent);
  padding-left: calc(0.75rem - 3px);
}
/* Mobile native-row Selektions-Zustand – konsistent mit Desktop .mail-row.is-selected */
.native-row.is-selected {
  background: var(--bg-tertiary);
  border-left: 3px solid var(--accent);
  padding-left: calc(0.75rem - 3px);
}
/* Avatar-Selektions-Zustand (Häkchen statt Initial) */
.mail-avatar--selected {
  background: var(--accent);
  color: #fff;
}

/* ── Mail: Aktionsleiste ─────────────────────────────── */
.mail-action-bar {
  padding: .4rem .75rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
  min-height: 40px;
  display: flex;
  align-items: center;
}
.mail-select-all {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .82rem;
  cursor: pointer;
  color: var(--text-secondary);
}
.mail-action-bar-selection {
  display: flex;
  align-items: center;
  gap: .25rem;
  flex-wrap: wrap;
  margin-left: auto; /* Ticket 3.245: rechtsbündig wie .mail-count-info, das sie bei aktiver Auswahl ersetzt */
}
.mail-selection-count {
  font-size: .82rem;
  font-weight: 600;
  color: var(--accent);
  margin-right: .5rem;
}
.mail-action-bar .btn.is-danger { color: var(--danger); }
.mail-action-bar .btn.is-danger:hover { background: var(--danger-light); }
/* P0-4: Gmail-Banner „Alle im Ordner auswählen" */
.mail-select-all-banner {
  width: 100%;
  padding: .375rem .75rem;
  font-size: .8125rem;
  background: var(--accent-light);
  color: var(--text-primary);
  border-bottom: 1px solid var(--border);
  text-align: center;
}
.mail-select-all-banner strong { color: var(--accent); font-weight: 600; }
.mail-select-all-banner-link {
  background: none;
  border: none;
  color: var(--accent);
  font-size: .8125rem;
  font-weight: 600;
  cursor: pointer;
  padding: 0 .25rem;
  text-decoration: underline;
}
.mail-select-all-banner-link:hover { color: var(--accent-dark); }
/* P0-5: Pagination counter „X von N" rechts in der Default-Aktionsleiste */
.mail-action-bar-default {
  display: flex;
  align-items: center;
  gap: .75rem;
  width: 100%;
}
.mail-count-info {
  margin-left: auto;
  font-size: .78rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

.mail-folder-badge {
  margin-left: auto;
  font-size: .68rem;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--accent);
  color: #fff;
  font-weight: 600;
}
.mail-folder-divider { height: 1px; background: var(--border); margin: 0.375rem 0.75rem; }

/* ── Mail: Skeleton-UI (Initial-Load) ──────────────────────
   Zweck: Struktur des UI zeigen bevor die Daten da sind – statt leerem
   "Lade…"-Text, der nach einer Sekunde immer noch nichts aussagt. */
@keyframes mail-skeleton-shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position:  200% 0; }
}
.mail-folder-skeleton,
.mail-row-skeleton {
  display: flex; align-items: center; gap: .55rem;
  padding: .5rem .75rem;
}
.mail-folder-skeleton { min-height: 32px; }
.mail-row-skeleton    { min-height: 60px; border-bottom: 1px solid var(--border); }
.mail-row-skeleton .skeleton-lines { flex: 1; display: flex; flex-direction: column; gap: .4rem; }
.skeleton-dot, .skeleton-bar, .skeleton-circle {
  background: linear-gradient(
    90deg,
    var(--bg-tertiary) 0%,
    var(--border) 50%,
    var(--bg-tertiary) 100%
  );
  background-size: 200% 100%;
  animation: mail-skeleton-shimmer 1.4s ease-in-out infinite;
  border-radius: 4px;
}
.skeleton-dot    { width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0; }
.skeleton-circle { width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; }
.skeleton-bar    { height: 10px; flex: 1; }
.skeleton-bar-short { width: 40%; flex: none; }
.skeleton-bar-long  { width: 80%; flex: none; }

/* ── Mail: Sticky-Sync-Banner ─────────────────────────────
   Erscheint oben in der Mail-Liste, solange im Hintergrund syncQuiet läuft.
   Nicht-blockierend: User kann trotzdem scrollen/klicken. */
.mail-sync-banner {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; gap: .5rem;
  padding: .375rem .75rem;
  background: var(--accent-light);
  color: var(--accent);
  font-size: .78rem;
  font-weight: 500;
  border-bottom: 1px solid var(--border);
}
.mail-sync-banner .spin {
  width: 12px; height: 12px; animation: mail-skeleton-shimmer 0s; /* keine Shimmer-Animation hier */
}
.mail-sync-banner svg.spin {
  animation: spin 1.2s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Infinite-Scroll Sentinel: minimale Hoehe, damit IntersectionObserver ihn
   auch in kurzen Listen noch sauber triggern kann. */
.mail-load-more-wrap {
  padding: .75rem;
  min-height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
}
.mail-load-more { font-size: .82rem; }
.mail-load-done {
  font-size: .75rem;
  color: var(--text-tertiary);
  font-style: italic;
}

/* ── Message List Column ── */
.mail-list-col {
  width: 340px;
  flex-shrink: 0;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg-primary);
}

.mail-list-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.625rem 0.75rem;
  border-bottom: 1px solid var(--border);
  gap: 0.5rem;
  flex-shrink: 0;
}

.mail-list-title {
  font-weight: 600;
  font-size: 0.9375rem;
  white-space: nowrap;
}

.mail-list-actions {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  min-width: 0;
  /* Volle Headerbreite einnehmen, damit die Split-Buttons rechtsbündig sitzen
     (Suchfeld links, Filter+Aktualisieren ganz rechts). */
  flex: 1;
}
/* Suchfeld links halten, freien Raum dahinter aufbrauchen → beide Split-Buttons
   rücken ganz nach rechts. (margin-right:auto auf dem Suchfeld ist robust gegen
   Element-Typ – :first-of-type hätte fälschlich auf .mail-search-wrap gematcht.) */
.mail-list-actions .mail-search-wrap {
  margin-right: auto;
}

.mail-search-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

/* Geteilte Optik Suchfeld + Konto-Umschalter (Ticket 3.368.1) – EINE Regel statt
   Abschrift, damit beide garantiert gleich hoch/geformt bleiben. */
.mail-search-input,
.mail-account-switch-btn {
  height: 32px;
  padding: 0.375rem 0.625rem;
  font-size: 0.8125rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
}

.mail-search-input {
  min-height: unset;
  width: 140px;
  transition: width var(--transition);
}
.mail-search-input:focus { width: 180px; }

/* Natives WebKit-/Blink-Clear-X unterdrücken – dieses Feld hat ein eigenes
   .mail-search-clear (sonst Doppel-X bei Fokus/Inhalt in Chrome/Safari). */
.mail-search-input::-webkit-search-cancel-button,
.mail-search-input::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
}

.mail-search-clear {
  position: absolute;
  right: 0.375rem;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  font-size: 0.75rem;
  padding: 0.125rem;
  line-height: 1;
}

.mail-sync-btn {
  min-height: 32px !important;
  padding: 0.25rem 0.5rem !important;
  flex-shrink: 0;
}

/* ── Mail-List Body-Wrap: non-scrolling Anker für Overlay ───────────── */
/* Overlay muss auf dem WRAP sitzen (nicht auf .mail-list-body), damit er
   nicht mit dem Scroll-Inhalt mitfährt. A3-Fix 2026-06-10. */
.mail-list-body-wrap {
  position: relative;
  flex: 1;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.mail-list-body {
  overflow-y: auto;
  flex: 1;
}

/* ── Bulk-Aktion Lade-Overlay ───────────────────────── */
/* Anchors on .mail-list-body-wrap → bleibt im sichtbaren Bereich unabhängig von Scroll-Position */
.mail-list-busy {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: all; /* Klicks während Aktion abfangen */
}
.mail-list-busy::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--bg-primary);
  opacity: .55;
}
.mail-list-busy .spinner {
  position: relative;
  z-index: 1;
}

.mail-loading, .mail-empty {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--text-tertiary);
  font-size: 0.875rem;
}

.mail-load-more {
  width: 100%;
  border-radius: 0;
  border-top: 1px solid var(--border);
  min-height: 40px !important;
}

/* ── Message Row ── */
.mail-row {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  padding: 0.625rem 0.75rem;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background var(--transition);
}
.mail-row:hover { background: var(--bg-secondary); }
.mail-row:hover .mail-row-actions { opacity: 1; }
.mail-row.active { background: var(--accent-light); }
.mail-row.unread { background: var(--bg-secondary); }
.mail-row.unread .mail-row-from { font-weight: 700; }
.mail-row.unread .mail-row-subject { font-weight: 600; }

.mail-row-unread-bar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--accent);
  border-radius: 0 2px 2px 0;
}

.mail-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--accent-light);
  color: var(--accent);
  font-size: 0.75rem;
  font-weight: 700;
  flex-shrink: 0;
  letter-spacing: 0;
}
.mail-avatar--sm { width: 28px; height: 28px; font-size: 0.6875rem; }

.mail-row-body { flex: 1; min-width: 0; }

.mail-row-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.25rem;
  margin-bottom: 0.125rem;
}

.mail-row-from {
  font-size: 0.875rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
}

.mail-row-meta {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  flex-shrink: 0;
}

.mail-row-date {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* Ticket 3.384.1: Konto-Kennzeichnung in der Listenzeile (nur bei >1 Konten,
   Desktop-Listen – Einzelnachricht + Konversation). Zurückhaltend: kleiner
   als .mail-row-date, deutlich schwaecher als .mail-row-from/.mail-row-subject. */
.mail-row-account {
  font-size: 0.6875rem;
  color: var(--text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 110px;
  padding: 0 0.375rem;
  border-right: 1px solid var(--border);
}

.mail-row-subject {
  font-size: 0.8125rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 0.125rem;
}

.mail-row-preview {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mail-row-actions {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  opacity: 0;
  transition: opacity var(--transition);
}

.mail-action-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  transition: all var(--transition);
  padding: 0;
}
.mail-action-btn:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}

/* ── Mail: Wischgesten in der Nachrichtenliste (Ticket 3.359.2) ────────────
   macOS-Mail-Stil: rechts wischen = gelesen/ungelesen, links wischen =
   löschen. EINE Bahn für Touch (Finger) und Desktop-Trackpad (Zweifinger-
   Wisch) – beide sind für den Browser dieselbe horizontale Scroll-Geste,
   siehe pages/_mail-swipe.js für die genaue Konstruktion (5 Kinder, davon
   nur 3 Snap-Punkte). `--mail-swipe-action-w` lokal gescoped (kein globaler
   Root-Wert nötig) – einzige Stelle, an der die Aktionsbreite steht. */
.mail-swipe-track {
  --mail-swipe-action-w: 80px;
  display: flex;
  width: 100%;
  overflow-x: scroll;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: none;
  /* pan-x pan-y (NICHT nur pan-x) – Ticket 3.359.2, per echtem iPhone-Test
     bewiesen: reines "pan-x" blockiert JEDE Berührung auf einer Zeile für
     vertikales Scrollen der ganzen Liste, nicht nur diagonale Gesten. Der
     Browser wählt die Achse selbst nach der dominanten Startrichtung – das
     horizontale Snappen bleibt unverändert erhalten. */
  touch-action: pan-x pan-y;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.mail-swipe-track::-webkit-scrollbar { display: none; }
.mail-swipe-track:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Runway: zusätzlicher, NICHT snappender Scroll-Weg hinter den Aktionen –
   das ist die "tiefe" Schwelle (langer Wisch löst direkt aus, s. JS). */
.mail-swipe-runway { flex: 0 0 calc(50% - var(--mail-swipe-action-w)); }

.mail-swipe-content { flex: 0 0 100%; scroll-snap-align: start; min-width: 0; }

.mail-swipe-action {
  flex: 0 0 var(--mail-swipe-action-w);
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  border: none;
  cursor: pointer;
  color: #fff;
  font-size: 0.68rem;
  font-weight: 600;
  /* touch-action:none (nicht pan-x/pan-y wie die Bahn selbst) – Ticket
     3.359.2, per echtem Android-Test bewiesen. Ein Touch, der AUF dem
     Knopf beginnt, darf dem umgebenden Scroll-Snap-Container (`pan-x
     pan-y` auf .mail-swipe-track) gar nicht erst zur Interpretation
     angeboten werden – sonst deutet der Browser das unvermeidliche
     Zittern eines echten Fingers als Wisch-Beginn und kapert die Geste
     (pointercancel statt pointerup), bevor der 12px-Bewegungs-Wächter in
     _mail-swipe.js überhaupt greifen kann. Bewusster Trade-off: ein
     Zurück-Wisch, der genau auf dem Knopf startet, scrollt die Bahn nicht
     mehr zu – der Inhaltsbereich bleibt dafür immer sichtbar/erreichbar,
     und die Aktion selbst schließt die Bahn ohnehin (recenter()). */
  touch-action: none;
}
.mail-swipe-action--read   { background: var(--accent); }
/* scroll-snap-align:end (nicht start wie die Basisklasse) – die Löschen-
   Aktion liegt HINTER dem Inhalt; ihr eigener Start (Track-Position) läge
   außerhalb des tatsächlich erreichbaren scrollLeft-Maximums (das native
   Scrollen kann nur bis scrollWidth-clientWidth reichen). Mit "end" richtet
   der Browser stattdessen ihr rechtes Ende am rechten Bahnrand aus – genau
   das ist innerhalb des erreichbaren Bereichs und ergibt den erwarteten
   „Knopf klebt rechtsbündig"-Zustand (Ticket 3.359.2 per echtem Touch-Test
   verifiziert: ohne diesen Fix war der Löschen-Snap-Punkt gar nicht
   erreichbar, jeder Wisch nach links landete sofort im Tiefen-Bereich). */
.mail-swipe-action--delete { background: var(--danger); scroll-snap-align: end; }
.mail-swipe-action-label { white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  .mail-swipe-track { scroll-behavior: auto; }
}

/* ── Detail Column ── */
.mail-detail-col {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--bg-primary);
}

.mail-detail-empty, .mail-detail-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  gap: 0.75rem;
  color: var(--text-tertiary);
  font-size: 0.875rem;
}

.mail-detail-header {
  padding: 1rem 1.25rem 0.75rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.mail-detail-subject {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: 1.125rem;
  font-weight: 700;
  margin: 0 0 0.75rem;
  line-height: 1.3;
}
.mail-detail-subject-text {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Icon-only Trash-Button in Betreff-Zeile (Desktop-Detail) */
.mail-detail-subject-delete {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  padding: 0;
  margin-top: -0.1875rem; /* optisch an Betreff-Baseline ausrichten */
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--text-tertiary);
  cursor: pointer;
  transition: color var(--transition), background var(--transition);
}
.mail-detail-subject-delete:hover {
  color: var(--coral);
  background: var(--coral-light);
}

.mail-detail-meta {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  margin-bottom: 0.75rem;
}

.mail-detail-meta-row {
  display: flex;
  gap: 0.5rem;
  font-size: 0.8125rem;
}

.mail-detail-label {
  color: var(--text-tertiary);
  min-width: 40px;
  flex-shrink: 0;
}

.mail-detail-value {
  color: var(--text-primary);
  flex: 1;
  min-width: 0;
  word-break: break-word;
}

.mail-detail-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: nowrap;
}

.mail-image-banner {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1.25rem;
  background: var(--amber-light);
  color: var(--amber);
  font-size: 0.8125rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.mail-detail-body {
  flex: 1;
  overflow: hidden;
  padding: 0;
}

/* ── Thread / Conversation badge ── */
.mail-thread-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border-radius: 9px;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: 0.6875rem;
  font-weight: 600;
  margin-left: 0.25rem;
  line-height: 1;
}
.mail-thread-badge--sm {
  min-width: 16px;
  height: 16px;
  font-size: 0.625rem;
}

/* ── Thread count row (below subject in thread detail) ── */
.mail-thread-count-row {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  margin-bottom: 0.5rem;
}

/* ── Thread body (wraps all messages in conversation detail) ── */
/* mail-detail-col has overflow-y:auto so the whole column scrolls naturally */
.mail-thread-body {
  display: flex;
  flex-direction: column;
}

/* ── Individual thread message ── */
.mail-thread-msg {
  border-bottom: 1px solid var(--border);
}
.mail-thread-msg:last-child {
  border-bottom: none;
}

.mail-thread-msg-header {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.75rem 1.25rem;
  cursor: pointer;
  transition: background var(--transition);
  user-select: none;
}
.mail-thread-msg-header:hover {
  background: var(--bg-secondary);
}
.mail-thread-msg.expanded .mail-thread-msg-header {
  background: var(--bg-secondary);
}

.mail-thread-msg-meta {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}
.mail-thread-msg-from {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: flex;
  align-items: center;
}
.mail-thread-msg-date {
  font-size: 0.75rem;
  color: var(--text-tertiary);
}
.mail-thread-msg-icons {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  flex-shrink: 0;
}
.mail-thread-chevron {
  flex-shrink: 0;
  color: var(--text-tertiary);
  transition: transform var(--transition);
}
.mail-thread-chevron.open {
  transform: rotate(180deg);
}

.mail-thread-msg-body {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--border);
  background: var(--bg-primary);
}
.mail-thread-msg-body .mail-iframe {
  min-height: 300px;
}

.mail-thread-msg-preview {
  padding: 0 1.25rem 0.75rem 3.5rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin: 0;
}

.mail-thread-msg-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.625rem 1.25rem;
  border-top: 1px solid var(--border);
  background: var(--bg-secondary);
  flex-shrink: 0;
}

/* ── Compose Panel (inline, replaces detail column) ── */
.mail-compose-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg-primary);
  border-left: 1px solid var(--border);
  position: relative;
}

.mail-compose-action-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  background: var(--bg-secondary);
}

.mail-compose-sender {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  margin-left: 0.25rem;
}

.mail-compose-recipients {
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}

/* Ticket 3.409.2: dezenter Hinweis im Verfassen-Fenster, wenn das
   Antwort-an-Feld der Original-Mail vom Absender abweicht. */
.mail-compose-reply-hint {
  flex-shrink: 0;
  padding: 0.375rem 0.75rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
}
.mail-compose-reply-hint strong {
  color: var(--text-primary);
  font-weight: 600;
}

.mail-compose-recipient-row {
  display: flex;
  align-items: center;
  gap: 0;
  border-bottom: 1px solid var(--border);
  position: relative;
  min-height: 36px;
}
.mail-compose-recipient-row:last-child { border-bottom: none; }

.mail-compose-recipient-label {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  padding: 0 0.75rem;
  white-space: nowrap;
  width: 36px;
  flex-shrink: 0;
}

.mail-compose-recipient-field {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  padding: 0.25rem 0.25rem 0.25rem 0;
  cursor: text;
  min-height: 36px;
}

.mail-compose-recipient-input {
  border: none;
  outline: none;
  background: none;
  font-size: 0.875rem;
  color: var(--text-primary);
  min-width: 120px;
  flex: 1;
  padding: 0.25rem 0;
  height: 28px;
}

.mail-compose-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  background: var(--accent-light);
  color: var(--accent);
  border-radius: 99px;
  padding: 0.125rem 0.5rem 0.125rem 0.625rem;
  font-size: 0.8125rem;
  font-weight: 500;
  white-space: nowrap;
  /* Ticket 3.372.5: 200px -> 320px, damit Name UND E-Mail-Adresse nebeneinander Platz
     finden (Chip wraps ohnehin per flex-wrap in .mail-compose-recipient-field). */
  max-width: 320px;
}

/* Name-Teil trägt jetzt die Ellipsis-Kuerzung (nicht mehr der ganze Chip) --
   die neu ergänzte E-Mail-Adresse (.mail-compose-chip-email) bleibt IMMER
   vollstaendig lesbar, das ist der eigentliche Zweck der Änderung. */
.mail-compose-chip-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.mail-compose-chip-email {
  opacity: 0.68;
  font-weight: 400;
  flex-shrink: 0;
}

.mail-compose-chip-remove {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--accent);
  font-size: 1rem;
  padding: 0;
  line-height: 1;
  opacity: 0.7;
  flex-shrink: 0;
}
.mail-compose-chip-remove:hover { opacity: 1; }

.mail-compose-bcc-toggle {
  font-size: 0.75rem;
  color: var(--text-secondary);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.25rem 0.75rem;
  white-space: nowrap;
  text-decoration: underline;
  flex-shrink: 0;
}
.mail-compose-bcc-toggle:hover { color: var(--accent); }

.mail-compose-autocomplete {
  position: absolute;
  top: 100%;
  left: 36px;
  right: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-top: none;
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  box-shadow: var(--shadow-md);
  z-index: 100;
  max-height: 200px;
  overflow-y: auto;
}

.mail-compose-ac-item {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.625rem;
  padding: 0.5rem 0.75rem;
  border: none;
  background: none;
  cursor: pointer;
  width: 100%;
  text-align: left;
  font-size: 0.875rem;
}
.mail-compose-ac-item:hover,
.mail-compose-ac-item.active { background: var(--accent-light); color: var(--accent); }
.mail-compose-ac-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--accent-light);
  color: var(--accent);
  font-size: 0.75rem;
  font-weight: 700;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.mail-compose-ac-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.mail-compose-ac-info { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.mail-compose-ac-name { color: var(--text-primary); font-weight: 500; }
.mail-compose-ac-email { color: var(--text-secondary); font-size: 0.8125rem; }
.mail-compose-ac-item.active .mail-compose-ac-name,
.mail-compose-ac-item.active .mail-compose-ac-email { color: var(--accent); }

/* ── Toolbar area ── */
.mail-compose-toolbar-area {
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}

.mail-compose-toolbar {
  display: flex;
  align-items: center;
  gap: 1px;
  padding: 0.25rem 0.5rem;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  scrollbar-width: none;
}
.mail-compose-toolbar::-webkit-scrollbar { display: none; }

.mail-compose-toolbar-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 28px;
  padding: 0 6px;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: 0.875rem;
  white-space: nowrap;
  transition: background var(--transition);
  flex-shrink: 0;
}
.mail-compose-toolbar-btn:hover { background: var(--bg-tertiary); }
.mail-compose-toolbar-btn.active { background: var(--accent-light); color: var(--accent); }

.mail-compose-toolbar-sep {
  width: 1px;
  height: 18px;
  background: var(--border);
  flex-shrink: 0;
  margin: 0 2px;
}

.mail-compose-toolbar-select {
  height: 28px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: 0.8125rem;
  padding: 0 0.375rem;
  cursor: pointer;
  flex-shrink: 0;
}

.mail-compose-color-btn {
  position: relative;
  overflow: hidden;
}
.mail-compose-color-input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
  width: 100%;
  height: 100%;
}

.mail-compose-subject-row {
  padding: 0 0.75rem;
  border: none;
  display: flex;
  align-items: center;
}

.mail-compose-subject-input {
  flex: 1;
  border: none;
  outline: none;
  background: none;
  font-size: 0.9375rem;
  color: var(--text-primary);
  padding: 0.5rem 0;
  font-weight: 500;
}
.mail-compose-subject-input::placeholder { color: var(--text-tertiary); font-weight: 400; }

/* ── Editor (P2-7: ds-rich-editor wrapper) ── */
.mail-compose-editor-wrap {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* ds-rich-editor füllt den ganzen Wrapper aus */
.mail-compose-editor-wrap ds-rich-editor,
.mail-compose-editor-wrap .ds-rich-editor {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* .ds-rich-editor-body ist generisch auf max-height:280px gedeckelt (_core.css
   „ds-rich-editor (Quill v2)"-Sektion, für die ~60 kompakten Bestandsverwendungen
   gedacht). Im Compose-Kontext soll der Editor stattdessen die volle Resthoehe des
   Panels einnehmen – Deckel hier gezielt aufheben + selbst flex-column machen,
   damit .ql-toolbar (flex-shrink:0) oben fix bleibt und .ql-container (flex:1)
   darunter wächst + intern scrollt. */
.mail-compose-editor-wrap .ds-rich-editor-body {
  flex: 1;
  min-height: 0;
  max-height: none;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* Quill-Editor-Body scrollt intern */
.mail-compose-editor-wrap .ql-container {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  font-size: 0.9375rem;
  line-height: 1.6;
}
.mail-compose-editor-wrap .ql-editor {
  min-height: 10rem;
  padding: 0.875rem 1.125rem;
}
/* Quill-Toolbar kompakter im Compose-Kontext */
.mail-compose-editor-wrap .ql-toolbar {
  flex-shrink: 0;
  border-top: none;
  border-left: none;
  border-right: none;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
}
/* Dark-Mode: Quill-Toolbar-Farben anpassen (nur expliziter data-theme="dark"-Toggle) */
:root[data-theme="dark"] .mail-compose-editor-wrap .ql-toolbar .ql-stroke { stroke: var(--text-secondary); }
:root[data-theme="dark"] .mail-compose-editor-wrap .ql-toolbar .ql-fill   { fill:   var(--text-secondary); }
:root[data-theme="dark"] .mail-compose-editor-wrap .ql-toolbar button:hover .ql-stroke { stroke: var(--accent); }
:root[data-theme="dark"] .mail-compose-editor-wrap .ql-toolbar button:hover .ql-fill   { fill:   var(--accent); }

/* ── Link popup ── */
.mail-compose-link-popup {
  position: absolute;
  bottom: 1rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: 0.75rem;
  display: flex;
  gap: 0.5rem;
  align-items: center;
  z-index: 50;
  min-width: 320px;
}

/* ── Compose attachments ─────────────────────────── */
.mail-compose-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
  padding: .375rem .75rem;
  border-top: 1px solid var(--border);
  background: var(--bg-secondary);
  flex-shrink: 0; /* always visible – never scrolls away */
}

.mail-compose-attach-chip {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .2rem .5rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: .75rem;
  color: var(--text-secondary);
  max-width: 220px;
}

.mail-compose-attach-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}

.mail-compose-attach-size {
  color: var(--text-tertiary);
  flex-shrink: 0;
}

/* Drop overlay inside compose panel */
.mail-compose-drop-overlay {
  position: absolute;
  inset: 0;
  background: rgba(var(--accent-rgb, 0,55,128), .08);
  border: 2px dashed var(--accent);
  border-radius: var(--radius-md);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .75rem;
  color: var(--accent);
  font-size: .9375rem;
  font-weight: 500;
  pointer-events: none;
  z-index: 10;
}

.mail-compose-panel.drag-over {
  outline: 2px dashed var(--accent);
  outline-offset: -2px;
}

/* ── Spin animation for sync button ── */
@keyframes mail-spin {
  to { transform: rotate(360deg); }
}
.spin { animation: mail-spin 1s linear infinite; display: inline-block; }

/* ── Mail-Iframe: immer weißer Hintergrund (Dark-Mode-safe) ── */
/* srcdoc-Iframes enthalten eigene E-Mails – immer auf Weiß rendern */
/* width:100% + border:0: iframe füllt Container-Breite (Desktop: .mail-detail-col;
   Mobile: volle Spalte) → width=device-width im srcdoc greift auf tatsächliche
   iframe-Breite und responsive Mails layouten korrekt ohne Page-Horizontal-Scroll. */
.mail-iframe {
  background: #fff;
  width: 100%;
  border: 0;
}

/* ── Mobile Ordner-Liste ── */
/* Sicherstellt dass native-row als button volle Breite hat */
.native-list .native-row {
  width: 100%;
  box-sizing: border-box;
  min-height: 48px;
  display: flex;
  align-items: center;
  text-align: left;
  border: none;
  background: transparent;
  padding: 0.75rem 1rem;
  gap: 0.75rem;
  cursor: pointer;
  color: var(--text-primary);
}

.native-list .native-row:hover,
.native-list .native-row:focus-visible {
  background: var(--bg-secondary);
  outline: none;
}

.mail-folder-native-row {
  /* Ordner-Zeile: Link-Zone erstreckt sich volle Breite */
  min-height: 52px;
}

.mail-folder-row-icon {
  flex-shrink: 0;
  width: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mail-folder-unread-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
}

.mail-folder-section-header {
  padding: 0.25rem 1rem;
  font-size: 0.75rem;
  color: var(--text-tertiary);
  border-top: 1px solid var(--border);
}

/* ── Mobile overrides ── */
@media (max-width: 900px) {
  .mail-shell { display: none; } /* replaced by mobile drill-down layout */

  .mail-compose-panel {
    position: fixed;
    inset: 0;
    z-index: 200;
    border: none;
  }

  .mail-iframe {
    min-height: 300px;
  }

  /* Mobile Detail-Body: füllt Resthöhe nach page-header, iframe wächst mit */
  .mail-mobile-detail-body {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
  }

  /* Spezifität > .mail-iframe { min-height:300px } – überschreibt via zwei Klassen */
  .mail-mobile-detail-body .mail-iframe {
    flex: 1 1 auto;
    min-height: 0;
  }
}

/* ── Mail Detail Meta (Mobile) ──────────────────────────────────────────── */
/* Kompakter Absender/Betreff-Block in der Mobile-Detailansicht.              */
/* Kein media-query nötig – nur in _renderMobileDetail gerendert.            */
.mail-detail-meta-mobile {
  padding-bottom: .5rem;
  margin-bottom: .5rem;
  border-bottom: 1px solid var(--border);
}

/* Betreff-Zeile mit integriertem Back-Pfeil */
.mail-detail-meta-subjrow {
  display: flex;
  align-items: flex-start;
  gap: .25rem;
  margin-bottom: .25rem;
}

.mail-detail-back-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 36px;
  min-height: 36px;
  margin-left: -.375rem;
  border: none;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  border-radius: var(--radius-md);
  padding: .25rem;
}

.mail-detail-back-btn:hover,
.mail-detail-back-btn:active {
  background: var(--bg-secondary);
  color: var(--text-primary);
}

.mail-detail-meta-subjrow .mail-detail-meta-subject {
  flex: 1;
  min-width: 0;
  margin: 0;
}

.mail-detail-meta-fromaddr {
  color: var(--text-tertiary);
  word-break: break-all;
}

.mail-detail-meta-subject {
  margin: 0 0 .25rem;
  font-size: .9375rem;
  font-weight: 600;
  line-height: 1.25;
  color: var(--text-primary);
}

.mail-detail-meta-from {
  margin: 0 0 .125rem;
  font-size: .78rem;
  color: var(--text-secondary);
}

.mail-detail-meta-date {
  margin: 0;
  font-size: .72rem;
  color: var(--text-tertiary);
}

/* Absender + Datum in einer Zeile (Mobile Detail, Änderung 2026-06-09) */
.mail-detail-meta-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .375rem;
  margin: 0 0 .5rem;
  font-size: .78rem;
  color: var(--text-secondary);
}
.mail-detail-meta-dot {
  color: var(--text-tertiary);
}
.mail-detail-meta-date-inline {
  color: var(--text-tertiary);
  font-size: .72rem;
}

/* Kompakte Einladungs-Statuszeile in Mail-Detail-Ansichten */
.mail-invite-status {
  display: flex;
  align-items: center;
  gap: .375rem;
  margin: .25rem 0 .5rem;
  font-size: .8125rem;
  color: var(--text-secondary);
  /* Standalone (Mobile/Thread): Badge+Icon rechtsbündig sitzen */
  justify-content: flex-end;
}
.mail-invite-status svg {
  color: var(--accent);
  flex-shrink: 0;
}
/* Desktop-Aktionsleiste: Status rechtsbündig, vertikal mittig, kein Extra-Margin */
.mail-detail-actions .mail-invite-status {
  margin: 0 0 0 .5rem;
  /* Im flex-row-Kontext der Aktionsleiste: kein justify-content override nötig –
     .mail-detail-actions ist bereits flex mit justify-content:flex-end-äquivalent */
  justify-content: flex-start;
}

/* Kalender-Icon in der Mail-Liste für Mails mit Termineinladung (has_invite=1) */
.mail-invite-indicator {
  color: var(--accent);
  flex-shrink: 0;
  vertical-align: middle;
}

/* Antwort-Pfeil-Icon in der Mail-Liste für beantwortete Mails (is_answered=1) –
   text-tertiary statt accent: dezent, nicht mit Einladungs-/Kontakt-Badges verwechselbar */
.mail-answered-indicator {
  color: var(--text-tertiary);
  flex-shrink: 0;
  vertical-align: middle;
}

/* „Bekannter Kontakt"-Indikator (Phase A, 2026-07-07) – Listen-Badge neben
   Sendername (.mail-row-from / .native-row-title) + klickbarer Chip im
   Detail-Sender-Bereich (.mail-detail-value / .mail-detail-meta-line). */
.mail-known-contact-indicator {
  color: var(--accent);
  flex-shrink: 0;
  vertical-align: middle;
}
.mail-known-contact-badge {
  display: inline-flex;
  align-items: center;
  margin-left: .3rem;
  vertical-align: middle;
}
.mail-known-contact-chip {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  margin-left: .5rem;
  padding: .0625rem .5rem;
  border: 1px solid var(--accent);
  border-radius: var(--radius-full, 999px);
  background: var(--accent-light);
  color: var(--accent-dark);
  font-size: .75rem;
  font-weight: 500;
  line-height: 1.5;
  cursor: pointer;
  white-space: nowrap;
}
.mail-known-contact-chip:hover {
  background: var(--accent);
  color: #fff;
}
.mail-unknown-sender-hint {
  margin-left: .5rem;
  color: var(--text-tertiary);
  font-size: .75rem;
  font-style: italic;
}

/* ── Form Builder ──────────────────────────────────────────────────────── */
/* Flex-Chain: ds-content-body → page-forms → page-form-builder → .form-builder-layout
   (analog page-calendar-Kommentar oben in _calendar.css). page-form-builder
   selbst ist der Flex-Host: .page-header bleibt fix oben (flex-shrink:0),
   .form-builder-layout nimmt den Rest per flex:1 ein. Ersetzt eine frühere
   feste vh-Berechnung, die die reale Hoehe von .page-header nicht kannte und
   dadurch den unteren Rand des 3-Spalters staendig (unabhängig von Content-
   Größe) um ~86px abschnitt – verifiziert per statischem CSS-Repro, Bug
   2026-07-09.

   🔒 page-forms-Glied (Bug 2026-07-11, "kann man nicht mehr scrollen"): die
   Route #/forms?id=X&view=builder rendert <page-form-builder> NICHT direkt in
   .ds-content-body, sondern als Kind von <page-forms> (page-forms.js render():
   `return html\`<page-form-builder .formId=...></page-form-builder>\`;` – die
   Formular-Liste/Builder/Submissions-Wrapper-Komponente). <page-forms> hatte
   KEINE eigene CSS-Regel → default display:block, kein Flex-Teilnehmer. Damit
   griff page-form-builder's eigenes flex:1 ins Leere (dessen Parent war kein
   Flex-Container mit begrenzter Hoehe), page-form-builder wuchs auf volle
   Content-Hoehe, und .ds-content-body (overflow:hidden im Builder-Modus)
   schnitt den Rest kommentarlos ab – OHNE dass irgendwo ein Scrollbalken
   erschien (weder aussen noch in den 3 Spalten, deren eigene Boxen ja ebenso
   unbegrenzt mitwuchsen). Verifiziert per Repro-Harness (page-forms-Wrapper
   nachgebaut): vorher scrollTop-Schreibversuch auf allen 3 Spalten wirkungslos
   (moved:false), nachher scrollt jede Spalte unabhängig. Fix: page-forms
   bekommt – nur wenn es page-form-builder enthält (:has-Scope, analog
   .ds-content-body:has(page-form-builder) unten in nav.css) – dieselbe
   Flex-Host-Behandlung wie page-form-builder selbst. Für die Formular-LISTE
   (kein page-form-builder-Kind) bleibt page-forms unangetastet – die Liste
   nutzt weiterhin den normalen Block-Flow + .ds-content-body's Default-
   overflow-y:auto (wie jede andere Listenseite). */
page-forms:has(page-form-builder) {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
page-form-builder {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
page-form-builder .page-header {
  flex-shrink: 0;
}
.form-builder-layout {
  display: grid;
  /* Felder-Palette fix bei 200px; Canvas (Mitte) und Properties (rechts) im
     Verhältnis 2:3 – Properties bekommt mehr Platz für Sprach-Tabs +
     i18n-Inputs. minmax verhindert dass eine Spalte unter 360px schrumpft. */
  grid-template-columns: 200px minmax(360px, 2fr) minmax(360px, 3fr);
  gap: 0;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
.form-builder-palette {
  border-right: 1px solid var(--border);
  overflow-y: auto;
  padding: 0.75rem 0;
  /* Grid-Items haben per Default min-height:auto → wachsen bei viel Content
     über die Grid-Track-Hoehe hinaus, das vorhandene overflow-y:auto greift
     dann nie (kann nicht schrumpfen). Pflicht bei jedem .form-builder-layout-
     Grid-Item, sonst wird der Rest unten abgeschnitten (Bug 2026-07-09). */
  min-height: 0;
}
.form-builder-canvas {
  overflow-y: auto;
  padding: 1.5rem;
  background: var(--bg-secondary);
  min-height: 0;
}
.form-builder-props {
  border-left: 1px solid var(--border);
  overflow-y: auto;
  padding: 1rem;
  background: var(--bg-primary);
  min-height: 0;
}

/* Vertikaler Rhythmus im Properties-Panel: 1.125rem Abstand zwischen Items.
   Nur scoped auf den Form-Builder, damit andere Pages mit eigener Form-Group-
   Spacing-Logik unverändert bleiben. */
.form-builder-props .form-group {
  margin-bottom: 1.5rem;
}
.form-builder-props .form-group:last-child {
  margin-bottom: 0;
}
.form-builder-props .form-label {
  /* etwas mehr Luft zwischen Label und Input – die Base-Gap (0.375rem) wirkt
     bei tiefem Properties-Stack zu eng */
  margin-bottom: 0.0625rem;
}

/* CRM-Feld-Marker (read-only) im Property-Panel – eigener Wrapper statt
   .form-group, weil .form-group (flex-column) den Badge sonst per
   align-items:stretch auf volle Breite ziehen würde. */
.form-crm-badge-row {
  margin-bottom: 1.5rem;
}

/* ── ds-theme-toggle Modifier ──────────────────────────────────────────────
   Ergaenzende Modifier für .ds-theme-toggle (Basis in nav.css).
   --sm: kompakter Toggle für Listen/Tabellen (44×26px → 28×16px).
   --teal: gruen wenn aktiv statt accent-blau (z.B. Aktiv/Inaktiv-Status).
   Doppelte Klasse (.ds-theme-toggle.ds-theme-toggle--sm) = höhere Spezifität
   als die Base-Rule in nav.css – verhindert, dass nav.css-Dimensionen gewinnen.
*/
.ds-theme-toggle.ds-theme-toggle--sm {
  width: 28px;
  height: 16px;
  min-width: 0;
}
.ds-theme-toggle.ds-theme-toggle--sm .ds-theme-toggle-thumb {
  width: 12px;
  height: 12px;
  top: 2px;
  left: 2px;
}
.ds-theme-toggle.ds-theme-toggle--sm.active .ds-theme-toggle-thumb {
  transform: translateX(12px); /* 28 - 2 - 2 - 12 = 12px */
}

.ds-theme-toggle.ds-theme-toggle--teal.active {
  background: var(--teal);
}
.ds-theme-toggle.ds-theme-toggle--teal.active:hover {
  background: var(--teal);
  filter: brightness(1.08);
}

/* ── Form-Builder Settings-Row ──
   Toggle-Zeilen im Properties-Panel: eigenstaendige Karte mit Label links und
   Toggle rechts, statt zwei lose Atome im Whitespace. Inspiration: Linear- und
   Vercel-Dashboard-Settings – der ganze Row-Bereich reagiert auf Hover und ist
   klickbar (Toggle behält sein eigenes Click-Target über Bubbling).

   Markup (Lit):
     <label class="builder-toggle-row">
       <span class="builder-toggle-row__main">
         <span class="builder-toggle-row__label">Wizard-Modus</span>
         <span class="builder-toggle-row__hint">…optional Beschreibung…</span>
       </span>
       <button class="ds-theme-toggle …">…</button>
     </label>
*/
.builder-toggle-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 0.875rem;
  padding: 0.6875rem 0.875rem;
  margin: 0 0 1.5rem; /* Rhythmus-Spacing analog form-group */
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color 150ms ease, background 150ms ease, box-shadow 150ms ease;
}
.builder-toggle-row:hover {
  border-color: color-mix(in srgb, var(--accent) 35%, var(--border));
  background: var(--bg-primary);
}
.builder-toggle-row:has(.ds-theme-toggle.active) {
  /* Aktive Zeile bekommt einen subtilen Accent-Tint, damit sie auf einen Blick
     vom Rest unterscheidbar ist – ohne aufdringlich zu wirken. */
  border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
  background: color-mix(in srgb, var(--accent-light) 50%, var(--bg-primary));
}
.builder-toggle-row__main {
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  flex: 1;
  min-width: 0;
}
.builder-toggle-row__label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.005em;
  line-height: 1.3;
}
.builder-toggle-row__hint {
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--text-tertiary);
  line-height: 1.4;
}
.builder-toggle-row .ds-theme-toggle {
  flex-shrink: 0;
}
.form-palette-item {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 0.75rem;
  cursor: pointer;
  font-size: 0.875rem;
  color: var(--text-secondary);
  transition: background var(--transition);
}
.form-palette-item:hover { background: var(--accent-light); color: var(--accent); }
.form-palette-item.disabled { opacity: 0.45; cursor: not-allowed; }

/* ── Form-Builder Breiten-Icon-Auswahl (Spec 20260707 flexibles Layout) ──
   Ersetzt das frühere <select> im Property-Panel: 4 Icon-Buttons, jedes
   Icon zeigt die Spalten-Proportion als 6-Segment-Balken – 1:1 zum
   zugrundeliegenden 6-Spalten-Grid-Modell (siehe _form-layout.js::spanFor).
   Aktive Auswahl: Accent-Border + Accent-Light-BG + Accent-Text. */
.form-width-picker {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.form-width-picker-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3125rem;
  padding: 0.5rem 0.625rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text-tertiary);
  cursor: pointer;
  transition: border-color 150ms ease, background 150ms ease, color 150ms ease;
  flex: 1;
  min-width: 0;
}
.form-width-picker-btn:hover {
  border-color: color-mix(in srgb, var(--accent) 35%, var(--border));
  color: var(--text-secondary);
}
.form-width-picker-btn.active {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
}
.form-width-picker-btn svg { flex-shrink: 0; }
.form-width-picker-btn__label {
  font-size: 0.6875rem;
  font-weight: 500;
  white-space: nowrap;
}

/* ── Form-Builder Live-Vorschau: 6-Spalten-Grid ──
   Eigene Klassen statt Wiederverwendung von `.form-row`/`.form-cell` – die
   generische `.form-row` (oben, Z.364) ist app-weit als 2-Spalten-Split im
   Einsatz (z.B. Mail „Zu Kontakt hinzufuegen"-Panel) und darf nicht auf ein
   6-Spalten-Grid umgestellt werden. `--fw` (Custom Property statt Roh-Wert)
   hält den Span dynamisch pro Feld. */
.form-builder-preview-row {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 1rem;
}
.form-builder-preview-cell {
  grid-column: span var(--fw, 6);
  min-width: 0;
}
@media (max-width: 600px) {
  .form-builder-preview-row { grid-template-columns: 1fr; }
  .form-builder-preview-cell { grid-column: span 1 !important; }
}
.form-palette-item.disabled:hover { background: none; color: var(--text-secondary); }
.form-palette-icon { font-size: 1rem; width: 20px; text-align: center; }
/* Palette-Gruppen-Überschrift ("Feldtypen" / "CRM Feldtypen") – --sep hängt
   eine Trennlinie + zusätzlichen Abstand über nachfolgende Gruppen. */
.form-palette-group-heading {
  padding: 0.5rem 0.75rem 0.25rem;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-tertiary);
}
.form-palette-group-heading--sep {
  margin-top: 0.5rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
}
.form-canvas-field {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.75rem 1rem;
  margin-bottom: 0.625rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  transition: border-color var(--transition);
}
.form-canvas-field:hover,
.form-canvas-field.selected { border-color: var(--accent); }
.form-canvas-field.drag-over { border-color: var(--accent); border-style: dashed; background: var(--accent-light); }
.form-canvas-field.dragging  { opacity: 0.4; }
.form-canvas-drag-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  flex-shrink: 0;
  color: var(--text-tertiary);
  cursor: grab;
  padding: 0 2px;
}
.form-canvas-drag-handle:active { cursor: grabbing; }
.form-canvas-drag-handle:hover  { color: var(--accent); }
.form-canvas-field-info { flex: 1; min-width: 0; }
.form-canvas-field-type { font-size: 0.75rem; color: var(--text-tertiary); }
.form-canvas-field-label { font-size: 0.875rem; font-weight: 500; color: var(--text-primary); }
.form-canvas-field-actions { display: flex; gap: 0.25rem; }
.form-canvas-empty {
  text-align: center;
  padding: 3rem 1rem;
  color: var(--text-tertiary);
}
.form-options-list { display: flex; flex-direction: column; gap: 0.375rem; }
.form-option-row { display: flex; align-items: center; gap: 0.5rem; }
.form-option-row input { flex: 1; }
/* Form-Builder: Reihenfolge-Buttons (Auf/Ab) – immer sichtbar, Touch-Target ≥40px */
.form-canvas-move-btn {
  min-width: 40px;
  min-height: 40px;
  opacity: 0.55;
  transition: opacity var(--transition);
}
.form-canvas-move-btn:not(:disabled):hover { opacity: 1; }
.form-canvas-move-btn:disabled { opacity: 0.2; cursor: not-allowed; }

/* Mobile */
@media (max-width: 900px) {
  /* Desktop-Flex-Chain zurücksetzen – Mobile stapelt die 3 Bereiche und
     scrollt normal über .ds-content-body (siehe nav.css Mobile-Override),
     statt intern zu clippen. */
  page-form-builder { display: block; flex: none; min-height: 0; overflow: visible; }
  .form-builder-layout { grid-template-columns: 1fr; height: auto; flex: none; overflow: visible; }
  .form-builder-palette,
  .form-builder-props { border: none; border-bottom: 1px solid var(--border); }

  /* Visuelle Abschnitts-Trennung zwischen den drei gestapelten Bereichen */
  .form-builder-palette::before {
    content: 'Feldtypen';
    display: block;
    padding: 0.75rem 0.75rem 0.25rem;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-tertiary);
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border);
    margin-bottom: 0.25rem;
  }
  .form-builder-canvas::before {
    content: 'Formular';
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-tertiary);
    margin-bottom: 0.75rem;
    padding-top: 0.25rem;
  }
  .form-builder-props::before {
    content: 'Einstellungen';
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-tertiary);
    margin-bottom: 0.75rem;
    border-top: 2px solid var(--accent-light);
    padding-top: 0.75rem;
  }
}

/* Booking-Detail-Panel: Comments-Sektion-Wrap (visuelle Trennung) */
.booking-detail-comments-wrap {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.booking-detail-comments-title {
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  margin-bottom: .625rem;
}

/* ─────────────────────────────────────────────────────────────────
   <ds-comments>
   Refined-minimalism Comments-Modul. Vertikale Timeline-Schiene
   links, dezente Avatar-Kreise, Hover-revealed Aktionen, Mentions
   als Akzent-Pills, Tags als hairline-outlined Chips.
   ───────────────────────────────────────────────────────────────── */

.ds-comments {
  display: block;
  font-size: .875rem;
  color: var(--text-primary);
  line-height: 1.5;
}

/* ── Composer ──────────────────────────────────────────────────── */
.cmt-composer {
  position: relative; /* anchor für .cmt-picker (absolute top:100%) */
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .75rem;
  margin-bottom: 1.25rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.cmt-composer:focus-within {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent);
}
.cmt-composer.is-drag-over {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, var(--bg-primary));
  border-style: dashed;
}
.cmt-textarea {
  width: 100%;
  border: 0;
  background: transparent;
  resize: none; /* Ticket 3.309, Entscheid E7 – Wachstum via JS (autoGrowTextarea), kein Ziehgriff mehr */
  min-height: 2.4em;
  max-height: 40vh; /* Deckel doppelt: CSS + JS – s. window.autoGrowTextarea in utils.js */
  padding: 0;
  font: inherit;
  color: inherit;
  outline: none;
  line-height: 1.5;
  overflow-y: hidden; /* JS schaltet auf 'auto' nur bei echtem Überlauf > max-height */
}
.cmt-textarea::placeholder {
  color: var(--text-tertiary);
  font-size: .8125rem;
}
.cmt-composer-actions {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding-top: .375rem;
  border-top: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
}
.cmt-composer-hint {
  flex: 1;
  font-size: .7rem;
  color: var(--text-tertiary);
  letter-spacing: -0.005em;
}
.cmt-composer-hint code {
  font-size: .65rem;
  padding: .0625rem .25rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.cmt-attach-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.625rem; height: 1.625rem;
  color: var(--text-tertiary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: color 150ms ease, background 150ms ease;
}
.cmt-attach-btn:hover {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.cmt-submit { letter-spacing: -0.005em; }

.cmt-draft-files {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
  padding-bottom: .25rem;
}
.cmt-draft-file {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .25rem .5rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  font-size: .75rem;
  max-width: 100%;
}
.cmt-draft-file svg { color: var(--text-tertiary); flex-shrink: 0; }
.cmt-draft-file-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 12rem;
}
.cmt-draft-file-size {
  color: var(--text-tertiary);
  font-size: .7rem;
}
.cmt-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.125rem; height: 1.125rem;
  background: transparent;
  border: 0;
  border-radius: 50%;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: color 150ms ease, background 150ms ease;
}
.cmt-icon-btn:hover {
  color: var(--coral);
  background: color-mix(in srgb, var(--coral) 12%, transparent);
}

/* ── Stream ────────────────────────────────────────────────────── */
.cmt-stream {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}
.cmt-empty {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--text-tertiary);
  font-size: .8125rem;
  font-style: italic;
}
.cmt-error {
  padding: .625rem .875rem;
  margin-bottom: .75rem;
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--coral) 10%, transparent);
  color: var(--coral);
  font-size: .8125rem;
}

/* ── Comment-Karte ─────────────────────────────────────────────── */
.cmt {
  position: relative;
  padding-left: 1.25rem;
  animation: cmt-enter 220ms ease-out;
}
@keyframes cmt-enter {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Vertikale Timeline-Schiene: dezenter 1px-Strich + Marker pro Comment.
   Lebt visuell von der Achse – Comments fuehlen sich wie Story-Einträge an. */
.cmt-rail {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: linear-gradient(
    to bottom,
    transparent 0,
    var(--border) .25rem,
    var(--border) calc(100% - .25rem),
    transparent 100%
  );
}
.cmt-rail-marker {
  position: absolute;
  left: 50%;
  top: .65rem;
  width: 8px; height: 8px;
  border-radius: 50%;
  border: 1.5px solid var(--border);
  background: var(--bg-primary);
  transform: translateX(-50%);
  transition: border-color 200ms ease, background 200ms ease, box-shadow 200ms ease;
}
.cmt:hover > .cmt-rail .cmt-rail-marker {
  border-color: var(--accent);
}
.cmt-rail-marker.is-filled {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}

/* ── Header ────────────────────────────────────────────────────── */
.cmt-head {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: .375rem;
  min-height: 1.5rem;
}
.cmt-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem; height: 1.5rem;
  border-radius: 50%;
  background: var(--cmt-avatar-color, var(--text-tertiary));
  color: white;
  font-size: .625rem;
  font-weight: 600;
  letter-spacing: .02em;
  flex-shrink: 0;
  overflow: hidden;
}
.cmt-avatar img { width: 100%; height: 100%; object-fit: cover; }
.cmt-avatar--sm { width: 1.25rem; height: 1.25rem; font-size: .55rem; }
.cmt-avatar-initials { line-height: 1; }
.cmt-author {
  font-weight: 600;
  font-size: .8125rem;
  color: var(--text-primary);
  letter-spacing: -0.005em;
}
.cmt-time {
  font-size: .7rem;
  color: var(--text-tertiary);
  letter-spacing: -0.005em;
}
.cmt-time-edited {
  font-size: .7rem;
  color: var(--text-tertiary);
  font-style: italic;
}
.cmt-pin-badge {
  font-size: .55rem;
  color: var(--accent);
  margin-left: -.125rem;
  line-height: 1;
}

/* ── Aktions-Toolbar (rechts, Hover-revealed) ──────────────────── */
.cmt-actions {
  margin-left: auto;
  display: flex;
  gap: .125rem;
  opacity: 0;
  transform: translateX(2px);
  transition: opacity 160ms ease, transform 160ms ease;
}
.cmt:hover .cmt-actions,
.cmt:focus-within .cmt-actions {
  opacity: 1;
  transform: translateX(0);
}
.cmt-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem; height: 1.5rem;
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--text-tertiary);
  cursor: pointer;
  transition: color 150ms ease, background 150ms ease;
}
.cmt-action:hover {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.cmt-action--danger:hover {
  color: var(--coral);
  background: color-mix(in srgb, var(--coral) 12%, transparent);
}

/* ── Body ──────────────────────────────────────────────────────── */
.cmt-body {
  font-size: .875rem;
  line-height: 1.55;
  color: var(--text-primary);
  word-wrap: break-word;
}
.cmt-body--sm { font-size: .8125rem; }
.cmt-body .cmt-h1 {
  font-size: 1.0625rem;
  font-weight: 700;
  margin: .5rem 0 .375rem;
  letter-spacing: -0.015em;
  color: var(--text-primary);
  line-height: 1.25;
}
.cmt-body .cmt-h1:first-child { margin-top: 0; }
.cmt-body .cmt-h2 {
  font-size: .9375rem;
  font-weight: 600;
  margin: .375rem 0 .25rem;
  letter-spacing: -0.01em;
  color: var(--text-primary);
}
.cmt-body .cmt-h3 {
  font-size: .8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  margin: .625rem 0 .125rem;
  color: var(--text-secondary);
}
.cmt-body .cmt-p {
  margin: 0 0 .25rem;
}
.cmt-body .cmt-p:last-child { margin-bottom: 0; }
.cmt-body .cmt-list {
  margin: .125rem 0 .25rem;
  padding-left: 1rem;
}
.cmt-body .cmt-list li { margin-bottom: .0625rem; }
.cmt-body .cmt-bq {
  margin: .375rem 0;
  padding: .25rem .625rem;
  border-left: 2px solid color-mix(in srgb, var(--accent) 45%, var(--border));
  color: var(--text-secondary);
  font-style: italic;
}
.cmt-body .cmt-pre {
  margin: .375rem 0;
  padding: .5rem .625rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  overflow-x: auto;
}
.cmt-body .cmt-inline-code {
  padding: .0625rem .3125rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8125em;
}
.cmt-body .cmt-link {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px dotted color-mix(in srgb, var(--accent) 35%, transparent);
  transition: border-color 150ms ease;
}
.cmt-body .cmt-link:hover {
  border-bottom-color: var(--accent);
}

/* Mentions: gefuellte Akzent-Pills */
.cmt-mention {
  display: inline-flex;
  align-items: center;
  padding: 0 .375rem;
  margin: 0 .0625rem;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent);
  font-size: .78em;
  font-weight: 500;
  border-radius: var(--radius-sm);
  cursor: pointer;
  letter-spacing: -0.005em;
  transition: background 150ms ease;
}
.cmt-mention:hover {
  background: color-mix(in srgb, var(--accent) 22%, transparent);
}
.cmt-mention--contact {
  background: color-mix(in srgb, var(--teal) 14%, transparent);
  color: var(--teal);
}
.cmt-mention--contact:hover {
  background: color-mix(in srgb, var(--teal) 26%, transparent);
}

/* Tags: hairline-outlined Chips */
.cmt-tag-inline {
  display: inline-flex;
  align-items: center;
  padding: 0 .375rem;
  margin: 0 .0625rem;
  background: transparent;
  color: var(--text-secondary);
  font-size: .75em;
  font-weight: 500;
  border: 1px solid color-mix(in srgb, var(--text-tertiary) 35%, transparent);
  border-radius: var(--radius-sm);
  cursor: pointer;
  letter-spacing: -0.005em;
  transition: color 150ms ease, border-color 150ms ease;
}
.cmt-tag-inline:hover {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
}

/* Block-Tags-Liste unter Body */
.cmt-tags {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem;
  margin-top: .5rem;
}
.cmt-tag {
  display: inline-flex;
  align-items: center;
  padding: .0625rem .4375rem;
  background: transparent;
  color: var(--text-tertiary);
  font-size: .7rem;
  font-weight: 500;
  border: 1px solid color-mix(in srgb, var(--text-tertiary) 30%, transparent);
  border-radius: var(--radius-sm);
  letter-spacing: -0.005em;
}

/* ── Anhänge ──────────────────────────────────────────────────── */
.cmt-attachments {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  margin-top: .5rem;
}
.cmt-attachment {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .25rem .5rem;
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-primary);
  text-decoration: none;
  font-size: .75rem;
  transition: background 150ms ease;
  position: relative;
  max-width: max-content;
}
.cmt-attachment:hover {
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-secondary));
}
.cmt-attachment svg { color: var(--text-tertiary); flex-shrink: 0; }
.cmt-attachment-name {
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 14rem;
}
.cmt-attachment-size {
  color: var(--text-tertiary);
  font-size: .7rem;
}
.cmt-attachment-rm {
  margin-left: .25rem;
  opacity: 0;
  transition: opacity 150ms ease;
}
.cmt-attachment:hover .cmt-attachment-rm { opacity: 1; }

/* ── Replies (1 Ebene) ─────────────────────────────────────────── */
.cmt-replies {
  margin-top: .75rem;
  padding-left: 1rem;
  border-left: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.cmt--reply {
  padding-left: 0;
}
.cmt--reply .cmt-rail { display: none; }

/* ── Edit / Reply Shells ──────────────────────────────────────── */
.cmt-edit-shell, .cmt-reply-shell {
  position: relative; /* anchor für Inline-Picker */
  margin-top: .375rem;
  padding: .5rem .625rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  display: flex;
  flex-direction: column;
  gap: .5rem;
  animation: cmt-enter 180ms ease-out;
}
.cmt-edit-shell:focus-within, .cmt-reply-shell:focus-within {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
}
.cmt-edit-actions {
  display: flex;
  justify-content: flex-end;
  gap: .375rem;
}

/* ── Skeleton ──────────────────────────────────────────────────── */
.cmt-skeleton-composer {
  height: 4.5rem;
  width: 100%;
  margin-bottom: 1.25rem;
}
.cmt-skeleton-row {
  display: flex;
  gap: .75rem;
  margin-bottom: 1rem;
  padding-left: 1.25rem;
}
.cmt-skeleton-row .skeleton-circle {
  width: 1.5rem; height: 1.5rem;
  flex-shrink: 0;
}
.cmt-skeleton-lines {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .375rem;
}

/* ── Mention-Picker (autocomplete) ─────────────────────────────── */
/* Inline gerendert pro Textarea-Container – verlaesslich anker direkt
   unter dem Eingabefeld (top:100%). Container muss position:relative haben. */
.cmt-picker {
  position: absolute;
  top: calc(100% + .25rem);
  left: 0;
  right: 0;
  z-index: 50;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: .25rem;
  display: flex;
  flex-direction: column;
  gap: 1px;
  max-height: 16rem;
  overflow-y: auto;
  font-size: .8125rem;
  animation: cmt-enter 140ms ease-out;
}
.cmt-picker-item {
  display: grid;
  grid-template-columns: 1.5rem 1fr auto auto;
  align-items: center;
  gap: .5rem;
  padding: .375rem .5rem;
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  text-align: left;
  cursor: pointer;
  color: var(--text-primary);
  transition: background 100ms ease;
  width: 100%;
}
.cmt-picker-item:hover,
.cmt-picker-item.is-active {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.cmt-picker-item.is-active {
  outline: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
}
.cmt-picker-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem; height: 1.5rem;
  border-radius: 50%;
  background: var(--cmt-avatar-color, var(--text-tertiary));
  color: white;
  font-size: .55rem;
  font-weight: 600;
  letter-spacing: .02em;
  overflow: hidden;
  flex-shrink: 0;
}
.cmt-picker-avatar img { width: 100%; height: 100%; object-fit: cover; }
.cmt-picker-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem; height: 1.5rem;
  font-weight: 600;
  font-size: .9rem;
  color: var(--text-tertiary);
}
.cmt-picker-icon--tag { color: var(--accent); }
.cmt-picker-name {
  font-weight: 500;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  letter-spacing: -0.005em;
}
.cmt-picker-meta {
  font-size: .7rem;
  color: var(--text-tertiary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 9rem;
}
.cmt-picker-type {
  font-size: .65rem;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: .0625rem .375rem;
  border-radius: var(--radius-sm);
  border: 1px solid color-mix(in srgb, var(--text-tertiary) 25%, transparent);
}

/* ── Mobile ────────────────────────────────────────────────────── */
@media (max-width: 600px) {
  .cmt-actions { opacity: 1; transform: none; } /* Touch: kein Hover */
  .cmt-attachment-rm { opacity: 1; }
  .cmt-composer-hint { display: none; }
  .cmt-picker { min-width: 0; max-width: calc(100vw - 1rem); }
}

/* ── ds-address-autocomplete – Inline-Suggestion-Dropdown ───────── */
/* Eigene Dropdown-UI (programmatische Places API v3, keine gmp-Web-Component) */
/* CSS-Variablen → Light + Dark automatisch abgedeckt                          */

.ds-addr-ac {
  position: relative;
}

.ds-addr-ac-list {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  margin: 4px 0 0;
  padding: 4px 0;
  list-style: none;
  max-height: 280px;
  overflow-y: auto;
  /* Above ds-cal-panel (z-index 401) */
  z-index: 410;
}

.ds-addr-ac-item {
  padding: 0.5rem 0.75rem;
  cursor: pointer;
  transition: var(--transition);
}

.ds-addr-ac-item.active,
.ds-addr-ac-item:hover {
  background: var(--accent-light);
}

.ds-addr-ac-main {
  font-weight: 500;
  color: var(--text-primary);
  font-size: 0.9rem;
}

.ds-addr-ac-secondary {
  font-size: 0.8rem;
  color: var(--text-secondary);
  margin-top: 1px;
}

/* ── ds-contact-picker (Spec 2000 Schritt 4) ────────────────────
   Single-Select-Kontakt-Picker für Rechnungen, Angebote etc.
   Analog zu .fb-contact-suggest / .attendee-suggest-dropdown –
   aber als eigenstaendige Lit-Component mit eigenem Wrapper.
*/
.ds-cp-wrap {
  position: relative;
}

/* Suchfeld: erbt .input-Styling, kein Extra-Override nötig */

/* Ausgewählter Kontakt: Readonly-Zeile mit X-Button */
.ds-cp-selected {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  padding: .45rem .65rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  min-height: 2.25rem;
  position: relative;
  padding-right: 2rem;        /* Platz für Clear-Button */
}
.ds-cp-selected-name {
  font-size: .9rem;
  color: var(--text-primary);
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1 1 auto;
  min-width: 0;
}
.ds-cp-selected-email {
  font-size: .78rem;
  color: var(--text-tertiary);
  white-space: nowrap;
  flex-shrink: 0;
}
/* A5: Link-Icon zur Detail-Seite (Kontakt / Firma) */
.ds-cp-detail-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: .375rem;
  min-width: 32px;
  min-height: 32px;
  line-height: 1;
  color: var(--text-tertiary);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  transition: color var(--transition), background var(--transition);
  text-decoration: none;
}
.ds-cp-detail-link:hover {
  color: var(--accent);
  background: var(--accent-light);
}
@media (max-width: 900px) {
  .ds-cp-detail-link {
    min-width: 44px;
    min-height: 44px;
    padding: .5rem;
  }
}
.ds-cp-clear {
  position: absolute;
  right: .4rem;
  top: 50%;
  transform: translateY(-50%);
  padding: .2rem;
  line-height: 1;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color var(--transition), background var(--transition);
}
.ds-cp-clear:hover {
  color: var(--coral);
  background: var(--coral-light);
}

/* Suggestion-Dropdown */
.ds-cp-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  max-height: 220px;
  overflow-y: auto;
  z-index: 410;
}
.ds-cp-item {
  padding: .5rem .75rem;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: .15rem;
  font-size: .85rem;
  transition: background var(--transition);
}
.ds-cp-item:hover,
.ds-cp-item.is-active { background: var(--accent-light); }
.ds-cp-item-name {
  color: var(--text-primary);
  font-weight: 500;
}
.ds-cp-item-sub {
  color: var(--text-tertiary);
  font-size: .78rem;
}

/* Create-Footer-Item (Inline-Create-Link am Dropdown-Ende) */
.ds-cp-item--create {
  flex-direction: row;
  align-items: center;
  gap: .4rem;
  color: var(--accent);
  font-weight: 500;
  border-top: 1px solid var(--border);
  padding-top: .55rem;
  padding-bottom: .55rem;
  min-height: 44px;           /* Touch-Target */
}
.ds-cp-item--create:hover {
  background: var(--accent-light);
}
/* Plus-Icon im Create-Item */
.ds-cp-item--create .ds-cp-create-icon {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  color: var(--accent);
}

/* ── Picker Top-Suggestion-Sektion (Time-Tracking Polish Session D) ─────── */
/* Wird in ds-company-picker oben im Dropdown-Bereich gerendert,
   wenn Smart-Suggestion-Counter Einträge vorhanden sind. */
.ds-picker-top-section {
  margin-bottom: .125rem;
  border-bottom: 1px solid var(--border);
  padding-bottom: .125rem;
}
.ds-picker-top-header {
  padding: .35rem .75rem .2rem;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  user-select: none;
}
.ds-picker-top-item {
  display: flex;
  align-items: center;
  gap: .375rem;
  padding: .5rem .75rem;
  cursor: pointer;
  min-height: 36px;
}
.ds-picker-top-item:hover {
  background: var(--bg-secondary);
}
.ds-picker-top-item.is-active {
  background: var(--accent-light);
}
.ds-picker-top-item-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .9rem;
}
.ds-picker-top-dismiss {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border: none;
  background: none;
  cursor: pointer;
  padding: 0;
  opacity: .45;
  color: var(--text-tertiary);
  border-radius: var(--radius-sm);
  transition: opacity var(--transition), color var(--transition), background var(--transition);
}
.ds-picker-top-dismiss:hover {
  opacity: 1;
  color: var(--coral);
  background: var(--coral-light);
}

/* ── Contacts: Kundennummer pro Profil ──────────────────────────────── */
.contact-customer-numbers {
  display: flex;
  flex-direction: column;
  gap: .375rem;
  margin-top: .25rem;
}
.contact-customer-number-row {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.contact-customer-number-profile {
  min-width: 8rem;
  font-size: .875rem;
  color: var(--text-secondary);
}
.contact-customer-number-row .input {
  flex: 1;
}

/* ── Visibility: Icon in Listen (ds-vis-icon) ──────────────────── */
/*
 * Kleine Sichtbarkeits-Indikatoren neben Eintrags-Titel in Listen.
 * Slot: privat=Schloss, all=Globus, team=kein Icon.
 * Leicht gedimmt damit sie optisch nicht mit dem Inhalt konkurrieren.
 * Spec: stratum_roles_permissions.md – Schritt 9
 */
.ds-vis-icon {
  display: inline-flex;
  align-items: center;
  color: var(--text-tertiary);
  vertical-align: middle;
  margin-inline-start: .25rem;
  flex-shrink: 0;
}
.ds-vis-icon--private {
  color: var(--text-tertiary);
}
.ds-vis-icon--all {
  color: var(--teal);
  opacity: .75;
}

/* Owner-Avatar neben fremden Team-Einträgen */
.ds-vis-owner-hint {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  margin-inline-start: .375rem;
  vertical-align: middle;
  font-size: .72rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}
.ds-vis-owner-avatar {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  overflow: hidden;
  flex-shrink: 0;
  background: var(--accent-light);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .6rem;
  font-weight: 700;
  color: var(--accent);
  line-height: 1;
}
.ds-vis-owner-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Visibility-Picker Integration in Forms */
.ds-vis-form-row {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .5rem 0;
}
.ds-vis-form-row .form-label {
  margin-bottom: 0;
  white-space: nowrap;
}

@media (max-width: 900px) {
  .ds-vis-owner-hint > span { display: none; }  /* nur Avatar auf Mobile */
}

/* ── Super-Admin: Benutzer-Verwaltung (page-users) ──────────────────────── */

/* Mandanten-Filter direkt unter der Such-Bar */
.users-filter-bar {
  margin: .5rem 0 .75rem;
  display: flex;
  align-items: center;
  gap: .5rem;
}
.users-filter-bar .select {
  min-width: 200px;
  max-width: 320px;
}

/* Tab-Leiste im Edit-Slide-In-Panel */
.users-edit-tabs {
  margin: .5rem 0 0;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0;
  flex-wrap: wrap;
  gap: 0;
}
.users-edit-tabs .tab-filter-btn {
  font-size: .8rem;
  padding: .4rem .65rem;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

/* Mandant-Spalte: Zeilen-Liste */
.users-tenant-list {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  font-size: .875rem;
}

/* Rolle-Spalte: Badge-Liste (gleiche Reihenfolge wie Tenant-Liste) */
.users-role-list {
  display: flex;
  flex-direction: column;
  gap: .2rem;
}

/* Membership-Zeile in Tab 4 */
.users-membership-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .4rem 0;
  border-bottom: 1px solid var(--border);
}
.users-membership-name {
  flex: 1;
  font-size: .875rem;
  color: var(--text-primary);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Select in der Membership-Row darf nicht volle Breite einnehmen
   (würde sonst den .users-membership-name auf 0 quetschen) */
.users-membership-row > .select,
.users-membership-row > .select.select-sm {
  width: auto;
  min-width: 9rem;
  flex: 0 0 auto;
}
.users-membership-expires {
  font-size: .75rem;
  color: var(--text-tertiary);
  display: inline-flex;
  align-items: center;
  gap: .2rem;
  white-space: nowrap;
}
.users-membership-remove {
  color: var(--coral);
  flex-shrink: 0;
}

/* 5er-Grid für Farb-Picker im Kalender-Tab */
.users-color-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: .75rem;
  padding: .5rem 0;
}
.users-color-item {
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
.users-color-input {
  height: 2.25rem;
  padding: .15rem .25rem;
  cursor: pointer;
  min-width: 0;
  width: 100%;
}

/* Mobile: Mandant+Rolle-Badges untereinander in der nativen Liste */
.users-mobile-memberships {
  display: flex;
  flex-wrap: wrap;
  gap: .2rem;
  margin-top: .25rem;
}

/* text-tertiary Hilfsklasse für leere Spalten */
.text-tertiary {
  color: var(--text-tertiary);
}

@media (max-width: 900px) {
  .users-filter-bar .select {
    min-width: 0;
    flex: 1;
    max-width: 100%;
  }
  .users-color-grid {
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  }
  .users-membership-row {
    flex-wrap: wrap;
    gap: .375rem;
  }
  .users-membership-name {
    flex-basis: 100%;
    white-space: normal;
  }
}

/* ── Team / Users – Toolbar ──────────────────────────────────── */
.ds-team-toolbar {
  display: flex;
  gap: .5rem;
  align-items: stretch;
  margin-bottom: 1rem;
}
.ds-team-toolbar-search {
  flex: 9;
  margin-bottom: 0;
  min-width: 0;
}
.ds-team-toolbar-tabs {
  flex: 3;
  margin-bottom: 0;
}
@media (max-width: 600px) {
  .ds-team-toolbar { flex-direction: column; }
  .ds-team-toolbar-search,
  .ds-team-toolbar-tabs { flex: 1 1 auto; }
}

/* ── Platform-Admin System-Dashboard ────────────────────────────────────────── */
/* Spec: 20260516_maintenance_mode – Session 2 */

.system-dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
  margin-top: 1rem;
}

.system-card {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: .25rem;
  transition: var(--transition);
}

.system-card--clickable {
  cursor: pointer;
}
.system-card--clickable:hover {
  border-color: var(--accent);
  background: var(--bg-secondary);
}

.system-card-label {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  font-weight: 600;
}

.system-card-value {
  font-size: 2rem;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1;
  margin-top: .25rem;
}

/* Modifier für Karten ohne numerischen Wert (Ticket 3.94.3, Rundnachricht-Karte)
   – Textwert statt Zahl braucht keine 2rem-Grossschrift. */
.system-card-value--sm {
  font-size: 1.125rem;
  font-weight: 600;
}

.system-card-hint {
  font-size: .75rem;
  color: var(--text-tertiary);
  margin-top: .25rem;
}

.system-card-actions {
  display: flex;
  gap: .5rem;
  margin-top: .75rem;
  flex-wrap: wrap;
}

/* Wartungsmodus-Card – aktiv */
.system-card--maintenance.is-active {
  border-color: var(--coral);
  background: var(--coral-light);
}
.system-card--maintenance.is-active .system-card-value {
  color: var(--coral);
}

/* Wartungsmodus-Card – geplant */
.system-card--maintenance.is-scheduled {
  border-color: var(--amber);
  background: var(--amber-light);
}
.system-card--maintenance.is-scheduled .system-card-value {
  color: var(--amber);
}

/* Wartungsmodus-Card – Nur-Lesen-Betrieb (Ticket 3.94.2 = 3.94 Teil 3) */
.system-card--maintenance.is-readonly {
  border-color: var(--accent);
  background: var(--accent-light);
}
.system-card--maintenance.is-readonly .system-card-value {
  color: var(--accent);
}

/* ── Attachments Section (generisch, C4-C7 Session 5 2026-05-25) ──────────── */
.ds-attachments-section {}
.ds-attachments-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .75rem;
}
.ds-attachments-title {
  font-size: .875rem;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--text-tertiary);
  letter-spacing: .04em;
}
.ds-attachments-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.ds-attachments-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--border);
}
.ds-attachments-item:last-child {
  border-bottom: none;
}
.ds-attachments-item-icon {
  color: var(--text-tertiary);
  flex-shrink: 0;
}
.ds-attachments-item-info {
  flex: 1;
  min-width: 0;
}
.ds-attachments-item-name {
  font-size: .875rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-attachments-item-meta {
  font-size: .75rem;
  color: var(--text-tertiary);
}
.ds-attachments-item-preview-trigger {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex: 1;
  min-width: 0;
  padding: 0;
  border: none;
  background: none;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
  border-radius: var(--radius-sm);
}
.ds-attachments-item-preview-trigger:hover .ds-attachments-item-name,
.ds-attachments-item-preview-trigger:focus-visible .ds-attachments-item-name {
  color: var(--accent);
}
.ds-attachments-item-preview-trigger:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.ds-attachments-actions {
  display: flex;
  gap: .25rem;
  flex-shrink: 0;
}
.ds-attachments-empty {
  color: var(--text-tertiary);
  font-size: .875rem;
  padding: .75rem 0;
  text-align: center;
}
.ds-attachments-uploading {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .875rem;
  color: var(--text-tertiary);
  margin-top: .5rem;
}

/* ── Attachments-Gruppen (Firmen – Partner-Standarddokumente, S2 2026-06-30) ── */
.ds-attachments-group {
  margin-bottom: 1.125rem;
}
.ds-attachments-group:last-child {
  margin-bottom: 0;
}
.ds-attachments-group-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-bottom: .375rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: .375rem;
}
.ds-attachments-group-title {
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-secondary);
}
.ds-attachments-group-empty {
  font-size: .8125rem;
  color: var(--text-tertiary);
  padding: .375rem 0 .25rem;
  font-style: italic;
}
.ds-attachments-group.drag-over {
  outline: 2px dashed var(--accent);
  outline-offset: -2px;
  background: var(--accent-light);
  border-radius: var(--radius-sm);
}

/* Sessions-Tabelle im Panel */
.system-sessions-table th {
  font-size: .8rem;
}
.system-sessions-table td {
  font-size: .82rem;
  vertical-align: middle;
}

/* Wartungsverlauf-Panel (Ticket 3.94.1) */
.system-panel-loading {
  padding: 1.5rem;
  text-align: center;
  color: var(--text-tertiary);
}
.system-history-empty {
  padding: 3rem 1rem;
  text-align: center;
  color: var(--text-tertiary);
  font-size: .875rem;
}
.system-history-nowrap {
  white-space: nowrap;
}
.system-history-subline {
  font-size: .72rem;
  color: var(--text-tertiary);
}
.system-history-more {
  margin-top: .75rem;
  text-align: center;
}

/* Mobile overrides */
@media (max-width: 900px) {
  page-platform-admin-system .page-header-h1 { display: none; }
  .system-dashboard-grid { grid-template-columns: 1fr; }
  .system-card-value { font-size: 1.5rem; }
  .system-card-value--sm { font-size: 1rem; }
}

/* ── Systemfähigkeiten (B65-Vorprüfung, 2026-08-02) ───────────────────────────
   Hoster-Unterschiede (PHP-Erweiterungen, DB-Engine, PDF-Rasterung) sichtbar
   machen – Anlass: PDF-Rasterung war lokal/PROD unterschiedlich (kein
   Ghostscript/PDF-Delegate auf PROD), nur per SSH-Wegwerf-Skript geprüft.
   Genutzt in: pages/platform-admin-system.js (_renderCapabilitiesFieldset). */
.system-cap-fieldset {
  margin-top: 1.5rem;
}
.system-cap-group {
  margin-bottom: 1.125rem;
}
.system-cap-group:last-child {
  margin-bottom: 0;
}
.system-cap-group--highlight {
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  padding: .75rem .875rem;
}
.system-cap-group-title {
  font-size: .8rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: .5rem;
}
.system-cap-grid {
  display: grid;
  grid-template-columns: minmax(9rem, auto) 1fr;
  gap: .375rem 1rem;
  align-items: center;
}
.system-cap-label {
  font-size: .8125rem;
  color: var(--text-secondary);
}
.system-cap-value {
  font-size: .8125rem;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  gap: .375rem;
  flex-wrap: wrap;
  min-width: 0;
}
.system-cap-detail {
  font-size: .75rem;
  color: var(--text-tertiary);
  word-break: break-word;
}
.system-cap-value code {
  font-size: .7rem;
  background: var(--bg-tertiary);
  padding: .05rem .3rem;
  border-radius: var(--radius-sm);
  word-break: break-all;
}

@media (max-width: 900px) {
  .system-cap-grid {
    grid-template-columns: 1fr;
    gap: .125rem 0;
  }
  .system-cap-label {
    font-weight: 600;
    margin-top: .375rem;
  }
}

/* ── System-Info / Backup / ENV-Konfiguration (Ticket 3.398.1) ────────────────
   Umgezogen aus dem component-scoped <style>-Block von pages/admin-tools.js
   (dort waren die Klassen zuvor identisch definiert, aber Light-DOM-global –
   s. base-component.js createRenderRoot()) nach hierher, weil beide Karten
   ("System-Info", "Backup") jetzt in pages/platform-admin-system.js leben.
   .card-full bleibt zusätzlich im <style>-Block von admin-tools.js bestehen
   (dort von >10 anderen Karten genutzt) – dieselbe Regel hier ist unschaedlich,
   da niemals beide Seiten gleichzeitig im DOM hängen (SPA-Routing). */
/* .system-info-body löst die vorher inline gesetzte 2-Spalten-Angabe im
   card-body der System-Info-Karte ab (Ticket 3.402) – lief mobil ohne
   Medienabfrage über den Rand. Basisregel VOR der Media-Query, sonst
   gewinnt bei gleicher Spezifität die Quellreihenfolge (frontend.md). */
.system-info-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}
@media (max-width: 900px) {
  .system-info-body { grid-template-columns: 1fr; }
}
.system-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .35rem 1rem;
  font-size: .85rem;
}
@media (max-width: 600px) {
  .system-grid { grid-template-columns: 1fr; }
}
.sys-label { color: var(--text-secondary); }
.sys-value { color: var(--text-primary); font-weight: 500; overflow-wrap: break-word; }
.env-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .3rem 0;
  font-size: .8rem;
  font-family: monospace;
}
.env-key  { flex: 1; min-width: 0; overflow-wrap: anywhere; color: var(--text-primary); }
.env-miss { background: var(--coral-light); border-radius: var(--radius-sm); padding: .5rem .75rem; margin-bottom: .25rem; }
.card-full { grid-column: 1 / -1; }

/* Mobile: In-Page-H1 redundant – App-Shell-Kopfleiste zeigt den Modulnamen bereits (P3 design-system.md).
   Ganze .page-header ausblenden statt nur h1: .page-header-actions ist auf Mobile ohnehin global
   versteckt (layout.css) – ohne diesen Fix bleibt eine leere .page-header-Box mit margin-bottom stehen
   (sichtbarer Leerraum über der Suche). */
@media (max-width: 900px) {
  page-deals .page-header,
  page-activities .page-header {
    display: none;
  }
}

/* ── AI Logo Picker ──────────────────────────────────────────── */
.ai-logo-section {
  margin-bottom: 1.125rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border);
}
.ai-logo-label {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin: 0 0 .5rem;
}
.ai-logo-hint {
  font-size: .75rem;
  font-weight: 400;
  color: var(--text-tertiary);
  margin-left: .375rem;
}
.ai-logo-picker {
  display: flex;
  gap: .5rem;
  overflow-x: auto;
  padding-bottom: .25rem;
  scrollbar-width: thin;
}
.ai-logo-option {
  flex-shrink: 0;
  width: 64px;
  height: 64px;
  border: 2px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  cursor: pointer;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: border-color var(--transition), box-shadow var(--transition);
  gap: .125rem;
}
.ai-logo-option img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.ai-logo-option:hover {
  border-color: var(--accent);
}
.ai-logo-option.is-selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}
.ai-logo-option--none {
  font-size: .625rem;
  color: var(--text-tertiary);
  border-style: dashed;
  text-align: center;
  line-height: 1.3;
}
.ai-logo-option--none svg {
  opacity: .4;
  margin-bottom: .125rem;
}
.ai-logo-option--none.is-selected {
  border-color: var(--coral);
  box-shadow: 0 0 0 3px var(--coral-light);
  color: var(--coral);
}
.ai-logo-option--none.is-selected svg {
  opacity: 1;
}

/* ── Admin-Tools: Cronjob-Übersicht ─────────────────────────────────────── */

/* Summary-Kacheln-Leiste */
.cron-summary-row {
  display: flex;
  gap: .625rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

/* Einzelne Kachel */
.cron-summary-pill {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .1875rem;
  min-width: 5.5rem;
  padding: .625rem .875rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.cron-summary-pill--teal  { background: var(--teal-light);  border-color: var(--teal);  }
.cron-summary-pill--coral { background: var(--coral-light); border-color: var(--coral); }
.cron-summary-pill--amber { background: var(--amber-light); border-color: var(--amber); }

.cron-summary-value {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.cron-summary-pill--teal  .cron-summary-value { color: var(--teal);  }
.cron-summary-pill--coral .cron-summary-value { color: var(--coral); }
.cron-summary-pill--amber .cron-summary-value { color: var(--amber); }

.cron-summary-label {
  font-size: .6875rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-tertiary);
}
.cron-summary-pill--teal  .cron-summary-label { color: var(--teal);  }
.cron-summary-pill--coral .cron-summary-label { color: var(--coral); }
.cron-summary-pill--amber .cron-summary-label { color: var(--amber); }

/* Hinweistext unter Summary */
.cron-hint-text {
  font-size: .8125rem;
  color: var(--text-tertiary);
  margin: 0 0 1rem;
  line-height: 1.5;
}

/* Job-Zeile hover */
.cron-job-row:hover td { background: var(--bg-secondary); }
.cron-job-row.is-expanded td { background: var(--accent-light); }

/* Job-Label + Schedule */
.cron-job-label {
  font-weight: 500;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  gap: .375rem;
}
.cron-job-schedule {
  font-size: .75rem;
  color: var(--text-tertiary);
  font-family: monospace;
  margin-top: .125rem;
}

/* Warnsymbol wenn Skript fehlt */
.cron-script-missing-icon {
  color: var(--amber);
  flex-shrink: 0;
}

/* Letzter-Lauf / Dauer-Zellen */
.cron-last-run,
.cron-duration {
  font-size: .8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
}

/* Chevron-Zelle */
.cron-chevron-cell {
  text-align: center;
  color: var(--text-tertiary);
}
.cron-chevron {
  transition: transform var(--transition);
  display: block;
}
.cron-chevron.is-open {
  transform: rotate(180deg);
}

/* History-Expand-Zeile */
.cron-history-row td {
  padding: 0 !important;
  border-top: none !important;
}
.cron-history-cell {
  padding: 0 1.25rem .75rem 1.25rem !important;
  background: var(--bg-secondary);
}

/* History-Eintrags-Liste */
.cron-history-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .5rem 0;
}
.cron-history-entry {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  overflow: hidden;
}
.cron-history-entry-header {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .5rem .75rem;
  flex-wrap: wrap;
}
.cron-history-ts {
  font-size: .8125rem;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  flex: 1;
  min-width: 8rem;
}
.cron-history-dur {
  font-size: .8125rem;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}
.cron-history-msg {
  margin: 0 !important;
  border-radius: 0 !important;
  font-size: .8rem !important;
  white-space: pre-wrap;
  word-break: break-word;
  border-top: 1px solid var(--border) !important;
}

/* Trigger-URL Zeile unter .cron-job-schedule */
.cron-url-row {
  display: flex;
  align-items: center;
  gap: .375rem;
  margin-top: .25rem;
  max-width: 100%;
}
.cron-url-input {
  flex: 1;
  min-width: 0;
  font-family: monospace;
  font-size: .6875rem;
  padding: .25rem .4rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
  cursor: text;
}
.cron-url-copy {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-tertiary);
  cursor: pointer;
  padding: 0;
  transition: color var(--transition), background var(--transition), border-color var(--transition);
}
.cron-url-copy:hover {
  color: var(--accent);
  background: var(--accent-light);
  border-color: var(--accent);
}
.cron-url-cli {
  font-size: .6875rem;
  color: var(--text-tertiary);
  font-style: italic;
  margin-top: .25rem;
  display: inline-block;
}

/* ── Admin-Tools: Mail-Log – ausklappbarer Fehler-/Empfänger-Bereich
   (Ticket 3.372.1). Reiht sich in dieselbe Ausklapp-Zeile ein wie die
   Cronjob-Historie (.cron-chevron-cell/.cron-chevron/.cron-job-row/
   .cron-history-row/-cell, .tool-result.fail + .cron-history-msg für den
   umbrechenden Fehlertext) – nur die zwei Detailzeilen-Klassen sind neu. */
.mail-log-detail {
  display: flex;
  flex-direction: column;
  gap: .625rem;
  padding: .625rem 0;
  /* Die umschließende <td colspan> ist so breit wie die gesamte (bei vielen
     Spalten scrollbare) Tabelle – ohne Deckel würde der Fehlertext erst bei
     dieser vollen Tabellenbreite umbrechen und auf schmalen Fenstern/Mobile
     größtenteils außerhalb des sichtbaren Bereichs liegen (nur mit
     Horizontal-Scroll lesbar). Deckel macht den Text unabhängig von der
     Tabellenbreite lesbar, ohne die restlichen Spalten anzufassen. */
  max-width: min(640px, calc(100vw - 4rem));
}
.mail-log-detail-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
}
.mail-log-detail-header span {
  font-size: .78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--text-secondary);
}
.mail-log-detail-line {
  font-size: .8125rem;
  color: var(--text-secondary);
  word-break: break-word;
}
.mail-log-detail-line strong {
  color: var(--text-primary);
  font-weight: 600;
  margin-right: .375rem;
}

/* ── Cronjobs: Ein/Aus + Intervall-Steuerung je Job (B37, C3,
   .claude/specs/20260721_cron_job_ui_control.md) ──────────────────────────
   Deaktivierte Jobs: nur die statische Info wird gedaempft (Textfarbe statt
   opacity – opacity auf dem <td> würde den darunterliegenden, weiterhin
   voll bedienbaren .cron-job-controls-Block mit dimmen, da opacity auf
   Nachfahren nicht per Kind-Regel "zurückgesetzt" werden kann). */
.cron-job-row--disabled .cron-job-label,
.cron-job-row--disabled .cron-job-schedule,
.cron-job-row--disabled .cron-url-cli,
.cron-job-row--disabled .cron-last-run,
.cron-job-row--disabled .cron-duration {
  color: var(--text-tertiary);
}

.cron-job-controls {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin-top: .625rem;
  padding-top: .625rem;
  border-top: 1px dashed var(--border);
}

.cron-toggle-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}
.cron-toggle-label {
  font-size: .78rem;
  color: var(--text-secondary);
}
.cron-badge {
  margin-left: .125rem;
}

.cron-interval-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}
/* .select/.input sind global width:100% + min-height:44px (Formular-Kontext) –
   hier kompakte, nebeneinander sitzende Steuerelemente nötig. */
.cron-job-controls .select,
.cron-job-controls .input {
  width: auto;
  min-height: 32px;
  padding-top: .3rem;
  padding-bottom: .3rem;
  font-size: .8125rem;
}
.cron-interval-select {
  min-width: 12rem;
}
.cron-time-input {
  width: 6.5rem;
}
.cron-weekday-select {
  width: 8.5rem;
}
.cron-custom-input {
  flex: 1;
  min-width: 11rem;
  font-family: monospace;
}

.cron-reco-line {
  margin: 0;
  font-size: .75rem;
  color: var(--text-tertiary);
  line-height: 1.5;
}

.cron-notify-warning {
  margin: 0;
}

/* Mobile: table scrolls in .table-wrap, summary pills wrap naturally */
@media (max-width: 600px) {
  .cron-summary-pill {
    min-width: 4.5rem;
    padding: .5rem .625rem;
  }
  .cron-summary-value { font-size: 1.25rem; }
}
@media (max-width: 900px) {
  /* Touch-Target-Konvention (analog .tt-ts-table): kompakte Desktop-Hoehe
     zurück auf 44px sobald Touch wahrscheinlich ist. */
  .cron-job-controls .select,
  .cron-job-controls .input {
    min-height: 44px;
  }
}

/* ── Mail: Mobile-Detail Sticky-Action-Bar ─────────────────────────────────── */
/* Rendert nur in _renderMobileDetail() – kein @media-Guard nötig da die
   Methode nur auf Mobile aufgerufen wird. flex-shrink:0 als letztes Kind des
   height:100%-Flex-Roots → pinnt automatisch unten. */
.mail-detail-bottombar {
  flex-shrink: 0;
  display: flex;
  align-items: stretch;
  gap: .25rem;
  border-top: 1px solid var(--border);
  background: var(--bg-primary);
  padding: .375rem .5rem;
  padding-bottom: calc(.375rem + env(safe-area-inset-bottom, 0px));
}
.mail-detail-bottombar-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .125rem;
  min-height: 48px;
  border: none;
  background: transparent;
  color: var(--text-secondary);
  font-size: .6875rem;
  cursor: pointer;
  border-radius: var(--radius-md);
  transition: background var(--transition), color var(--transition);
  white-space: nowrap;
}
.mail-detail-bottombar-item:hover,
.mail-detail-bottombar-item:active {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.mail-detail-bottombar-item svg {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}
.mail-detail-bottombar-item--danger {
  color: var(--coral);
}
.mail-detail-bottombar-item--danger:hover,
.mail-detail-bottombar-item--danger:active {
  background: var(--coral-light);
  color: var(--coral);
}
.mail-detail-bottombar-more {
  flex-shrink: 0;
  width: 48px;
  min-height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  border-radius: var(--radius-md);
  transition: background var(--transition), color var(--transition);
}
.mail-detail-bottombar-more:hover,
.mail-detail-bottombar-more:active {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.mail-detail-bottombar-more svg {
  width: 20px;
  height: 20px;
}

/* ── Mail: Attachment-Preview-Overlay ─────────────────────────────────────
   Fixed-Overlay für Anhang-Vorschau (PDF iframe, Bild, ICS/RSVP, Fallback).
   z-index 1090 – über Bottom-Bar (z:100), UNTER dem geteilten ContextMenu
   (core/ds-context-menu.js: .ds-context-menu-backdrop 1099 / .ds-context-menu
   1100, _calendar.css). Vor D4 (In-Mediathek-hinzufügen-Zielwahl, Spec
   20260730_receipt_inbox_media_library.md) stand hier fälschlich 1200 – der
   Kommentar sprach von „unter Context-Menu (z:2100)", das reale ContextMenu
   war aber nie höher als 1100 (Doku-Drift, nie geprüft, weil bis D4 nie ein
   ContextMenu AUS diesem Overlay heraus geöffnet wurde). Bei 1200 hätte das
   D4-Zielwahl-Menü hinter dem eigenen Backdrop gerendert und wäre unsichtbar/
   unklickbar gewesen. 1090 bleibt weiterhin über Modal (z:1000).
   PDF-Render: Desktop → <iframe class="mail-att-preview-frame"> (CSP: frame-src blob:).
               Mobile → .mail-att-preview-other-Karte mit „PDF öffnen"-Button
               (window.open blob, nativ) – iOS/Android rendern PDFs in iframe nicht.
   Erweiterungspunkt: .mail-att-preview-footer für künftige Aktionen (z.B.
   „Bei Kontakt als Dokument speichern") – weitere .btn dort einfach ergänzen.
   ─────────────────────────────────────────────────────────────────────── */

.mail-att-preview-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: 1090;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}

.mail-att-preview-panel {
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  max-width: 900px;
  width: 100%;
  height: 90vh;
  overflow: hidden;
}

.mail-att-preview-header {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .75rem 1rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.mail-att-preview-title {
  flex: 1;
  font-weight: 600;
  font-size: .9375rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-primary);
}

.mail-att-preview-close {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

.mail-att-preview-body {
  flex: 1;
  overflow: auto;
  display: flex;
  flex-direction: column;
  position: relative;
}

.mail-att-preview-frame {
  width: 100%;
  flex: 1;
  border: none;
  background: #fff;
  min-height: 400px;
}

.mail-att-preview-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  margin: auto;
  display: block;
  padding: 1rem;
}

.mail-att-preview-ics-wrap {
  flex: 1;
  overflow-y: auto;
  padding: 1rem;
}

.mail-att-preview-other {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: 2rem 1rem;
  text-align: center;
  color: var(--text-primary);
}

.mail-att-preview-loading {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
}

@keyframes mail-att-spin {
  to { transform: rotate(360deg); }
}

.mail-att-preview-spinner {
  animation: mail-att-spin 1s linear infinite;
  color: var(--accent);
  opacity: .7;
}

.mail-att-preview-footer {
  display: flex;
  gap: .5rem;
  align-items: center;
  padding: .75rem 1rem;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
  justify-content: flex-end;
  padding-bottom: calc(.75rem + env(safe-area-inset-bottom, 0px));
}

/* „In Mediathek hinzufügen" (D4) – sekundärer .btn-ghost links vom primären
   Download-Button. Öffnet per Klick die Zielwahl (ContextMenu). */
.mail-att-preview-media-btn {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  white-space: nowrap;
}

/* „In neuem Tab öffnen" (Ticket 3.406.2) – sekundärer .btn-ghost in der
   Footer-Reihe, vor dem primären Download-Button. Erscheint nur, wenn ein
   PDF bereits geladen ist (Desktop – Mobile hat einen eigenen Knopf in der
   Karte, s. .mail-att-preview-other). */
.mail-att-preview-open-btn {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  white-space: nowrap;
}

/* Mobile: full-screen panel, full-width buttons */
@media (max-width: 900px) {
  .mail-att-preview-backdrop {
    padding: 0;
    align-items: flex-end;
  }

  .mail-att-preview-panel {
    max-width: none;
    width: 100%;
    height: 100%;
    border-radius: 0;
    border: none;
  }

  .mail-att-preview-footer {
    flex-direction: column;
  }

  .mail-att-preview-footer .btn {
    width: 100%;
    justify-content: center;
  }
}

/* ── Mail: Kontakt-Anlegen-Panel In-Place (Feature B, 2026-07-07) ──────── */
/* Nutzt dieselbe Backdrop/Header/Footer-Optik wie .mail-att-preview-*     */
/* (gemounted via dieselbe .mail-att-preview-backdrop-Klasse in render()); */
/* nur der eigentliche Panel-Container + Body-Scroll sind eigenstaendig,   */
/* weil das Anlege-Formular andere Massen als die Anhang-Vorschau braucht. */
.mail-cc-panel {
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  max-width: 520px;
  width: 100%;
  max-height: 90vh;
  overflow: hidden;
}

.mail-cc-panel-body {
  flex: 1;
  overflow-y: auto;
  padding: 1rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: .875rem;
}

@media (max-width: 900px) {
  .mail-cc-panel {
    max-width: none;
    width: 100%;
    height: 100%;
    max-height: none;
    border-radius: 0;
    border: none;
  }
}

/* ── Mail: Aufgabe-Anlegen-Panel In-Place (Ticket 3.212.2) ────────────── */
/* Teilt sich .mail-cc-panel/-body (s.o.) – eigene Klassen nur für die    */
/* Hinweis-Box (Duplikat-Erkennung + Kürzungs-Hinweis) + deren Link-Liste. */
.mail-task-panel-hint {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.375rem;
  padding: 0.625rem 0.875rem;
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: 0.8125rem;
}

.mail-task-panel-hint--warn {
  background: var(--amber-light);
  color: var(--amber);
}

.mail-task-panel-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  width: 100%;
}

.mail-task-panel-link-btn {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  text-decoration: underline;
  font-size: 0.8125rem;
  cursor: pointer;
  text-align: left;
}

.mail-task-panel-link-btn:hover,
.mail-task-panel-link-btn:focus-visible {
  color: var(--accent-dark);
}

/* ── Mail: Split-Button-Familie (Filter + Refresh) ───────────── */
/* Ghost-Variante – btn-ghost-Optik, geteilte Radius-Logik,      */
/* dezenter var(--border)-Trenner zwischen Main und Chevron.      */
.mail-split-btn {
  display: inline-flex;
  align-items: stretch;
  flex-shrink: 0;
}

.mail-split-btn-main {
  border-top-right-radius: 0 !important;
  border-bottom-right-radius: 0 !important;
  border-right: none !important;
  min-height: 32px;
  padding: 0.25rem 0.5rem;
}

.mail-split-btn-chevron {
  border-top-left-radius: 0 !important;
  border-bottom-left-radius: 0 !important;
  border-left: 1px solid var(--border) !important;
  padding: 0 0.375rem;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Active-State: Filter ist aktiv → accent-Farbe + accent-light-Füllung auf Main */
.mail-split-btn-main.is-active {
  color: var(--accent);
  background: var(--accent-light);
}
.mail-split-btn-main.is-active:hover {
  background: var(--accent-light);
  color: var(--accent-dark);
}

/* Dark-Mode: automatisch via CSS-Variablen */

/* ── Generischer Split-Button (Primär-Variante) ──────────────────────────── */
/* Wiederverwendbar für jeden Modul-Kontext wo ein Primär-Button mit Chevron  */
/* zu einem kompakten Control verschmolzen wird. Vorbild: .todo-newmenu-wrap. */
/* Dokumentation: design-system.md → Abschnitt „Generischer Split-Button".   */
.ds-split-btn {
  position: relative;
  display: inline-flex;
}

.ds-split-btn-main {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.ds-split-btn-chev {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  border-left: 1px solid color-mix(in srgb, var(--accent-dark) 40%, transparent);
  padding: 0 .55rem;
  min-width: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

@media (max-width: 900px) {
  .ds-split-btn-chev {
    min-width: 44px;
    min-height: 44px;
  }
  .ds-split-btn-main {
    min-height: 44px;
  }
}

/* ── Admin-Tools: Fehler-Log ────────────────────────────────────────────── */

.admin-log-pre {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  line-height: 1.5;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .75rem;
  max-height: 60vh;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0;
}

.admin-log-line {
  padding: .05rem 0;
}

.admin-log-line.is-error {
  color: var(--coral);
}

.admin-log-line.is-warn {
  color: var(--amber);
}

/* ── Geteilter Farb-Picker (ds-color-picker.js) ─────────────────────────────
   Wrapper für Dropdown-Inhalt. Swatches + Raster nutzen .cal-color-swatch /
   .cal-color-picker-grid aus _calendar.css (bereits global verfügbar).
   Neue Klassen nur für Wrapper + Custom-Farbe-Trigger.                       */

.ds-color-picker-wrap {
  padding: .25rem 0;
}

/* Optionaler Trenner zwischen Preset- und Custom-Farben-Reihe */
.ds-color-picker-divider {
  height: 1px;
  background: var(--border);
  margin: .375rem .5rem;
}

/* "Keine Farbe"-Eintrag (Ticket 3.310, opt-in via opts.clearLabel) – volle Zeilenbreite,
   analog .ds-dropdown-item (_calendar.css), damit er sich optisch klar von den Swatch-Kacheln
   absetzt (echte Aktion "Format entfernen", kein Farbwert). */
.ds-color-picker-clear-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  padding: .4rem .5rem;
  margin-bottom: .25rem;
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: .8125rem;
  text-align: left;
  cursor: pointer;
  transition: background var(--transition);
}
.ds-color-picker-clear-item:hover { background: var(--bg-secondary); }
.ds-color-picker-clear-item.is-active { font-weight: 600; color: var(--accent); }
.ds-color-picker-clear-label { flex: 1; }
/* Kreis mit diagonaler Linie – universelles "kein Wert"-Icon, dark-mode-sicher via
   CSS-Variablen (kein hartkodiertes Rot/Rosa – das ist keine destruktive Aktion). */
.ds-color-picker-clear-swatch {
  position: relative;
  display: inline-block;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
}
.ds-color-picker-clear-swatch::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: linear-gradient(
    to top right,
    transparent calc(50% - 1px),
    var(--text-tertiary) calc(50% - 1px),
    var(--text-tertiary) calc(50% + 1px),
    transparent calc(50% + 1px)
  );
}

/* Custom-Swatch-Zelle (Swatch + Löschen-X) */
.ds-color-picker-custom-cell {
  position: relative;
  display: inline-flex;
}

/* Löschen-X auf Custom-Swatch (oben rechts) */
.ds-color-picker-del {
  position: absolute;
  top: -5px;
  right: -5px;
  width: 16px;
  height: 16px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-size: 12px;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--bg-primary);
  color: var(--text-tertiary);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--transition), color var(--transition), background var(--transition);
}
.ds-color-picker-custom-cell:hover .ds-color-picker-del {
  opacity: 1;
}
.ds-color-picker-del:hover {
  background: var(--coral-light);
  color: var(--coral);
  border-color: var(--coral);
}

/* „Eigene Farbe"-Zeile: Farb-Input + Label + Anwenden */
.ds-color-picker-custom-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem .5rem .25rem;
}

/* Nativer Farb-Input – sichtbarer Swatch */
.ds-color-picker-native-input {
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: none;
  cursor: pointer;
  flex-shrink: 0;
}
.ds-color-picker-native-input::-webkit-color-swatch-wrapper { padding: 2px; }
.ds-color-picker-native-input::-webkit-color-swatch { border: none; border-radius: 3px; }
.ds-color-picker-native-input::-moz-color-swatch { border: none; border-radius: 3px; }

.ds-color-picker-custom-label {
  flex: 1;
  font-size: .8125rem;
  color: var(--text-secondary);
}

.ds-color-picker-apply {
  flex-shrink: 0;
}

@media (max-width: 900px) {
  .ds-color-picker-del {
    opacity: 1; /* Touch: kein Hover – X immer sichtbar */
    width: 18px;
    height: 18px;
  }
}

/* ── Mobile Off-Canvas Drawer (.ds-drawer) ──────────────────────────────────
   Modul-agnostisches Drawer-Pattern – nur auf Mobile (≤900px) aktiv.
   Desktop blendet Backdrop, Drawer und Toggle hart aus (display:none !important).
   Nutzende Seiten: page-todos (Projekte), page-notes (Notizbücher/Workspaces).
   BackStack-Integration: push(closeFn) bei Öffnen, close(token) bei Schließen.
   ──────────────────────────────────────────────────────────────────────────── */
.ds-drawer-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .45);
  z-index: 1190;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease;
}
.ds-drawer-backdrop.is-open {
  opacity: 1;
  pointer-events: auto;
}

.ds-drawer {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 86vw;
  max-width: 320px;
  background: var(--bg-primary);
  border-right: 1px solid var(--border);
  z-index: 1200;
  transform: translateX(-100%);
  transition: transform .25s ease;
  overflow-y: auto;
  box-shadow: var(--shadow-lg);
  padding-bottom: env(safe-area-inset-bottom);
}
.ds-drawer.is-open {
  /* transform:none statt translateX(0) – jeder Wert ausser "none" macht das
     Element zum Containing Block für position:fixed-Nachfahren (z.B. das
     Zeit-Popover der Aufgaben-Detail-Sidebar, .sb-popover--anchored). Mit
     translateX(0) landete das Popover relativ zur 320px-Schublade statt zum
     Viewport – außerhalb, vom overflow-y:auto abgeschnitten, unsichtbar
     (Ticket 3.88). "none" interpoliert während der Transition weiterhin als
     Identitaets-Matrix, die Einblend-Animation bleibt dadurch unverändert. */
  transform: none;
}

.ds-drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .75rem 1rem;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  background: var(--bg-primary);
  z-index: 1;
}

.ds-drawer-title {
  font-weight: 600;
  font-size: .95rem;
  color: var(--text-primary);
}

.ds-drawer-close {
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  color: var(--text-secondary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}
.ds-drawer-close:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}

.ds-drawer-toggle {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  /* Sichtbarkeit/Position steuert die jeweilige Seite; nur auf Mobile zeigen */
}

/* Desktop: Drawer, Backdrop und Toggle komplett ausblenden */
@media (min-width: 901px) {
  .ds-drawer,
  .ds-drawer-backdrop,
  .ds-drawer-toggle {
    display: none !important;
  }
}

/* Rechts einfahrende Variante (Spec 20260730_todo_detail_mobile_sidebar) --
   für Metadaten-Nebenflächen, deren Desktop-Pendant rechts sitzt (z.B. die
   Todo-Detail-Sidebar). Ein Modifier auf der geteilten Familie statt einer
   zweiten Drawer-Definition (P-5) – Breite/z-index/Header/Backdrop/Desktop-
   Ausblendung bleiben identisch zur Links-Variante, nur Seite + Randlinie
   drehen um. .ds-drawer.is-open (0,2,0 Spezifität) gewinnt weiterhin gegen
   die hier gesetzte Ruhe-Transform (0,1,0) – kein eigener .is-open-Override
   nötig, translateX(0) ist für beide Richtungen im offenen Zustand gleich.
   Nutzende Seite: page-todos (Todo-Detail-Metadaten, _renderDetailSidebarDrawer). */
.ds-drawer--right {
  left: auto;
  right: 0;
  border-right: none;
  border-left: 1px solid var(--border);
  transform: translateX(100%);
}

/* ── Mobile Sub-Nav-Leiste (.ds-mobile-navbar) ──────────────────────────────
   Gemeinsame Zeilen-Struktur für Module mit Off-Canvas-Drawer-Navigation:
   Drawer-Toggle links + dezentes, nicht-interaktives Kontext-Label rechts
   (aktuelle Ansicht/Projekt/Workspace, optional mit Farbpunkt). Extrahiert aus
   zwei divergierenden Modul-Spiegeln (page-todos.js `.todos-mobile-navbar` +
   pages/notes.js `.notes-ws-drawer-row`, P-5) – beide nutzen jetzt dieselbe
   Klassen-Familie statt eigener, leicht abweichender CSS-Blöcke.
   Nutzende Seiten: page-todos (Projekte), page-notes (Notizbücher).
   ──────────────────────────────────────────────────────────────────────────── */
.ds-mobile-navbar {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem 0 .5rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: .5rem;
}
.ds-mobile-navbar .ds-drawer-toggle {
  flex-shrink: 0;
  padding: .25rem .5rem;
  gap: .25rem;
}
.ds-mobile-navbar-context {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .3rem;
  flex: 1;
  min-width: 0;
  /* Abstand zum rechten Rahmen – page-todos hat auf Mobile 0 Ambient-Padding
     (nav.css .ds-content-body:has(page-todos)), ohne dieses Padding klebt das
     Kontext-Label (z.B. "Heute") direkt am Bildschirmrand. */
  padding-right: .5rem;
  color: var(--text-secondary);
  font-size: .8125rem;
  font-weight: 600;
}
.ds-mobile-navbar-context-name {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  min-width: 0;
}
.ds-mobile-navbar-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
/* Ticket 3.253 – optionale Bedienelemente-Gruppe zwischen Drawer-Toggle und
   Kontext-Label (aktuell nur von page-todos genutzt: Einstellungen/Suche/
   Aktualisieren, s. ds-todo-list-view.js::renderMobileNavExtras()). Steht
   VOR .ds-mobile-navbar-context im Markup, damit dessen bestehende
   padding-right:.5rem (Abstand zum Bildschirmrand, s.o.) unverändert
   greift und Notizen (die diese Gruppe nicht nutzt) unberührt bleiben –
   kein Eingriff in .ds-mobile-navbar-context selbst (P-5, keine Regression
   für den Bestandsnutzer pages/notes.js).
   Größe bewusst 32px (nicht die generischen 44px von .btn-icon): die
   Leistenhoehe wird durch den Drawer-Toggle (.btn-sm, min-height:32px)
   bestimmt – ein 44px-Icon würde die Leiste hoeher machen als vorher
   (🔒 Pflichtauflage "Leiste darf nicht hoeher werden"). 32px matched
   exakt die Content-Hoehe des Drawer-Toggles, daher keine Änderung der
   Zeilenhoehe trotz zusätzlicher Icons.
   Ticket 3.253.2 – der Ansichten-Wechsler ("Ansicht wählen") ist NICHT
   mehr Teil dieser Gruppe: er sitzt seither als eigenstaendiges
   .ds-mobile-navbar-icon INNERHALB von .ds-mobile-navbar-context (erstes
   Kind, VOR Farbpunkt/Name – s. ds-todo-list-view.js::
   renderMobileViewSwitcher() + page-todos.js::_renderMobileNavBar()),
   analog zur Desktop-Anordnung (Einstellungen beim Titel, Ansicht rechts).
   Kein zusätzliches CSS nötig: .ds-mobile-navbar-icon trägt bereits
   flex-shrink:0 (s.u.), .ds-mobile-navbar-context ist bereits
   flex;justify-content:flex-end – der Button reiht sich damit rechtsbündig
   VOR Punkt+Name ein, ohne den Namen zu verdraengen (dessen Ellipsis bleibt
   unverändert, s. .ds-mobile-navbar-context-name). */
.ds-mobile-navbar-icons {
  display: flex;
  align-items: center;
  gap: .25rem;
  flex-shrink: 0;
}
.ds-mobile-navbar-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.ds-mobile-navbar-icon:hover,
.ds-mobile-navbar-icon:focus-visible {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}
.ds-mobile-navbar-icon:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Aktiver Zustand – aktuell nur vom Lupen-Icon genutzt (Suche aufgeklappt),
   s. renderMobileNavExtras(). */
.ds-mobile-navbar-icon.is-active {
  background: var(--accent-light);
  border-color: transparent;
  color: var(--accent-dark);
}
.ds-mobile-navbar-icon svg { display: block; }

/* ── QR-Codes Modul ──────────────────────────────────────────────────────────
   Klassen-Familie: .qr-*
   Genutzt in: pages/qr-codes.js (page-qr-codes)
   Eingetragen in design-system.md → Abschnitt „QR-Codes Modul"
   ─────────────────────────────────────────────────────────────────────────── */

/* Tabellen-Hilfselemente */
.qr-table-name {
  font-weight: 600;
}
.qr-table-lock {
  display: inline-flex;
  align-items: center;
  margin-left: .375rem;
  color: var(--text-tertiary);
  vertical-align: middle;
}

/* QR-Vorschau-Block im Slide-In-Panel */
.qr-preview-wrap {
  display: flex;
  justify-content: center;
  margin-bottom: 1.25rem;
}
.qr-preview-img {
  width: 160px;
  height: 160px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  object-fit: contain;
  background: #fff; /* QR immer auf weißem Grund sichtbar – auch im Dark Mode */
}
.qr-preview-placeholder {
  width: 160px;
  height: 160px;
  border-radius: var(--radius-md);
  border: 1px dashed var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  background: var(--bg-secondary);
}

/* Download-Button-Zeile */
.qr-download-bar {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
  justify-content: center;
  margin-bottom: 1.25rem;
}

/* „Ziel-URL öffnen"-Button unter der Download-Leiste (nur veröffentlicht, kein Scan-Tracking) */
.qr-target-link-row {
  display: flex;
  justify-content: center;
  margin-bottom: 1.25rem;
}

/* Panel-Wrapper – konsistenter vertikaler Rhythm */
.qr-panel-wrap {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding-bottom: 1.5rem;
}
.qr-panel-wrap .form-group {
  margin-bottom: .875rem;
}

/* Haupt-Aktionen */
.qr-panel-actions {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin-top: .5rem;
}
.qr-panel-actions .btn {
  width: 100%;
}

/* Veröffentlichen-Toggle-Zeile über Speichern-Button */
.qr-publish-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .625rem .75rem;
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
}
.qr-publish-toggle-label {
  font-size: .875rem;
  font-weight: 600;
  color: var(--text-primary);
}
/* Dezenter Hinweis-Text unter dem Toggle wenn gesperrt */
.qr-publish-locked-hint {
  font-size: .75rem;
  color: var(--text-tertiary);
  margin: 0;
  padding: .25rem .125rem 0;
}

/* Logo-Quellen-Auswahl (Segmented-Buttons) */
.qr-logo-source-strip {
  display: flex;
  gap: .25rem;
  flex-wrap: wrap;
  margin-bottom: .125rem;
}
.qr-logo-source-btn {
  flex: 1;
  min-width: 0;
  padding: .375rem .625rem;
  font-size: .78125rem;
  font-weight: 500;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
  text-align: center;
  white-space: nowrap;
}
.qr-logo-source-btn:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}
.qr-logo-source-btn.active {
  background: var(--accent-light);
  color: var(--accent-dark);
  border-color: var(--accent);
  font-weight: 600;
}

/* Status-Aktionen (Veröffentlichen / Archivieren / Löschen) */
.qr-status-actions {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}

/* Farb-Picker (native color input + Text-Input nebeneinander) */
.qr-color-input {
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  background: none;
  flex-shrink: 0;
}

/* Statistik-Seite – Scan-Zähler */
.qr-stats-total {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .25rem;
  margin-bottom: 1.5rem;
}
.qr-stats-count {
  font-size: 2.5rem;
  font-weight: 800;
  font-family: var(--font-display);
  letter-spacing: -0.03em;
  color: var(--text-primary);
  line-height: 1;
}
.qr-stats-label {
  font-size: .8125rem;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .06em;
}

/* CSS-Balkendiagramm (keine externe Chart-Lib) */
.qr-chart-wrap {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 1rem 1rem .5rem;
  background: var(--bg-secondary);
}
.qr-chart-bars {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 80px;
}
.qr-chart-bar-wrap {
  flex: 1;
  display: flex;
  align-items: flex-end;
  height: 100%;
}
.qr-chart-bar {
  width: 100%;
  border-radius: 2px 2px 0 0;
  background: var(--accent);
  min-height: 2px;
  transition: background var(--transition);
}
.qr-chart-bar-wrap:hover .qr-chart-bar {
  background: var(--accent-dark);
}
.qr-chart-dates {
  display: flex;
  justify-content: space-between;
  margin-top: .375rem;
}

/* ── Bulk-Selection (CSV-Export + Bulk-Actions) ──────────────────────────── */

/* Checkbox-Spalte in Desktop-Tabelle */
.table .bulk-check-col {
  width: 36px;
  padding: 0 0 0 0.75rem !important;
  text-align: center;
  vertical-align: middle;
}
.table .bulk-check-col input[type="checkbox"] {
  width: 16px;
  height: 16px;
  cursor: pointer;
  accent-color: var(--accent);
  border-radius: 3px;
}

/* Sticky Bulk-Action-Bar (erscheint nur wenn Einträge ausgewählt) */
.bulk-action-bar {
  position: sticky;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 1rem);
  z-index: 120;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 0.625rem 0.875rem;
  box-shadow: var(--shadow-lg);
  margin-top: 0.75rem;
  animation: bulk-bar-in 0.15s ease-out;
}
@keyframes bulk-bar-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0);   }
}
.bulk-action-bar-count {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  margin-right: 0.25rem;
}
.bulk-action-bar-sep {
  width: 1px;
  height: 1.25rem;
  background: var(--border);
  flex-shrink: 0;
}
.bulk-action-bar-spacer {
  flex: 1;
}
.bulk-action-bar .btn {
  white-space: nowrap;
  min-height: 36px;
}
.bulk-action-bar .bulk-tag-input {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.3125rem 0.625rem;
  font-size: 0.875rem;
  background: var(--bg-secondary);
  color: var(--text-primary);
  outline: none;
  width: 140px;
  min-height: 36px;
  transition: border-color var(--transition);
}
.bulk-action-bar .bulk-tag-input:focus {
  border-color: var(--accent);
}
.bulk-action-bar .bulk-status-select {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.3125rem 0.625rem;
  font-size: 0.875rem;
  background: var(--bg-secondary);
  color: var(--text-primary);
  outline: none;
  min-height: 36px;
  cursor: pointer;
  transition: border-color var(--transition);
}
.bulk-action-bar .bulk-status-select:focus {
  border-color: var(--accent);
}

/* ── Duplikate-Panel (.dup-group, .dup-member, …) ─────────────────── */
/* Kontakte > „Duplikate finden" → Slide-In-Panel mit Gruppen-Karten  */

.dup-group {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.dup-group-header {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.75rem 1rem;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}

.dup-group-match-value {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  font-weight: 500;
  word-break: break-all;
}

.dup-group-members {
  display: flex;
  flex-direction: column;
}

/* Mitglieder-Zeile – wählbare label-Zeile */
.dup-member {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background var(--transition);
  position: relative;
}
.dup-member:last-child {
  border-bottom: none;
}
.dup-member:hover {
  background: var(--bg-secondary);
}
.dup-member--survivor {
  background: var(--accent-light);
}
.dup-member--survivor:hover {
  background: color-mix(in srgb, var(--accent-light) 80%, var(--bg-secondary));
}

.dup-member-pick {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
}
.dup-member-pick input[type="radio"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}

.dup-member-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.dup-member-name {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dup-member-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem 0.75rem;
  font-size: 0.8rem;
  color: var(--text-secondary);
}
.dup-member-meta span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 18rem;
}

/* Survivor-Badge rechts */
.dup-survivor-badge {
  flex-shrink: 0;
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--accent);
  background: var(--accent-light);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius: var(--radius-pill);
  padding: 0.1875rem 0.5625rem;
  white-space: nowrap;
}

.dup-group-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 0.625rem 1rem;
  border-top: 1px solid var(--border);
  background: var(--bg-secondary);
}

/* Badge-Modifier für match_type (light/dark via Variablen) */
.badge-accent {
  background: var(--accent-light);
  color: var(--accent-dark);
}
/* .badge-teal – kanonische Definition weiter oben (Zeile 266), Dupe hier entfernt */
.badge-amber {
  background: var(--amber-light);
  color: var(--amber);
}

/* Touch-Target Mindestgröße für Member-Zeilen (Mobile) */
@media (max-width: 900px) {
  .dup-member {
    min-height: 56px;
  }
  .dup-member-name {
    font-size: 0.875rem;
  }
}

/* ── Recency-Badge (P3 Last-Touch – Kontakte + Firmen) ─────────────────────────
   Dezentes Inline-Badge in Listen-Tabellen + Mobile-Rows zur Visualisierung
   des letzten Kontaktzeitpunkts. Modifier steuern die Farbsemantik:
   --fresh ≤30d = teal, --warm 30–90d = amber, --cold >90d / nie = coral.
   Kein Fehler-Farbtoken (–danger) – coral ist hier dekorativ (Aufmerksamkeit,
   keine Destruktivität). */
.recency-badge {
  display: inline-flex;
  align-items: center;
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
  padding: 0.1875rem 0.5rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  /* Default (fallback): neutral */
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.recency-badge--fresh {
  background: var(--teal-light);
  color: var(--teal);
}
.recency-badge--warm {
  background: var(--amber-light);
  color: var(--amber);
}
.recency-badge--cold {
  background: var(--coral-light);
  color: var(--coral);
}
/* --compact: reduzierte Schrift für Mobile native-row-right */
.recency-badge--compact {
  font-size: 0.6875rem;
  padding: 0.125rem 0.375rem;
}

/* ── Nächster-Schritt-Badge (Wiedervorlage in Kontakte-Liste + Detail) ─────────
   Kompaktes Inline-Badge das Fälligkeit einer offenen Wiedervorlage signalisiert.
   Modifier steuern Farbsemantik: --overdue = Danger (überfällig), --today = Amber
   (heute fällig), ohne Modifier = Teal (zukünftig). Nur CSS-Variablen, kein
   hardcodierter Hex/RGB-Wert. Light + Dark via Variablen automatisch. */
.next-step-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1;
  padding: 0.1875rem 0.4375rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  /* Default: zukünftig fällig – teal */
  background: var(--teal-light);
  color: var(--teal);
}
.next-step-badge svg {
  flex-shrink: 0;
}
.next-step-badge--overdue {
  background: var(--danger-light);
  color: var(--danger);
}
.next-step-badge--today {
  background: var(--amber-light);
  color: var(--amber);
}

/* ── Cold-Filter-Leiste (Kontakte + Firmen Listenseite) ────────────────────────
   Inline-Wrapper für das „Zuletzt kontaktiert"-Select neben der Aktiv/Inaktiv-
   Tab-Leiste. Label + Select horizontal kompakt angeordnet. */
.cold-filter-wrap {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}
.cold-filter-label {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
}
/* Kompaktes Select-Element neben Tab-Filter */
.select.select--compact {
  min-height: 36px;
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
  font-size: 0.8125rem;
}

/* ── Tag-Filter-Combobox (Kontakte/Firmen-Filterleiste) ──────────────
   Durchsuchbares Input + Datalist. `.contact-tag-filter-wrap` reused in companies.js. */
.contact-tag-filter-wrap {
  position: relative;
  display: flex;
  align-items: center;
  flex-shrink: 0;
}
.contact-tag-filter-input {
  min-width: 8rem;
  max-width: 13rem;
  padding-right: 1.625rem; /* Platz für ×-Button */
}
.contact-tag-filter-clear {
  position: absolute;
  right: 0.375rem;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--text-tertiary);
  border-radius: var(--radius-sm);
  padding: 0;
  transition: color var(--transition-fast), background var(--transition-fast);
}
.contact-tag-filter-clear:hover {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}

/* ── Consent-Box (DSGVO-Einwilligungsindikator im Kontakt-Detail) ──────────────
   Zeigt den Marketing-Einwilligungsstatus deutlich und zugänglich.
   --withdrawn = coral (Achtung, nicht destruktiv – kein --danger nötig, da kein
   Lösch- oder Fehler-Kontext). --given = teal. Analog .ds-info-box in der API. */
.ds-consent-box {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  padding: 0.625rem 0.875rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  font-size: 0.8125rem;
  color: var(--text-secondary);
  margin: 0.25rem 0;
}
.ds-consent-box svg {
  flex-shrink: 0;
  margin-top: 0.0625rem;
}
.ds-consent-box--withdrawn {
  background: var(--coral-light);
  border-color: color-mix(in srgb, var(--coral) 25%, transparent);
  color: var(--coral);
}
.ds-consent-box--given {
  background: var(--teal-light);
  border-color: color-mix(in srgb, var(--teal) 25%, transparent);
  color: var(--teal);
}
.ds-consent-box-title {
  font-weight: 600;
  line-height: 1.3;
}
.ds-consent-box-meta {
  font-size: 0.75rem;
  margin-top: 0.125rem;
  opacity: 0.85;
}

/* ── Account-Tier-Badge (P6 Kundenwert A/B/C/D) ────────────────────────────
   Kleines Inline-Pill-Badge das den effektiven Account-Tier eines Kontakts /
   einer Firma visualisiert. Vier Modifier für A–D; absteigend in Sättigung.
   --a = kräftig (accent-Blau), --b = amber-warm, --c = neutral-grau,
   --d = helles Tertiary (dezent). Kein Badge wenn kein Tier gesetzt.
   Licht + Dark vollständig via CSS-Variablen – kein Hex/RGB hartkodiert.   */
.account-tier-badge {
  display: inline-flex;
  align-items: center;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  padding: 0.125rem 0.4375rem;
  border-radius: var(--radius-pill);
  letter-spacing: 0.04em;
  white-space: nowrap;
  /* Default (sollte nie sichtbar sein – immer Modifier setzen) */
  background: var(--bg-tertiary);
  color: var(--text-tertiary);
  flex-shrink: 0;
}
.account-tier-badge--a {
  background: var(--accent-light);
  color: var(--accent-dark);
}
.account-tier-badge--b {
  background: var(--amber-light);
  color: var(--amber);
}
.account-tier-badge--c {
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.account-tier-badge--d {
  background: var(--bg-secondary);
  color: var(--text-tertiary);
  border: 1px solid var(--border);
}
/* Geerbt-Hinweis im Detail: dezente Kursiv-Note neben dem Badge */
.account-tier-inherited {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  font-style: italic;
}

/* ── Kadenz-Ampel (P6 Kundenpflege-Status) ─────────────────────────────────
   Farbiger Punkt / Pill zeigt den Fälligkeits-Status der nächsten Kontaktaufnahme.
   .cadence-ampel ist ein kompakter Inline-Punkt (8×8 px rund), Modifier --green
   (teal), --amber, --red (coral dekorativ – kein Fehler-Kontext). --none zeigt
   neutralen Punkt. Pill-Variante .cadence-ampel-pill für Hover-Tooltip in Listen.
   Keine hardcodierten Farben – ausschließlich CSS-Variablen.                   */
.cadence-ampel {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--bg-tertiary);
}
.cadence-ampel--green  { background: var(--teal); }
.cadence-ampel--amber  { background: var(--amber); }
.cadence-ampel--red    { background: var(--coral); }
.cadence-ampel--none   { background: var(--bg-tertiary); border: 1px solid var(--border); }

/* Wrapper: Punkt + optionales Tooltip-Label horizontal nebeneinander */
.cadence-ampel-wrap {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  cursor: default;
}
/* Pill-Variante: für Detail-View oder kompakte Inline-Anzeige mit Text */
.cadence-ampel-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
  padding: 0.1875rem 0.5rem 0.1875rem 0.375rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.cadence-ampel-pill .cadence-ampel {
  width: 7px;
  height: 7px;
}
.cadence-ampel-pill--green {
  background: var(--teal-light);
  color: var(--teal);
}
.cadence-ampel-pill--green .cadence-ampel { background: var(--teal); }
.cadence-ampel-pill--amber {
  background: var(--amber-light);
  color: var(--amber);
}
.cadence-ampel-pill--amber .cadence-ampel { background: var(--amber); }
.cadence-ampel-pill--red {
  background: var(--coral-light);
  color: var(--coral);
}
.cadence-ampel-pill--red .cadence-ampel { background: var(--coral); }

/* Kadenz-Settings-Sektion (page-settings-crm-cadence) */
.cadence-settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 0.75rem;
}
.cadence-settings-tier-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.cadence-settings-tier-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 5rem;
  font-weight: 500;
  font-size: 0.9375rem;
}
.cadence-settings-tier-input {
  width: 6rem;
  flex-shrink: 0;
}
.cadence-settings-tier-unit {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
}

/* Tier-Picker-Row im Detail (inline select + label) */
.tier-picker-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.tier-picker-label {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  flex-shrink: 0;
}
.tier-picker-select {
  min-width: 9rem;
}

@media (max-width: 600px) {
  .cadence-settings-grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* ── Engagement-Badge (P10 Engagement-Score, 2026-06-27) ─────────────────────
   Inline-Pill-Badge im Kontakt- + Firmen-Detail-Header. Visualisiert das
   Engagement-Level (none/low/medium/high) aus engagement.level (API).
   Basis baut auf recency-badge-Metriken (Pill, font-size, padding).
   Intensitäts-Indikator: 3 Mini-Balken via .engagement-bar-[1|2|3] Spans.
   Nur CSS-Variablen, kein hardcodiertes Hex/RGB. Light+Dark via Variablen.
   Selektor: .detail-header > div > div > .engagement-badge (nach Cadence-Pill).
   Dokumentiert in design-system.md Sektion „Engagement-Badge (P10)". */
.engagement-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
  padding: 0.1875rem 0.5rem 0.1875rem 0.4375rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  /* Default / none */
  background: var(--bg-tertiary);
  color: var(--text-tertiary);
  cursor: default;
}
.engagement-badge.is-low {
  background: var(--amber-light);
  color: var(--amber);
}
.engagement-badge.is-medium {
  background: var(--rose-light);
  color: var(--rose);
}
.engagement-badge.is-high {
  background: var(--accent-light);
  color: var(--accent-dark);
}
/* Intensitäts-Balken: 3 Mini-Rechtecke, Höhe gestaffelt */
.engagement-bar {
  display: inline-flex;
  align-items: flex-end;
  gap: 1.5px;
  flex-shrink: 0;
  height: 10px;
}
.engagement-bar-unit {
  width: 3px;
  border-radius: 1px;
  background: currentColor;
  opacity: 0.35; /* inaktiv */
}
.engagement-bar-unit:nth-child(1) { height: 4px; }
.engagement-bar-unit:nth-child(2) { height: 7px; }
.engagement-bar-unit:nth-child(3) { height: 10px; }
/* Aktive Balken je Level */
.engagement-badge.is-none .engagement-bar-unit  { opacity: 0.2; }
.engagement-badge.is-low  .engagement-bar-unit:nth-child(1) { opacity: 1; }
.engagement-badge.is-medium .engagement-bar-unit:nth-child(1),
.engagement-badge.is-medium .engagement-bar-unit:nth-child(2) { opacity: 1; }
.engagement-badge.is-high .engagement-bar-unit { opacity: 1; }

@media (max-width: 900px) {
  .engagement-badge {
    font-size: 0.6875rem;
    padding: 0.125rem 0.375rem 0.125rem 0.3125rem;
  }
}

/* ── Geburtstags-Badge (Kontakte-Liste + Detail) ───────────────────────────────
   Kompaktes Pill-Badge das einen bevorstehenden Geburtstag signalisiert.
   Semantik rose (festlich, weder Warnung noch Fehler). Kein Emoji im CSS –
   der Kalender-SVG wird via JS inline eingebettet.
   Beide Dark-Mode-Pfade (media + data-theme) greifen auf dieselben Variablen. */
.birthday-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1;
  padding: 0.1875rem 0.4375rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  background: var(--rose-light);
  color: var(--rose);
  flex-shrink: 0;
}
.birthday-badge svg {
  flex-shrink: 0;
}

/* ── Merge-Compare-Panel (.merge-compare, …) ────────────────────────────────────
   Split-Screen-Vergleich beim Zusammenführen von 2 Kontakten.
   Desktop: 3-spaltig (Label | Kontakt A | Kontakt B).
   Mobile (≤900px): Label über 2 kompakten Spalten, Zellen gestapelt.
   Nur CSS-Variablen, Light + Dark automatisch via Variablen-System.
   Neue Pattern-Klassen-Familie; Eintrag in design-system.md.              */

.merge-compare {
  display: flex;
  flex-direction: column;
  gap: 0;
  height: 100%;
}

/* Haupt-Kontakt-Wahl ──────────────────────────────────────────────────────── */
.merge-compare-survivor-pick {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.625rem;
  padding: 0.875rem 1rem;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.merge-compare-survivor-label {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
}
.merge-compare-survivor-options {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.merge-compare-survivor-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.3125rem 0.75rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-size: 0.8125rem;
  font-weight: 500;
  cursor: pointer;
  transition: all var(--transition);
  min-height: 36px;
}
.merge-compare-survivor-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.merge-compare-survivor-btn.is-active {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent-dark);
  font-weight: 600;
}
.merge-compare-survivor-check {
  display: none;
  color: var(--accent-dark);
  flex-shrink: 0;
}
.merge-compare-survivor-btn.is-active .merge-compare-survivor-check {
  display: inline-flex;
}

/* Vergleichs-Tabelle ────────────────────────────────────────────────────────
   Scrollbar: flex:1 + overflow-y:auto damit Panel-Footer immer sichtbar bleibt.
   overflow-x:auto erlaubt horizontales Scrollen bei N>2 Spalten auf Mobile.   */
.merge-compare-table {
  flex: 1;
  overflow-y: auto;
  overflow-x: auto;
  min-height: 0;
}

/* Spalten-Header */
.merge-compare-header {
  display: grid;
  grid-template-columns: 6.5rem 1fr 1fr;
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg-primary);
  border-bottom: 2px solid var(--border);
}
.merge-compare-header-label {
  padding: 0.75rem 0.5rem 0.75rem 1rem;
}
.merge-compare-header-col {
  padding: 0.75rem 0.75rem;
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.merge-compare-header-col.is-survivor-col {
  background: var(--accent-light);
  border-top: 2.5px solid var(--accent);
}

/* Avatar im Header */
.merge-compare-head-avatar-wrap {
  display: flex;
  align-items: center;
  gap: 0;
  position: relative;
}
.merge-compare-head-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}
.merge-compare-head-initials {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: 1rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.merge-compare-head-name {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  gap: 0.375rem;
  flex-wrap: wrap;
}
.merge-compare-head-badge {
  display: inline-flex;
  padding: 0.125rem 0.4375rem;
  border-radius: var(--radius-pill);
  font-size: 0.6875rem;
  font-weight: 600;
  background: var(--accent);
  color: #fff;
  line-height: 1.4;
  flex-shrink: 0;
}
.merge-compare-head-meta {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  font-size: 0.75rem;
  color: var(--text-secondary);
}

/* Feld-Zeilen ─────────────────────────────────────────────────────────────── */
.merge-compare-row {
  display: grid;
  grid-template-columns: 6.5rem 1fr 1fr;
  border-bottom: 1px solid var(--border);
  transition: background var(--transition);
}
.merge-compare-row.has-conflict {
  background: var(--amber-light);
}
.merge-compare-row-label {
  padding: 0.625rem 0.5rem 0.625rem 1rem;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  display: flex;
  align-items: flex-start;
  padding-top: 0.75rem;
}
.merge-compare-cell {
  padding: 0.625rem 0.75rem;
  border: none;
  border-left: 1px solid var(--border);
  background: transparent;
  cursor: pointer;
  text-align: left;
  font-size: 0.875rem;
  color: var(--text-primary);
  transition: background var(--transition);
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.375rem;
  min-height: 44px; /* Touch-Target */
}
.merge-compare-cell:hover {
  background: var(--bg-secondary);
}
.merge-compare-cell.is-survivor-cell {
  background: var(--accent-light);
}
.merge-compare-cell.is-survivor-cell:hover {
  background: rgba(242, 107, 78, 0.22);
}
.merge-compare-cell.is-chosen {
  /* Gewählte Seite: stärkerer Hintergrund + Häkchen */
  box-shadow: inset 0 0 0 2px var(--accent);
  border-radius: 0;
}
.merge-compare-cell.is-chosen.is-survivor-cell {
  background: var(--accent-light);
}
.merge-compare-cell.is-chosen:not(.is-survivor-cell) {
  background: var(--bg-secondary);
}
/* Häkchen-Badge rechts oben in gewählter Zelle */
.merge-compare-cell-check {
  position: absolute;
  top: 0.375rem;
  right: 0.375rem;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
/* Leerer Wert */
.merge-compare-empty {
  color: var(--text-tertiary);
  font-style: italic;
  font-size: 0.8125rem;
}
/* Avatar-Vorschau in Zelle */
.merge-compare-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
}
/* Notizen-Vorschau */
.merge-compare-notes {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Footer ────────────────────────────────────────────────────────────────────  */
.merge-compare-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.625rem;
  padding: 0.875rem 1rem;
  border-top: 1px solid var(--border);
  background: var(--bg-primary);
  flex-shrink: 0;
}

/* Mobile (≤900px): gestapelte Darstellung pro Feld ─────────────────────────  */
@media (max-width: 900px) {
  .merge-compare-survivor-pick {
    flex-direction: column;
    align-items: flex-start;
  }
  .merge-compare-header {
    grid-template-columns: 1fr 1fr;
  }
  .merge-compare-header-label {
    display: none;
  }
  .merge-compare-header-col {
    padding: 0.625rem 0.625rem;
    border-left: none;
  }
  .merge-compare-header-col + .merge-compare-header-col {
    border-left: 1px solid var(--border);
  }
  .merge-compare-row {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto auto;
  }
  .merge-compare-row-label {
    grid-column: 1 / -1;
    padding: 0.375rem 0.75rem 0.25rem;
    font-size: 0.6875rem;
    border-bottom: 1px solid var(--border);
    background: var(--bg-secondary);
  }
  .merge-compare-cell {
    padding: 0.5rem 0.625rem;
    border-left: none;
    min-height: 48px; /* Größerer Touch-Target Mobile */
  }
  .merge-compare-cell + .merge-compare-cell {
    border-left: 1px solid var(--border);
  }
  .merge-compare-row.has-conflict .merge-compare-row-label {
    background: var(--amber-light);
  }
  .merge-compare-footer {
    padding: 0.75rem 0.75rem env(safe-area-inset-bottom, 0.75rem);
  }
  .merge-compare-footer .btn {
    flex: 1;
  }
}

/* ── Kontakt-Detail: Followup-Tab (Wiedervorlagen-Liste) ────────────────────
   Zeilen-Liste im Tab „Wiedervorlagen" des Kontakt-Detail.
   Light + Dark via CSS-Variablen. Mobile-Touch-Targets ≥44px.              */

.contact-followup-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.625rem 1.25rem;
  border-bottom: 1px solid var(--border);
  transition: background var(--transition);
}
.contact-followup-row:last-child {
  border-bottom: none;
}
.contact-followup-row:hover {
  background: var(--bg-secondary);
}
.contact-followup-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.contact-followup-title {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.contact-followup-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
/* Fälligkeitsdatum-Badges */
.contact-followup-due {
  font-size: 0.78rem;
  color: var(--teal);
  font-weight: 500;
}
.contact-followup-due--today {
  font-size: 0.78rem;
  color: var(--amber);
  font-weight: 600;
}
.contact-followup-due--overdue {
  font-size: 0.78rem;
  color: var(--danger);
  font-weight: 600;
}
/* Status-Badges */
.contact-followup-status {
  font-size: 0.71875rem;
  padding: 0.125rem 0.4375rem;
  border-radius: var(--radius-pill);
  font-weight: 500;
  line-height: 1.5;
}
.contact-followup-status--open {
  background: var(--accent-light);
  color: var(--accent-dark);
}
.contact-followup-status--snoozed {
  background: var(--amber-light);
  color: var(--amber);
}
.contact-followup-status--done {
  background: var(--teal-light);
  color: var(--teal);
}
/* Aktionsbereich: Schaltflächen rechts */
.contact-followup-actions {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  flex-shrink: 0;
}
.contact-followup-btn {
  min-height: 32px;     /* Desktop kompakt */
  padding: 0.25rem 0.6rem;
  font-size: 0.8125rem;
}

@media (max-width: 900px) {
  .contact-followup-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
  }
  .contact-followup-actions {
    width: 100%;
    justify-content: flex-end;
  }
  .contact-followup-btn {
    min-height: 44px;   /* Touch-Target Mobile */
    padding: 0.375rem 0.75rem;
    font-size: 0.875rem;
  }
}

/* ── Mobile Filter-Leiste (Kontakte + Firmen) ──────────────────────────────
   Desktop: volle Filterleiste sichtbar (.contact-filter-bar-desktop).
   Mobile: nur Suche + Filter-Button (.contact-filter-bar-mobile).
   Die Klasse .contact-filter-bar-desktop blendet den erweiterten Filter-
   Container auf ≤900px aus; .contact-filter-bar-mobile wird auf >900px
   ausgeblendet. Beide Seiten (contacts.js + companies.js) teilen dieses Pattern.
   Der Filter-Button öffnet ein Slide-In-Panel via _openFilterPanel(). */

/* Container der erweiterten Filter – auf Mobile ausgeblendet */
.contact-filter-bar-desktop {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}

/* Mobile: nur Filter-Button-Zeile unter der Suche */
.contact-filter-bar-mobile {
  display: none;   /* Desktop: unsichtbar */
}

@media (max-width: 900px) {
  .contact-filter-bar-desktop {
    display: none;   /* Auf Mobile versteckt */
  }
  .contact-filter-bar-mobile {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
    flex-wrap: nowrap;
  }
}

/* Suchzeile (Suchfeld + Filter-Button) – Kontakte + Firmen (contacts.js + companies.js).
   align-items:stretch löste die Gleich-Hoehe NICHT zuverlaessig (Suchfeld blieb hoeher) –
   deterministischer Fix: beide Kinder bekommen eine FESTE, identische Hoehe (44px), die
   Zeile selbst zentriert statt zu stretchen. */
.contact-search-filter-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.contact-search-filter-row .search-bar {
  height: 44px;
  min-height: 44px;
  margin-bottom: 0;
}
.contact-search-filter-row .contact-filter-btn {
  height: 44px;
}
/* Fix P2-Versatz: .contact-filter-bar-mobile bringt im @media(max-width:900px)-Block
   ein eigenes margin-bottom mit (Abstand zur Liste darunter) – in dieser Zeile
   (align-items:center neben .search-bar) schiebt das den Wrapper visuell nach oben.
   Neutralisieren, Abstand zur Liste kommt bereits von .contact-search-filter-row selbst. */
.contact-search-filter-row .contact-filter-bar-mobile {
  margin-bottom: 0;
}

/* Filter-Button mit Badge-Zähler.
   Punkt 1+3: height:44px (identisch zu search-bar min-height:44px + box-sizing:border-box)
   löst height:40px/min-height:44px-Konflikt UND den 2px-Höhenversatz, der vorher entstand
   weil .search-bar (content-box) den Border ON TOP von min-height addierte (46px statt 44px).
   border-radius --radius-md = bündiges Paar mit der Suchleiste (statt --radius-pill).
   border-width 1px = gleich wie search-bar. box-sizing:border-box für exakte Höhe. */
.contact-filter-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0 0.875rem;
  height: 44px;
  box-sizing: border-box;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: all var(--transition);
  flex-shrink: 0;
  -webkit-tap-highlight-color: transparent;
}
.contact-filter-btn:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}
.contact-filter-btn.is-active {
  background: var(--accent-light);
  color: var(--accent-dark);
  border-color: transparent;
}

/* Badge-Zähler im Filter-Button */
.contact-filter-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 99px;
  background: var(--accent);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
}

/* ── Aktiv/Inaktiv-Segment-Control (Punkt 2, Kontakte + Firmen) ─────────────
   Kompaktes Segmented-Control als Ersatz für die .tab-filter-Leiste.
   Inline in .contact-filter-bar-desktop (neben den anderen Filtern) +
   im Filter-Panel (Mobile). Beide Buttons als visuelle Einheit. */
.contact-status-segment {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  flex-shrink: 0;
}
.contact-status-seg-btn {
  padding: 0 0.75rem;
  height: 32px;
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-size: 0.8125rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--transition), color var(--transition);
  border: none;
  border-right: 1px solid var(--border);
  -webkit-tap-highlight-color: transparent;
}
.contact-status-seg-btn:last-child {
  border-right: none;
}
.contact-status-seg-btn:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}
.contact-status-seg-btn.is-active {
  background: var(--accent-light);
  color: var(--accent-dark);
  font-weight: 600;
}
/* Im Filter-Panel (Mobile) etwas größer für Touch */
@media (max-width: 900px) {
  .contact-status-segment {
    width: 100%;
  }
  .contact-status-seg-btn {
    flex: 1;
    height: 40px;
    font-size: 0.875rem;
    justify-content: center;
    text-align: center;
  }
}

/* ── Detail-Tab-Overflow ⋯-Button ───────────────────────────────────────────
   Icon-only-Mehr-Button in der kompakten Detail-Tab-Leiste wenn Tabs überlaufen.
   Punkt 6 (contacts.js). min-width/height 44px für Touch-Target (Design-System). */
.detail-tab-more-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 32px;
  padding: 0 0.5rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  cursor: pointer;
  flex-shrink: 0;
  transition: background var(--transition), color var(--transition);
  -webkit-tap-highlight-color: transparent;
}
.detail-tab-more-btn:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
@media (max-width: 900px) {
  .detail-tab-more-btn {
    min-height: 44px;
    min-width: 44px;
  }
}

/* ── Mobile native-row-right: sekundäre Badges ausblenden ──────────────────
   Auf Mobile (≤900px) zeigt native-row-right nur: Timestamp + Recency-Badge.
   Alle weiteren Signale (Tier, Kadenz, Engagement, Next-Step, Geburtstag,
   Deals-Badge, Toggle) werden per Modifier-Klasse .native-row-right--slim
   ausgeblendet. Klasse auf contacts.js + companies.js native-row-right. */
@media (max-width: 900px) {
  .native-row-right--slim .cadence-ampel-pill,
  .native-row-right--slim .account-tier-badge,
  .native-row-right--slim .engagement-badge,
  .native-row-right--slim .next-step-badge,
  .native-row-right--slim .birthday-badge,
  .native-row-right--slim .badge-neutral {
    display: none;
  }
  /* Recency-Badge + Toggle bleiben immer sichtbar */
  .native-row-right--slim .recency-badge,
  .native-row-right--slim .ds-theme-toggle {
    display: inline-flex;
  }
}

/* ── grid-sidebar Detail: Cards nie breiter als Viewport ──────────────────
   .grid-sidebar ist auf Mobile bereits 1-spaltig (layout.css:380).
   Cards + deren flex/grid-Kinder brauchen min-width:0 + max-width:100%
   damit kein horizontaler Overflow entsteht. overflow-wrap:anywhere für
   lange URLs/Felder ohne Leerzeichen. */
@media (max-width: 900px) {
  .grid-sidebar {
    min-width: 0;
    max-width: 100%;
  }
  .grid-sidebar .card,
  .grid-sidebar > div {
    min-width: 0;
    max-width: 100%;
    overflow-wrap: anywhere;
    word-break: break-word;
  }
  /* Tabellen in Detail-Cards horizontal scrollbar, kein Page-Overflow */
  .grid-sidebar .table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  /* detail-panel overflow soll auf visible bleiben (companies.css override) */
}

/* ── Form Submissions – Lead-Workflow (.sub-*) ──────────────────
   Scoped to page-form-submissions. All layout vars from base.css.
   Neue Klassen: sub-detail-wrap, sub-lead-section, sub-suggest-panel.
   Dokumentiert in design-system.md § Forms-Submissions.
────────────────────────────────────────────────────────────────── */

.sub-detail-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}

.sub-detail-meta {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
}

/* Lead-Section wrapper */
.sub-lead-section {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.75rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

.sub-lead-section--empty {
  background: var(--bg-secondary);
  border-style: dashed;
}

/* Row: icon + contact-name + badge */
.sub-lead-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.sub-lead-contact-btn {
  font-weight: 600;
  color: var(--accent);
  padding: 0;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.sub-lead-contact-btn:hover { color: var(--accent-dark); }

/* "No contact" hint row */
.sub-lead-no-contact {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8125rem;
  color: var(--text-tertiary);
}

/* Action buttons row */
.sub-lead-actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Suggestions dropdown */
.sub-suggest-panel {
  border-top: 1px solid var(--border);
  padding-top: 0.625rem;
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.sub-suggest-label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-tertiary);
}

.sub-suggest-loading,
.sub-suggest-empty {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  padding: 0.375rem 0;
}

.sub-suggest-list {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

/* Individual candidate row – button for a11y */
.sub-suggest-item {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  width: 100%;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.75rem;
  cursor: pointer;
  text-align: left;
  transition: background var(--transition);
  font-family: inherit;
}
.sub-suggest-item:hover:not(:disabled) {
  background: var(--accent-light);
  border-color: var(--accent);
}
.sub-suggest-item:disabled {
  opacity: 0.5;
  cursor: default;
}

.sub-suggest-item-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.sub-suggest-item-name {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sub-suggest-item-email {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sub-suggest-close {
  align-self: flex-start;
  margin-top: 0.25rem;
}

/* Form fields in detail */
.sub-detail-fields {
  border-top: 1px solid var(--border);
  padding-top: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

.sub-detail-field-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-tertiary);
  margin-bottom: 0.125rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.sub-detail-field-value {
  font-size: 0.875rem;
  color: var(--text-primary);
}

/* Danger zone at bottom of panel */
.sub-detail-danger {
  border-top: 1px solid var(--border);
  padding-top: 0.75rem;
  margin-top: 0.25rem;
}

/* ── Kontakte/Firmen – F1 Inline-Style-Ablösung (2026-07-07) ─────────────────
   Cross-file wiederkehrende statische style="…" aus contacts.js + companies.js.
   .form-group-Breiten-Modifier für Flex-Zeilen (form-row), Text-/Spacing-Utilities. */
.form-group--flex1 { flex: 1; }
.form-group--flex2 { flex: 2; }
.form-group--w130  { flex: 0 0 130px; }
.form-group--w140  { flex: 0 0 140px; }
.form-group--w160  { flex: 0 0 160px; }
.form-group--inline { display: flex; align-items: center; gap: 0.5rem; }

/* Cold-Filter-Wrap gestapelte Variante (Filter-Panel, statt inline Label+Select) */
.cold-filter-wrap--stacked {
  flex-direction: column;
  align-items: flex-start;
  gap: 0.375rem;
}

/* Generischer vertikaler Flex-Stack für Panel-/Formular-Bodies */
.ds-stack-md  { display: flex; flex-direction: column; gap: 1rem; }
.ds-stack-lg  { display: flex; flex-direction: column; gap: 1.25rem; }

/* Utility-Spacing */
.ds-mb-sm { margin-bottom: 0.625rem; }
.ds-flex-icon-sm { margin-right: 0.25rem; flex-shrink: 0; }

/* Utility-Textfarben (inline Spans/Divs ohne eigene Komponentenklasse) */
.ds-text-tertiary { color: var(--text-tertiary); }
.ds-text-coral    { color: var(--coral); }
.ds-text-danger   { color: var(--danger); }
.ds-text-tertiary-count { color: var(--text-tertiary); font-weight: 400; }
.ds-text-sub      { font-size: 0.8125rem; color: var(--text-secondary); }
.ds-label-inline  { font-size: 0.875rem; cursor: pointer; }
.ds-row-title     { font-weight: 500; }

/* Badge-Größen-Modifier */
.badge--sm { font-size: 0.7rem; }

/* Spinner-Größen-Modifier (Basisklasse .spinner in dieser Datei) */
.spinner--14 { width: 14px; height: 14px; border-width: 2px; }
.spinner--16 { width: 16px; height: 16px; border-width: 2px; }
.spinner--18 { width: 18px; height: 18px; border-width: 2px; }
.spinner--22 { width: 22px; height: 22px; border-width: 2.5px; }

/* Spinner-Farb-Modifier: sichtbar auf farbigem/accent-Hintergrund (Primary-Buttons) */
.spinner--on-primary { border-color: rgba(255, 255, 255, .4); border-top-color: #fff; }

/* Spinner-Farb-Modifier für .btn-danger: Hintergrund ist --danger-light (hell/
   gedaempft, nicht solide-rot) – ein weisser Ring wäre kontrastarm. Ring-Seiten
   verschmelzen mit dem Button-Hintergrund (--danger-light), die drehende Top-Kante
   zeigt --danger – identischer Kontrast wie das Button-Label selbst. */
.spinner--on-danger { border-color: var(--danger-light); border-top-color: var(--danger); }

/* Ellipsis-Link (Website/LinkedIn in Stammdaten-Grid) */
.ds-link-ellipsis {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block;
  max-width: 100%;
}

/* Ellipsis-Titel (Deal-/Dokument-Titel in klickbaren Assign-Listen) */
.ds-title-ellipsis {
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Volle Breite + box-sizing für Inputs in Modal.confirm-Bodies (kein Lit-Template, reiner HTML-String) */
.ds-input-full-box { width: 100%; box-sizing: border-box; }

/* Panel-Body für Sekundär-Filter (Mobile Filter-Panel, Kontakte + Firmen identisch) */
.filter-panel-body { display: flex; flex-direction: column; gap: 1.25rem; padding: 1rem 0; }

/* Card-Body-Modifier: Formular-Qualitäts-Panel (größeres Padding + Flex-Stack) */
.card-body--stack { padding: 1.5rem; display: flex; flex-direction: column; gap: 1rem; }

/* Empty-State-Modifier: kompaktes Padding (Basis .empty-state: padding:3rem 2rem) */
.empty-state--compact { padding: 1.5rem; }
.empty-state--tight   { padding: 1.25rem; }

/* Primary-Button füllt die restliche Breite in einer Panel-Aktionsleiste (neben „Abbrechen") */
.btn--flex1 { flex: 1; }

/* Filter-Chip: Inhalt linksbündig statt zentriert (Sekundär-Filter-Panel) */
.filter-chip--start { justify-content: flex-start; }

/* Panel-Footer-Aktionsleiste (Abbrechen + Primary-Button) */
.panel-footer-actions { display: flex; gap: 0.5rem; margin-top: 0.25rem; }

/* ── Mail-Sync-Status (credentials-mail.js – E-Mail-Konten) ─────────────── */
/* Stale-Warnbanner: Abruf steht still (amber) bzw. lief noch nie (coral). */
.mail-sync-stale-banner {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  max-width: 720px;
  margin-bottom: 1.25rem;
  padding: 0.75rem 1rem;
  border-radius: var(--radius-md);
  background: var(--amber-light);
  color: var(--amber);
  border-left: 3px solid var(--amber);
  font-size: 0.875rem;
}
.mail-sync-stale-banner--never {
  background: var(--coral-light);
  color: var(--coral);
  border-left-color: var(--coral);
  font-weight: 600;
}
.mail-sync-stale-banner-icon { flex-shrink: 0; margin-top: 0.1rem; }
.mail-sync-stale-banner-text { flex: 1; line-height: 1.5; }

/* Dezente Zeile wenn der Abruf NICHT stale ist ("Letzter Abruf: …") */
.mail-sync-last-line {
  max-width: 720px;
  margin: -0.5rem 0 1.25rem;
  font-size: 0.8rem;
  color: var(--text-tertiary);
}

/* Per-Konto Sync-Status-Badge (zusätzlich zu .badge-coral/.badge-neutral) */
.mail-account-status-badge { cursor: help; }

/* ── App-Settings: Benachrichtigungen (Spec 20260714, Master/Modul/Typ-Toggles) ──
   Generisches Settings-Zeilen-Pattern (Label+Sub links, Toggle+Actions rechts) –
   ersetzt Inline-Styles bei neuen Abschnitten in page-app-settings (CLAUDE.md
   "CSS: Klassen statt Inline-Styles"). Reusable für weitere Settings-Sektionen. */
.app-settings-section-title {
  font-size: 0.875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  margin: 0;
}
.app-settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0;
}
.app-settings-row--module { padding: 0.75rem 0; }
.app-settings-row--type { padding: 0.55rem 0; }
.app-settings-row.is-disabled .app-settings-row-label,
.app-settings-row.is-disabled .app-settings-row-sub {
  color: var(--text-tertiary);
}
/* Vertikal gestapelte Settings-Sektion (Label+Sub oben, volle-Breite-Control
   darunter, optionaler weiterer Block darunter) – .app-settings-row deckt das
   NICHT ab (dort steht das Control rechts NEBEN dem Label). Ticket 3.222:
   Darstellung-Segmented-Control (4 Modi) + bedingte Zeitfelder. */
.app-settings-theme-row {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
/* flex:1 statt reinem justify-content:space-between-Vertrauen – Reihen mit
   einem VORANGESTELLTEN Icon (Mobile-Nav-Positionen-/Picker-Zeilen, s.u.)
   haben 3 Flex-Kinder statt 2; ohne flex:1 verteilt space-between den freien
   Raum gleichmäßig zwischen ALLEN Geschwistern (Icon<->Text<->Actions),
   statt Text links wachsen zu lassen und Actions rechtsbündig zu pinnen. */
.app-settings-row-text { min-width: 0; flex: 1 1 auto; }
.app-settings-row-label {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--text-primary);
}
.app-settings-row-sub {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  margin-top: 0.125rem;
}
.app-settings-row-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-shrink: 0;
}
.app-settings-divider {
  height: 1px;
  background: var(--border);
  margin: 0.5rem 0;
}
.app-settings-panel-body {
  display: flex;
  flex-direction: column;
}
.app-settings-panel-hint {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
  margin: 0 0 0.5rem;
  line-height: 1.5;
}

/* ── App-Settings: Mobile-Bottom-Nav-Konfiguration (Spec 20260721 M4) ──
   Live-Vorschau embedded die echte .ds-bottom-nav-Markup (nav.css) in einer
   umrandeten Box; Slot-Zeilen + Picker-Panel nutzen die App-Settings-Zeilen-
   klassen oben + zwei neue Klassen für Icon-Präfix und Picker-Buttons. */
.app-settings-mobile-preview {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  max-width: 420px;
}
.app-settings-mobile-preview .ds-bottom-nav-items { justify-content: space-around; }

.app-settings-row--picker {
  width: 100%;
  text-align: left;
  border: none;
  background: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.app-settings-row--picker:hover:not(.is-disabled) { background: var(--bg-secondary); }
.app-settings-row--picker:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.app-settings-row--picker.is-disabled { cursor: not-allowed; opacity: 0.5; }

.app-settings-picker-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
}
.app-settings-picker-group-label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-tertiary);
  margin: 0.75rem 0 0.25rem;
}
.app-settings-section-title--first  { margin-top: 0.5rem; }
.app-settings-section-title--spaced { margin-top: 1rem; }

/* ── ds-email-recipients (Backlog B41, Spec 20260728_document_send_recipients) ──
   Schlankere Variante von .ds-attendee-picker/.attendee-* – reine E-Mail-Chips,
   keine Kalender-Semantik (kein Settings-Dropdown, kein Status-Icon). Eigener
   Klassen-Namespace .ds-email-recip-* statt Wiederverwendung von .attendee-*. */
.ds-email-recip {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .3rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .5rem .75rem;
  min-height: 42px;
  cursor: text;
  background: var(--bg-primary);
}
.ds-email-recip:focus-within { border-color: var(--accent); }
.ds-email-recip.is-disabled {
  opacity: .6;
  cursor: not-allowed;
  background: var(--bg-secondary);
}

.ds-email-recip-chip {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: 2px 8px 2px 10px;
  border-radius: 999px;
  background: var(--accent-light);
  color: var(--accent);
  font-size: .82rem;
  white-space: nowrap;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-email-recip-chip-remove {
  background: none; border: none; cursor: pointer;
  color: inherit; padding: 0 0 0 4px; line-height: 1;
  opacity: .6; font-size: 1rem;
}
.ds-email-recip-chip-remove:hover { opacity: 1; }
.ds-email-recip-chip-remove:disabled { cursor: not-allowed; opacity: .4; }

.ds-email-recip-input-wrap { position: relative; flex: 1 1 160px; min-width: 160px; }
.ds-email-recip-input {
  width: 100%;
  border: none;
  outline: none;
  background: transparent;
  color: var(--text-primary);
  font-size: .9rem;
  padding: 2px 0;
  font-family: inherit;
  min-height: 24px;
}
.ds-email-recip-input:disabled { cursor: not-allowed; }

.ds-email-recip-suggest-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  min-width: 260px;
  max-height: 220px;
  overflow-y: auto;
  z-index: 200;
}
.ds-email-recip-suggest-item {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .45rem .75rem;
  cursor: pointer;
}
.ds-email-recip-suggest-item:hover,
.ds-email-recip-suggest-item.is-active { background: var(--accent-light); }
.ds-email-recip-suggest-avatar {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--bg-secondary);
  color: var(--text-secondary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: .75rem;
  font-weight: 600;
  flex-shrink: 0;
  overflow: hidden;
}
.ds-email-recip-suggest-avatar img { width: 100%; height: 100%; object-fit: cover; }
.ds-email-recip-suggest-text { min-width: 0; flex: 1; }
.ds-email-recip-suggest-name { font-size: .85rem; color: var(--text-primary); }
.ds-email-recip-suggest-email { font-size: .75rem; color: var(--text-tertiary); }

/* ── page-settings-mcp-keys – Verwaltung des zentralen MCP-Zugangsschlüssels
   (Ticket 3.410.10). Katalog-getriebene Modul-Zuteilung: je Modul ein
   An/Aus-Schalter (.ds-theme-toggle, echtes Binär), Umfang als Segmented-
   Control (.contact-status-segment – genau zwei benannte Werte, immer einer
   aktiv) und zwei Mehrfachauswahl-Cluster (Bereiche/Rechte) als Chips
   (.filter-chip – Mehrfachauswahl ist kein Toggle, Projektregel). Reused
   .card/.page-header/.ds-fieldset/.ds-info-box/.badge aus dieser Datei bzw.
   _invoicing.css (.ds-info-box) – keine neuen Basis-Komponenten. ────────── */
.mcp-keys-wrap { padding: 0.25rem 0 1.5rem; }
.mcp-keys-intro-text { font-size: 0.875rem; color: var(--text-secondary); margin: 0 0 1.25rem; }
.mcp-keys-create-trigger { margin-bottom: 1.25rem; }
.mcp-keys-empty-text { color: var(--text-secondary); padding: 1rem 0; font-size: 0.9rem; }
.mcp-keys-required { color: var(--coral); }

/* Katalog leer (z.B. Mandant mit feature_set='finance' ohne zuteilbare Module) */
.mcp-keys-catalog-empty {
  text-align: center;
  padding: 2.5rem 1.5rem;
  color: var(--text-secondary);
}
.mcp-keys-catalog-empty-icon { color: var(--text-tertiary); margin-bottom: 0.75rem; }
.mcp-keys-catalog-empty-title { margin: 0 0 0.4rem; font-weight: 600; color: var(--text-primary); }
.mcp-keys-catalog-empty-text { margin: 0; font-size: 0.875rem; }

.mcp-keys-skeleton-card { padding: 1.25rem; }
.mcp-keys-skeleton-row { display: flex; gap: 1rem; padding: 0.5rem 0; }
.mcp-keys-skeleton-row + .mcp-keys-skeleton-row { border-top: 1px solid var(--border); }

/* Klartext-Anzeige des neuen Schlüssels – genau EINMAL sichtbar */
.mcp-keys-newkey-card { border: 2px solid var(--teal); margin-bottom: 1.5rem; }
.mcp-keys-newkey-title { font-weight: 600; margin-bottom: 0.5rem; }
.mcp-keys-newkey-code {
  display: block;
  padding: 0.75rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  word-break: break-all;
  margin-bottom: 0.75rem;
}
.mcp-keys-newkey-warn { color: var(--amber); font-size: 0.875rem; margin-top: 0.75rem; }
/* Ticket 3.410.4 – Skill-Download neben dem frisch erzeugten Schlüssel: eigene Zeile, damit
   der primäre „Schließen“-Button darunter nicht mit einem inline-Link konkurriert. */
.mcp-keys-newkey-skill-link { display: flex; width: fit-content; margin-top: 0.75rem; text-decoration: none; }
.mcp-keys-newkey-close-btn { margin-top: 1rem; width: 100%; }
.mcp-keys-copy-icon { margin-right: 0.25rem; }

/* Anlegen-/Bearbeiten-Formular (geteilt: neuer Schlüssel + Zuteilungen bestehender Schlüssel) */
.mcp-keys-create-card { margin-bottom: 1.5rem; }
.mcp-keys-create-title { font-weight: 600; }
.mcp-keys-form-readonly-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem 1.25rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  margin: 0 0 1rem;
}
.mcp-keys-form-readonly-row strong { color: var(--text-primary); font-weight: 600; }
.mcp-keys-actions-row { display: flex; gap: 0.5rem; margin-top: 1rem; }
.mcp-keys-actions-primary { flex: 1; }

/* Modul-Zuteilungs-Editor */
.mcp-keys-modules { display: flex; flex-direction: column; gap: 0.75rem; margin-top: 0.75rem; }
.mcp-keys-module-row {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.75rem 0.875rem;
  transition: border-color var(--transition), background var(--transition);
}
.mcp-keys-module-row.is-enabled { border-color: var(--accent); background: var(--bg-secondary); }
.mcp-keys-module-row-head { display: flex; align-items: center; gap: 0.75rem; }
.mcp-keys-module-row-label { font-weight: 600; font-size: 0.9rem; color: var(--text-primary); }
.mcp-keys-module-row-body {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.mcp-keys-field-label {
  display: block;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-tertiary);
  margin-bottom: 0.4rem;
}
.mcp-keys-scope-mode-all-warn { margin-top: 0.5rem; }
.mcp-keys-scope-hint-text { font-size: 0.8125rem; color: var(--text-secondary); margin: 0.375rem 0 0; }
/* Wrapping Mehrfachauswahl-Cluster – bewusst EIGENE Klasse statt .chip-filter-strip:
   jene ist für die horizontal scrollende Seiten-Filterleiste gedacht
   (overflow-x:auto, border-bottom), hier wird stattdessen umgebrochen. */
.mcp-keys-chip-group { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.mcp-keys-empty-hint { font-size: 0.8125rem; color: var(--text-tertiary); margin: 0; }
.mcp-keys-scope-warn { color: var(--coral); font-size: 0.8rem; margin: 0.4rem 0 0; }
.mcp-keys-rights { margin: 0; padding: 0.75rem; }

.mcp-keys-edit-actions { display: flex; gap: 0.5rem; margin-top: 1rem; padding-top: 0.75rem; border-top: 1px solid var(--border); }
.mcp-keys-edit-actions-primary { flex: 1; }

/* Liste bestehender Schlüssel – Karten statt Tabelle (variable Zuteilungs-
   Inhalte pro Zeile passen schlecht in starre Spalten, s. Modul-Kommentar
   in settings-mcp-keys.js). */
.mcp-keys-list { display: flex; flex-direction: column; gap: 0.875rem; }
.mcp-keys-key-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.mcp-keys-key-card-title { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.mcp-keys-key-label { font-weight: 600; font-size: 0.95rem; color: var(--text-primary); }
.mcp-keys-key-card-actions { display: flex; gap: 0.5rem; flex-shrink: 0; }
.mcp-keys-key-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.25rem;
  font-size: 0.8rem;
  color: var(--text-secondary);
  margin-top: 0.5rem;
}
.mcp-keys-prefix-code {
  font-size: 0.8rem;
  background: var(--bg-secondary);
  padding: 0.15rem 0.4rem;
  border-radius: var(--radius-sm);
}

.mcp-keys-assignments-summary { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.75rem; }
.mcp-keys-assignment-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  font-size: 0.8125rem;
}
.mcp-keys-assignment-detail { color: var(--text-secondary); }
.mcp-keys-assignments-none { color: var(--text-tertiary); font-size: 0.8125rem; margin: 0.5rem 0 0; font-style: italic; }

@media (max-width: 900px) {
  .mcp-keys-key-card-actions { width: 100%; }
  .mcp-keys-key-card-actions .btn { flex: 1; }
}

/* Umfang-Segmented-Control mit längeren Labels als das Kontakte-Vorbild
   ("Bestimmte Bereiche" / "Alle (auch künftige)") – Basis-Klasse
   .contact-status-seg-btn bewusst NICHT verändert (kurze Zwei-Wort-Labels
   wie Aktiv/Inaktiv anderswo dürfen nicht umbrechen/wachsen), stattdessen
   scoped Override nur innerhalb der Modul-Zeile: Text darf umbrechen statt
   auf Mobile hinter dem Kartenrand abgeschnitten zu werden. */
.mcp-keys-module-row .contact-status-seg-btn {
  white-space: normal;
  line-height: 1.25;
  text-align: center;
}
@media (max-width: 900px) {
  .mcp-keys-module-row .contact-status-seg-btn {
    height: auto;
    min-height: 40px;
    padding-top: 0.4rem;
    padding-bottom: 0.4rem;
  }
}

/* ── Vereinte Zugriffsschlüssel-Übersicht (Ticket 3.410.11 Teil 2) ─────────
   Art-Auswahl beim Anlegen (Modulübergreifend/Aufgaben/Notizen) – dieselbe
   Scoped-Override-Begründung wie oben: "Modulübergreifend" ist länger als
   die kurzen Zwei-Wort-Vorbilder (Aktiv/Inaktiv) und muss auf Mobile
   umbrechen dürfen statt am Kartenrand abgeschnitten zu werden. */
.mcp-keys-kind-segment .contact-status-seg-btn {
  white-space: normal;
  line-height: 1.25;
  text-align: center;
}
@media (max-width: 900px) {
  .mcp-keys-kind-segment .contact-status-seg-btn {
    height: auto;
    min-height: 40px;
    padding-top: 0.4rem;
    padding-bottom: 0.4rem;
  }
}
/* Rechte-Chips unter Umfang/Bereich-Angabe der Aufgaben-/Notizen-Karten (die
   MCP-Karte hat ihre eigene .mcp-keys-assignments-summary, kein Overlap). */
.mcp-keys-rights-row { margin-top: 0.75rem; }
/* ── Import Module ── */

/* Source-Tabs (Google / LinkedIn) */
.import-source-tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
  flex-wrap: wrap;
}
.import-source-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  background: var(--bg-primary);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-secondary);
  cursor: pointer;
  transition: border-color var(--transition), color var(--transition), background var(--transition);
}
.import-source-tab:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
.import-source-tab.active {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-light);
}

/* Split-Screen-Merge-Modal.
   Backdrop wird inline im Lit-Template gerendert aber braucht fixed über
   der gesamten Viewport-Fläche. Die Ancestors (ds-content-body, page-import)
   erzeugen ggf. eigene Stacking-Contexts — daher brauchen wir explizites
   Contain-Override auf dem Page-Element wenn Modal offen ist. */
/* Merge-Modal: Backdrop + Modal werden direkt an document.body gerendert
   (per updated()-Hook), damit kein Ancestor mit overflow/transform clippt.
   Falls Inline-Fallback: overflow-override auf Ancestors. */
.import-merge-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.55);
  z-index: 99999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  animation: importMergeFade 150ms ease both;
}
@keyframes importMergeFade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.import-merge-modal {
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: min(860px, 100%);
  max-height: 90vh;
  overflow-y: auto;
  margin: auto;
  display: flex;
  flex-direction: column;
}
.import-merge-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem 1.5rem 0.75rem;
  border-bottom: 1px solid var(--border);
}
.import-merge-candidates {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
  padding: 0.75rem 1.5rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
}
.import-merge-candidate {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 0.5rem 0.875rem;
  background: var(--bg-primary);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-md);
  font-size: 0.8125rem;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.import-merge-candidate:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
.import-merge-candidate.active {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
}
.import-merge-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem 1rem;
  padding: 1rem 1.5rem;
}
.import-merge-col-head {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
  padding-bottom: 0.25rem;
  border-bottom: 1px solid var(--border);
}
.import-merge-field-label {
  grid-column: 1 / -1;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: 0.625rem;
  margin-bottom: -0.125rem;
}
.import-merge-cell {
  text-align: left;
  padding: 0.625rem 0.875rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  font-size: 0.875rem;
  color: var(--text-primary);
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
  word-break: break-word;
  min-height: 42px;
}
.import-merge-cell:hover:not(:disabled) {
  border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
}
.import-merge-cell.picked {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
}
.import-merge-cell.empty {
  background: var(--bg-secondary);
  cursor: default;
}
.import-merge-cell:disabled { opacity: 0.75; }
.import-merge-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem 1.5rem;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}
@media (max-width: 600px) {
  .import-merge-grid { grid-template-columns: 1fr; }
  .import-merge-col-head:last-of-type { display: none; }
}

.import-dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--radius-lg);
  padding: 3rem 2rem;
  text-align: center;
  cursor: pointer;
  transition: border-color 150ms ease, background 150ms ease;
  background: var(--bg-secondary);
}
.import-dropzone:hover,
.import-dropzone.drag-over {
  border-color: var(--primary);
  background: var(--primary-light, rgba(0,55,128,0.06));
}
.import-dropzone input[type="file"] {
  display: none;
}
.import-dropzone-icon {
  width: 48px;
  height: 48px;
  margin: 0 auto 1rem;
  color: var(--text-tertiary);
}
.import-dropzone-label {
  font-size: 1rem;
  font-weight: 500;
  color: var(--text-primary);
  margin-bottom: 0.375rem;
}
.import-dropzone-hint {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
}
.import-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1rem;
  margin-bottom: 1.5rem;
}
.import-stat {
  background: var(--bg-secondary);
  border-radius: var(--radius-md);
  padding: 1rem;
  text-align: center;
}
.import-stat-value {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1;
  margin-bottom: 0.25rem;
}
.import-stat-label {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.import-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8125rem;
}
.import-table th {
  text-align: left;
  padding: 0.5rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
  position: sticky;
  top: 0;
  z-index: 1;
}
.import-table td {
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border-light, var(--border));
  vertical-align: middle;
}
.import-row td {
  background: var(--bg-primary);
}
.import-row-skip td {
  background: var(--bg-secondary);
  color: var(--text-tertiary);
  text-decoration: line-through;
}
.import-row-skip .badge {
  opacity: 0.5;
}
.import-company-match {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
}
.import-create-company {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.75rem;
  color: var(--text-tertiary);
  margin-top: 0.25rem;
}
.import-create-company input[type="checkbox"] {
  accent-color: var(--primary);
}
/* vCard-Import: "Foto vorhanden"-Hinweis-Icon neben dem Kontaktnamen (Baustein C) */
.import-photo-badge {
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
  margin-left: 0.375rem;
  color: var(--text-tertiary);
}
.import-bulk-toolbar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.import-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  max-height: 60vh;
  overflow-y: auto;
}
.company-option {
  padding: 0.625rem 1rem;
  cursor: pointer;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  gap: 0.75rem;
  transition: background 100ms;
}
.company-option:hover {
  background: var(--bg-secondary);
}
.company-option-name {
  font-weight: 500;
}
.company-option-meta {
  font-size: 0.75rem;
  color: var(--text-tertiary);
}
/* .badge-teal — kanonische Definition in _core.css (Z.266), Dupe hier entfernt (B10) */
.badge-warning {
  background: var(--amber-light, rgba(255,160,0,0.12));
  color: var(--amber-dark, #e65100);
}
.badge-neutral {
  background: var(--bg-tertiary, var(--bg-secondary));
  color: var(--text-secondary);
}

/* ── Import Quality Score Badge ── */
.quality-score {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  padding: 0.2rem 0.45rem;
  border-radius: 999px;
  white-space: nowrap;
}
.quality-high {
  background: rgba(0,150,136,0.12);
  color: var(--teal, #009688);
}
.quality-med {
  background: rgba(255,160,0,0.14);
  color: #b45309;
}
.quality-low {
  background: rgba(239,68,68,0.12);
  color: var(--coral, #e53e3e);
}

/* ── Import: Company Preview + Merge Modal (Papierkram/SumUp, 2026-05-20) ── */
.import-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.import-profile-select {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin-bottom: 1rem;
  font-size: 0.875rem;
}
.import-profile-select label {
  color: var(--text-secondary);
  white-space: nowrap;
}
.import-company-name {
  font-weight: 500;
}
.import-company-email {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}
.import-merge-modal-section {
  border-top: 1px solid var(--border);
  margin-top: 0.75rem;
  padding-top: 0.75rem;
}
.import-merge-modal-section-title {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  margin-bottom: 0.5rem;
}
.import-merge-modal-section-title svg {
  flex-shrink: 0;
}
@media (max-width: 900px) {
  .import-profile-select {
    flex-direction: column;
    align-items: flex-start;
  }
  .import-profile-select .select {
    width: 100%;
  }
}

/* ── Credentials-Calendar – Sub-Kalender Liste ────────────────────── */
.cred-cal-subs {
  border-top: 1px solid var(--border);
  padding: 0.5rem 1.125rem;
}
.cred-cal-subs-header {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-bottom: 0.35rem;
}
.cred-cal-subrow {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.2rem 0;
  font-size: 0.82rem;
  border-radius: var(--radius-sm);
  transition: background var(--transition), opacity var(--transition);
}
.cred-cal-subrow:hover {
  background: var(--bg-secondary);
}
.cred-cal-subrow.is-dragging {
  opacity: 0.4;
}
.cred-cal-drag-handle {
  width: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  cursor: grab;
  flex-shrink: 0;
}
.cred-cal-drag-handle:active { cursor: grabbing; }
.cred-cal-color-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.cred-cal-sub-name {
  flex: 1;
  color: var(--text-primary);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cred-cal-move-btn {
  padding: 0.3rem !important;
  min-height: 28px;
  min-width:  28px;
  color: var(--text-tertiary);
}
.cred-cal-move-btn:hover:not(:disabled) {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}
.cred-cal-move-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.cred-cal-hide-btn {
  padding: 0.35rem !important;
  min-height: 32px;
  min-width:  32px;
  color: var(--text-tertiary);
}
.cred-cal-hide-btn:hover {
  color: var(--coral);
  background: var(--coral-light);
}
/* Harter App-Sichtbarkeits-Toggle (show_in_app) — getrennt vom weichen
   is_visible-Sidebar-Toggle. Sitzt zwischen Stern und Ausblenden-Button. */
.cred-cal-appvis-btn {
  padding: 0.35rem !important;
  min-height: 32px;
  min-width:  32px;
  color: var(--text-secondary);
}
.cred-cal-appvis-btn:hover {
  color: var(--accent);
  background: var(--accent-light);
}
.cred-cal-appvis-btn.is-off {
  color: var(--text-tertiary);
  opacity: 0.65;
}
.cred-cal-appvis-btn.is-off:hover {
  color: var(--amber);
  background: var(--amber-light);
}
.cred-cal-unhide-link {
  display: block;
  margin-top: 0.5rem;
  background: none;
  border: none;
  padding: 0.25rem 0;
  font-size: 0.78rem;
  color: var(--accent);
  cursor: pointer;
  text-align: left;
}
.cred-cal-unhide-link:hover { text-decoration: underline; }

/* ── Credentials-Calendar – Reauth-Warnung (needs_reauth) ─────────── */
/* Backlog A22, Spec 20260728_cron_alerting_and_connection_health.md §B4 */
.cred-cal-reauth-card {
  border-color: var(--coral);
}
.cred-cal-reauth-badge {
  font-size: 0.7rem;
}
.cred-cal-reauth-reason {
  font-size: 0.78rem;
  color: var(--coral);
  margin-top: 0.3rem;
}
.cred-cal-reauth-banner {
  border-top: 1px solid var(--border);
  padding: 0.625rem 1.125rem;
  background: var(--coral-light);
  display: flex;
  justify-content: flex-end;
}
.cred-cal-reauth-btn {
  background: var(--bg-primary);
  border: 1px solid var(--coral);
  color: var(--coral);
}
.cred-cal-reauth-btn:hover {
  background: var(--coral);
  color: #fff;
}

/* ── Calendar Volle Bildschirmhöhe ─────────────────────────────── */
/* Flex-Chain: ds-content-body → page-calendar → #cal-content → .card → .card-body → .cal-time-scroll
   Jede Ebene braucht flex:1 + min-height:0 damit Höhe nach unten durchgereicht wird
   und .cal-time-scroll als einziges Element intern scrollt. */

page-calendar {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  padding: 0.75rem 1rem 0.5rem;
  box-sizing: border-box;
}

/* page-header: feste Höhe, nicht scrollbar */
page-calendar .page-header {
  margin-bottom: 0.5rem;
  flex-shrink: 0;
}

/* #cal-content: nimmt den verbleibenden Platz ein */
page-calendar #cal-content {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* .card innerhalb von #cal-content dehnt sich aus */
/* overflow: visible – damit der Date-Picker-Dropdown nicht geclippt wird */
page-calendar #cal-content > .card {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: visible;
}

page-calendar #cal-content > .card > .card-header {
  flex-shrink: 0;
}

page-calendar #cal-content > .card > .card-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0;
}

/* Time-Grid-Wrapper dehnt sich, Scrolling intern */
page-calendar .cal-time-grid-wrap {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Das Zeitraster selbst scrollt intern – keine max-height */
page-calendar .cal-time-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* Monatsansicht: cal-mobile-split nimmt vollen Platz ein */
page-calendar .cal-mobile-split {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

/* Tabs für Buchungstypen/Buchungen: Padding wiederherstellen */
page-calendar .cal-content-padded {
  padding: 1rem;
  overflow-y: auto;
  flex: 1;
}

@media (max-width: 900px) {
  page-calendar {
    padding: 0.5rem 0.5rem 0.25rem;
  }
  /* Mobile: dynamische Viewport-Höhe (iOS Safari) */
  .ds-content-body:has(page-calendar) {
    height: 100dvh;
    max-height: 100dvh;
  }
}

/* ── Calendar Grid ─────────────────────────────────────────────── */
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  border-left: 1px solid var(--border);
  border-top: 1px solid var(--border);
}
.cal-grid-header {
  text-align: center;
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--text-tertiary);
  padding: 0.5rem 0.25rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
}
.cal-day {
  min-height: 96px;
  padding: 0.375rem;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  overflow: hidden;
  transition: background var(--transition);
  position: relative;
}
.cal-day:hover { background: var(--bg-secondary); }
.cal-day-empty {
  background: var(--bg-secondary);
  cursor: default;
  opacity: 0.5;
}
.cal-day-empty:hover { background: var(--bg-secondary); }
/* Vor-/Folgemonat-Tage: ausgegraut, klickbar */
.cal-day-other-month {
  cursor: pointer;
}
.cal-day-other-month .cal-day-num {
  color: var(--text-tertiary);
}
.cal-day-other-month:hover {
  background: var(--bg-secondary);
}
.cal-day-today { background: var(--accent-light); }
.cal-day-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--text-secondary);
  margin-bottom: 0.25rem;
  border-radius: 50%;
}
.cal-day-today .cal-day-num {
  background: var(--accent);
  color: #fff;
  font-weight: 600;
}
/* Kalenderwoche in der Montags-Spalte der Monatsansicht (Fix #1b) — dezent
   neben der Tageszahl, keine eigene Zeile. */
.cal-day-kw {
  font-size: 0.66rem;
  font-weight: 500;
  color: var(--text-tertiary);
  margin-left: 0.25rem;
  white-space: nowrap;
}
/* All-day event bars – Outlook Pill-Style */
.cal-event-bar {
  display: block;
  height: var(--cal-allday-height);
  line-height: var(--cal-allday-height);
  font-size: 0.75rem;
  font-weight: 500;
  padding: 0 6px 0 8px;
  border-radius: 3px;
  border-left: 3px solid transparent; /* color set inline */
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 2px;
  cursor: pointer;
  transition: filter var(--transition);
  box-sizing: border-box;
  /* iOS-Long-Press-Hardening: verhindert, dass der native Callout/Text-
     Auswahl-Long-Press unseren 500ms-Kontextmenü-Timer kapert (analog
     .cal-event-block). */
  -webkit-touch-callout: none;
  user-select: none;
}
.cal-event-bar:hover { filter: brightness(0.96); }

/* Feiertags-Bar – nicht editierbar, eigene Rose-Akzentfarbe */
/* User-Defaults für die lokalen Sidebar-Kalender. Werden zur Laufzeit
   von calendar.js#_applyLocalColorVars() überschrieben sobald das User-Profil
   geladen ist. */
:root {
  --user-local-color:    #003780;
  --user-holiday-color:  #C4426A;
  --user-followup-color: #BA7517;
}

.cal-holiday-bar {
  display: flex;
  align-items: center;
  gap: 4px;
  height: var(--cal-allday-height);
  line-height: var(--cal-allday-height);
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0 6px 0 8px;
  border-radius: 3px;
  border-left: 3px solid var(--user-holiday-color);
  background: color-mix(in srgb, var(--user-holiday-color) 12%, var(--bg-primary));
  color: var(--user-holiday-color);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 2px;
  cursor: pointer;
  transition: filter var(--transition);
  box-sizing: border-box;
}
.cal-holiday-bar:hover { filter: brightness(0.96); }
.cal-holiday-bar svg   { color: var(--user-holiday-color); }
.cal-holiday-bar span  { overflow: hidden; text-overflow: ellipsis; }

/* Wiedervorlage-Bar – gleicher Stil wie Holiday-Bar, aber Followup-Farbe */
.cal-followup-bar {
  display: flex;
  align-items: center;
  gap: 4px;
  height: var(--cal-allday-height);
  line-height: var(--cal-allday-height);
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0 6px 0 8px;
  border-radius: 3px;
  border-left: 3px solid var(--user-followup-color);
  background: color-mix(in srgb, var(--user-followup-color) 12%, var(--bg-primary));
  color: var(--user-followup-color);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 2px;
  cursor: pointer;
  transition: filter var(--transition);
  box-sizing: border-box;
}
.cal-followup-bar:hover { filter: brightness(0.96); }
.cal-followup-bar svg   { color: var(--user-followup-color); }
.cal-followup-bar span  { overflow: hidden; text-overflow: ellipsis; }

.cal-event-more {
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--accent);
  padding: 1px 4px;
  cursor: pointer;
  background: none;
  border: none;
  display: block;
  text-align: left;
  width: 100%;
}
.cal-event-more:hover { text-decoration: underline; }

@media (max-width: 600px) {
  .cal-day { min-height: 52px; padding: 0.25rem; }
  .cal-event-bar { display: none; }
  .cal-day:has(.cal-event-bar)::after {
    content: '';
    display: block;
    width: 5px; height: 5px;
    border-radius: 50%;
    background: var(--accent);
    margin: 2px auto 0;
  }
}

/* ── Calendar Toolbar (Outlook-Style) ───────────────────────── */
.cal-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 1rem;
  gap: 0.75rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-primary);
  flex-wrap: wrap;
}
.cal-toolbar-nav {
  display: flex;
  align-items: center;
  gap: 0.125rem;
}
.cal-toolbar-date {
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--text-primary);
  margin-left: 0.375rem;
  white-space: nowrap;
}

/* Date-Picker Trigger Button */
.cal-toolbar-date-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--text-primary);
  margin-left: 0.375rem;
  white-space: nowrap;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.2rem 0.375rem;
  border-radius: var(--radius-sm);
  transition: background var(--transition), color var(--transition);
}
.cal-toolbar-date-btn:hover,
.cal-toolbar-date-btn.active {
  background: var(--accent-light);
  color: var(--accent);
}
.cal-dp-chevron {
  color: var(--text-tertiary);
  transition: transform var(--transition);
  flex-shrink: 0;
}
.cal-dp-chevron.open { transform: rotate(180deg); }

/* ── Date-Picker Dropdown ────────────────────────────────────── */
.cal-dp-backdrop {
  position: fixed;
  inset: 0;
  z-index: 299;
}
.cal-dp-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 300;
  display: flex;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  animation: calDpIn 150ms ease both;
}
@keyframes calDpIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .cal-dp-dropdown { animation: none; }
}

.cal-dp-divider {
  width: 1px;
  background: var(--border);
  flex-shrink: 0;
}

/* Linkes + rechtes Panel */
.cal-dp-panel {
  padding: 0.75rem;
}
.cal-dp-left  { width: 224px; }
.cal-dp-right { width: 196px; display: flex; flex-direction: column; }

/* Panel-Header: Pfeile + Label */
.cal-dp-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.625rem;
}
.cal-dp-header-label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
}
.cal-dp-arrow {
  background: none;
  border: none;
  cursor: pointer;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  color: var(--text-secondary);
  transition: background var(--transition), color var(--transition);
  line-height: 1;
  padding: 0;
}
.cal-dp-arrow:hover { background: var(--bg-secondary); color: var(--text-primary); }

/* Mini-Kalender Wochentage */
.cal-dp-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin-bottom: 0.25rem;
}
.cal-dp-weekdays span {
  text-align: center;
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--text-tertiary);
  padding: 2px 0;
}

/* Mini-Kalender Tage */
.cal-dp-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
}
.cal-dp-day {
  background: none;
  border: none;
  cursor: pointer;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  font-size: 0.8125rem;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition), color var(--transition);
  padding: 0;
}
.cal-dp-day:hover           { background: var(--bg-tertiary); }
.cal-dp-other               { color: var(--text-tertiary); }
.cal-dp-today               { background: var(--accent); color: #fff; font-weight: 700; border-radius: 50%; }
.cal-dp-today:hover         { background: var(--accent-dark); border-radius: 50%; }
.cal-dp-in-range            { background: var(--accent-light); border-radius: 0; }
.cal-dp-in-range:first-child,
.cal-dp-in-range:hover      { border-radius: 50%; }
/* Heute bleibt immer ein Kreis, auch wenn er in der aktuellen Woche liegt */
.cal-dp-today.cal-dp-in-range { background: var(--accent); color: #fff; border-radius: 50%; }

/* Monats-Grid (rechtes Panel) */
.cal-dp-months {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
  flex: 1;
}
.cal-dp-month {
  background: none;
  border: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
  color: var(--text-primary);
  padding: 0.375rem 0.25rem;
  text-align: center;
  transition: background var(--transition), color var(--transition);
}
.cal-dp-month:hover        { background: var(--bg-tertiary); }
.cal-dp-month-active       { background: var(--accent); color: #fff; font-weight: 600; }
.cal-dp-month-active:hover { background: var(--accent-dark); }

/* Footer: Heute-Button */
.cal-dp-footer {
  display: flex;
  justify-content: flex-end;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
  margin-top: 0.5rem;
}

/* Mobile: Bottom-Sheet */
@media (max-width: 900px) {
  .cal-dp-backdrop {
    background: rgba(0,0,0,0.35);
  }
  .cal-dp-dropdown {
    position: fixed;
    top: auto;
    bottom: 0;
    left: 0;
    right: 0;
    flex-direction: column;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    border-bottom: none;
    animation: calDpBottomIn 200ms ease both;
    z-index: 400;
    max-height: 80dvh;
    overflow-y: auto;
  }
  @keyframes calDpBottomIn {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
  }
  .cal-dp-divider { width: 100%; height: 1px; }
  .cal-dp-left  { width: 100%; }
  .cal-dp-right { width: 100%; }
  /* Mobile: Backdrop als Overlay */
  .cal-dp-dropdown::before {
    content: '';
    display: block;
    position: fixed;
    inset: 0;
    bottom: 100%;
    background: rgba(0,0,0,0.3);
    z-index: -1;
  }
}

.cal-toolbar-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

/* ── Calendar view switcher (Segmented Pill) ─────────────────── */
.cal-view-switcher {
  display: flex;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 2px;
  gap: 2px;
}
.cal-view-btn {
  padding: 0.25rem 0.625rem;
  font-size: 0.8125rem;
  font-weight: 500;
  background: none;
  border: none;
  border-radius: calc(var(--radius-md) - 2px);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
  white-space: nowrap;
}
.cal-view-btn:hover  { background: var(--bg-primary); color: var(--text-primary); }
.cal-view-btn.active { background: var(--bg-primary); color: var(--accent); font-weight: 600; box-shadow: var(--shadow-sm); }

/* ── Time grid (week / workweek / day views) ─────────────────── */
.cal-time-grid-wrap {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Header + Allday + Time-Body nutzen alle dasselbe Grid-Template:
     [Gutter] [N × 1fr]
   damit die Spaltengrenzen pixelgenau untereinander bleiben, unabhängig
   von Subpixel-Rundung. --cal-days wird per JS auf .cal-time-grid-wrap
   gesetzt (1/3/5/7 je nach View). scrollbar-gutter:stable auf Header,
   Allday und Time-Scroll reserviert bei persistenten Scrollbars konstant
   Platz. */
.cal-time-grid-wrap {
  --cal-days: 7;
}

.cal-week-header {
  display: grid;
  grid-template-columns: var(--cal-hour-label-width) repeat(var(--cal-days), minmax(0, 1fr));
  border-bottom: 2px solid var(--border);
  background: var(--bg-primary);
  overflow-y: hidden;
  scrollbar-gutter: stable;
}
.cal-time-gutter-head {
  border-right: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
}
/* Kalenderwoche in der leeren oberen linken Ecke des Zeitrasters (Tag/Woche/
   Arbeitswoche) — dezent, keine visuelle Konkurrenz zu den Wochentag-Headern. */
.cal-kw-label {
  font-size: 0.66rem;
  font-weight: 600;
  color: var(--text-tertiary);
  text-align: center;
  line-height: 1.2;
  white-space: nowrap;
}
.cal-week-hd {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 6px 4px;
  border-right: 1px solid var(--border);
  gap: 2px;
  min-width: 0;
}
.cal-week-hd-dow {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
}
.cal-week-hd-num {
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--text-secondary);
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}
.cal-week-hd.is-today .cal-week-hd-dow { color: var(--accent); }
.today-circle { background: var(--accent); color: #fff !important; font-weight: 700; }

/* All-day row – gleiches Grid wie Header & Time-Body. */
.cal-allday-row {
  display: grid;
  grid-template-columns: var(--cal-hour-label-width) repeat(var(--cal-days), minmax(0, 1fr));
  border-bottom: 1px solid var(--border);
  background: var(--bg-primary);
  overflow-y: hidden;
  scrollbar-gutter: stable;
}
.cal-allday-gutter {
  border-right: 1px solid var(--border);
  font-size: 0.62rem;
  color: var(--text-tertiary);
  padding: 4px 6px;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  min-width: 0;
}
.cal-allday-cell {
  border-right: 1px solid var(--border);
  padding: 2px 3px;
  min-height: 26px;
  min-width: 0;
}
.cal-allday-cell .cal-event-bar { margin-bottom: 2px; }

/* Scrollable time body – Höhe wird durch Flex-Container gesteuert.
   scrollbar-gutter:stable hält die Spaltenbreite konstant, unabhängig
   davon ob aktuell gescrollt wird oder nicht. */
.cal-time-scroll {
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-gutter: stable;
}
.cal-time-body {
  display: grid;
  grid-template-columns: var(--cal-hour-label-width) repeat(var(--cal-days), minmax(0, 1fr));
  position: relative;
}

/* Hour labels */
.cal-time-gutter {
  border-right: 1px solid var(--border);
  background: var(--bg-primary);
  position: sticky;
  left: 0;
  z-index: 1;
  min-width: 0;
}
.cal-time-tick {
  height: calc(2 * var(--cal-slot-height)); /* 96px = 2 Slots à 48px = 1 Stunde */
  padding-right: 8px;
  text-align: right;
  font-size: 0.72rem;
  color: var(--text-secondary);
  line-height: 0;
  position: relative;
}

/* Single-day column im Panel (Day-Panel wie Tagesansicht) */
.cal-day-single {
  cursor: default;
  user-select: none;
}

/* Day columns – füllen im übergeordneten Grid (cal-time-body) alle Tag-Tracks
   und spiegeln das Header-Grid pixelgenau wider. */
.cal-day-cols {
  display: grid;
  grid-template-columns: repeat(var(--cal-days), minmax(0, 1fr));
  grid-column: 2 / -1;
  position: relative; /* Ankerpunkt für die Now-Line (volle Breite) */
}
.cal-day-col {
  position: relative;
  border-right: 1px solid var(--border);
  height: calc(48 * var(--cal-slot-height)); /* 48 Slots à 30 Min = 24h = 2304px */
  cursor: default;
  transition: background var(--transition);
  user-select: none;
  min-width: 0;
}
.cal-day-col:hover { background: var(--bg-secondary); }
/* Heutige Spalte im Zeitraster (Tag/3-Tage/Woche/Arbeitswoche, _renderTimeGrid) —
   Punkt 5, Fix 2026-07-18: bewusst KEIN eigener Hintergrund mehr (wirkte wie
   Auswahl/Sperre). Der umkreiste Tag im Spalten-Header (.today-circle) bleibt
   das alleinige "heute"-Signal. Hover faellt auf die generische
   .cal-day-col:hover-Regel zurück (kein Extra-Rule mehr nötig). Monatsansicht
   (.cal-day-today, Zeile 230) ist ein eigener Selektor — bleibt unveraendert. */
.cal-day-col-avail { border-top: 2px solid color-mix(in srgb, var(--teal) 50%, transparent); }
.cal-day-mob-sel { background: var(--accent-light) !important; }
.cal-day-mob-sel .cal-day-num { background: var(--accent); color: #fff; border-radius: 50%; }
.cal-day-avail { position: relative; }
.cal-day-avail::after {
  content: '';
  position: absolute;
  bottom: 4px;
  right: 4px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--teal);
  opacity: 0.6;
  pointer-events: none;
}

/* Ganztägige Sperre – dezenter coral Hintergrund */
.cal-day-full-blocked {
  background: var(--coral-light) !important;
}
/* Zeitliche Sperre – coral Punkt (zusätzlich zum teal-Punkt) */
.cal-day-timed-blocked { position: relative; }
.cal-day-timed-blocked::before {
  content: '';
  position: absolute;
  bottom: 4px;
  right: 12px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--coral);
  opacity: 0.7;
  pointer-events: none;
}

/* Sperren-Block im Zeitraster (Coral) */
.cal-block-range {
  position: absolute;
  left: 0; right: 0;
  overflow: hidden;
  border-left: 3px solid var(--coral);
  z-index: 1;
}
.cal-block-range-bg {
  position: absolute;
  inset: 0;
  background: var(--coral);
  opacity: 0.08;
  pointer-events: none;
}
.cal-block-range-label {
  position: relative;
  display: block;
  padding: 1px 4px;
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--coral);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.3;
}
/* Ganztägige Sperre als Banner über dem Zeitraster */
.cal-day-col-full-blocked {
  background: repeating-linear-gradient(
    -45deg,
    transparent,
    transparent 6px,
    rgba(var(--coral-rgb, 216,90,48), 0.06) 6px,
    rgba(var(--coral-rgb, 216,90,48), 0.06) 12px
  );
}

/* Hour / half-hour grid lines */
.cal-h-line {
  position: absolute;
  left: 0; right: 0;
  border-top: 1px solid var(--border);
  pointer-events: none;
}
.cal-hh-line {
  position: absolute;
  left: 0; right: 0;
  border-top: 1px dashed color-mix(in srgb, var(--border) 60%, transparent);
  pointer-events: none;
}

/* Current-time dashed line */
.cal-now-line {
  position: absolute;
  left: 0; right: 0;
  border-top: 2px dashed var(--cal-now-line-color);
  z-index: 2;
  pointer-events: none;
  transition: top 60s linear;
}
.cal-now-line::before {
  content: '';
  position: absolute;
  left: -4px; top: -5px;
  width: 8px; height: 8px;
  background: var(--cal-now-line-color);
  border-radius: 50%;
}

/* ── View-Crossfade (Schritt 17) ── */
.cal-time-grid-wrap {
  animation: calViewIn 200ms ease both;
}
.cal-grid {
  animation: calViewIn 200ms ease both;
}
@keyframes calViewIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Event blocks in time grid – Outlook-Style */
.cal-event-block {
  position: absolute;
  cursor: pointer;
  left: 2px;
  width: calc(100% - 4px);
  border-radius: var(--cal-event-radius);
  border-left: var(--cal-event-border-width) solid transparent; /* color set inline */
  padding: 3px 6px 3px 8px;
  overflow: hidden;
  cursor: pointer;
  z-index: 1;
  transition: filter var(--transition), box-shadow var(--transition), transform var(--transition);
  box-sizing: border-box;
  animation: calEventIn 150ms ease both;
  /* 🔒 animation-fill-mode:both haelt den Endwert (opacity:1) DAUERHAFT und
     gewinnt in der Kaskade gegen JEDE normale `opacity`-Deklaration auf
     .cal-event-block (Animationen stehen ueber normalen Autoren-Regeln,
     unter !important) -- eine Zustands-Klasse, die diesen Block dimmen soll
     (erledigte Wiedervorlage/Aufgabe, Vorbehalt/abgelehnt/verschoben), darf
     deshalb NIE eine normale `opacity`-Deklaration nutzen, sonst bleibt sie
     wirkungslos. Fix: eigenes `animation-name: calEventInDim*` je Zielwert
     (s. @keyframes weiter unten) -- erbt Dauer/Timing/Fill-Mode von HIER,
     ueberschreibt nur den Endwert. Bug + Fix: Ticket 3.377.2 Nachtrag,
     2026-08-27 (s. modules/calendar.md). */
  /* iOS-Long-Press-Hardening: verhindert, dass der native Callout/Text-
     Auswahl-Long-Press unseren 500ms-Kontextmenü-Timer kapert. */
  -webkit-touch-callout: none;
  user-select: none;
}
.cal-event-block:hover { filter: brightness(0.97); box-shadow: var(--shadow-sm); }

/* ── Event-Type-Varianten (Spec 20260416_1000) ────────────────────────
   Gilt für .cal-event-block (Time-Grid) und .cal-event-bar (All-day/Month).
   Overrides color/background basierend auf data-type. */
/* Event-Type-Styling: Farben kommen via inline --cal-color (aus User-Picker).
   CSS steuert nur Rahmen-Stil und Opacity. */
.cal-event-block[data-type="followup"],
.cal-event-bar[data-type="followup"] {
  border-left: 3px solid var(--cal-color, var(--user-followup-color)) !important;
}
.cal-event-block[data-type="todo"],
.cal-event-bar[data-type="todo"] {
  border-left: 3px solid var(--cal-color, var(--user-todo-color)) !important;
}
.cal-event-block[data-type="todo"].completed,
.cal-event-bar[data-type="todo"].completed {
  opacity: 0.5;
  text-decoration: line-through;
}
/* .cal-event-bar hat keine Entry-Animation -- ihre `opacity` oben greift
   normal. .cal-event-block trägt calEventIn (fill-mode:both) und braucht
   den animation-name-Override, s. Kommentar bei .cal-event-block oben. */
.cal-event-block[data-type="todo"].completed {
  animation-name: calEventInDim50;
}
/* Verfügbarkeit: harmonisiert mit cal-avail-block (solid links, dashed rest).
   Background kommt via inline --cal-bg (getEventColor), kein Override nötig. */
.cal-event-block[data-type="availability"],
.cal-event-bar[data-type="availability"] {
  border-top: 1px dashed color-mix(in srgb, var(--cal-color, var(--user-availability-color)) 40%, transparent) !important;
  border-right: 1px dashed color-mix(in srgb, var(--cal-color, var(--user-availability-color)) 40%, transparent) !important;
  border-bottom: 1px dashed color-mix(in srgb, var(--cal-color, var(--user-availability-color)) 40%, transparent) !important;
}
/* Ausgebucht: voller Hintergrund, kräftigerer Rand — Spec 20260416_1400 */
.cal-event-block[data-type="availability"].is-fully-booked,
.cal-event-bar[data-type="availability"].is-fully-booked {
  background: color-mix(in srgb, var(--cal-color) 25%, var(--bg-primary));
  border-style: solid !important;
  opacity: 1;
}

/* Auslastungs-Balken (Spec 20260416_1400 Schritt 5) */
.cal-avail-util {
  display: flex;
  align-items: center;
  gap: .35rem;
  margin-top: 2px;
  font-size: .65rem;
  font-weight: 500;
  color: var(--rose);
}
.cal-avail-util-bar {
  position: relative;
  flex: 1;
  height: 4px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--rose) 20%, transparent);
  overflow: hidden;
}
.cal-avail-util-bar-fill {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  background: var(--rose);
  border-radius: 2px;
  transition: width var(--transition);
}
.cal-avail-util-label { flex-shrink: 0; white-space: nowrap; }

/* ── Typ-Selector im Event-Formular (Spec 20260416_1000, Schritt 1) ──── */
.event-type-selector {
  display: flex;
  gap: 0.35rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.event-type-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.6rem;
  border-radius: var(--radius-xl);
  border: 1.5px solid var(--border);
  background: var(--bg-secondary);
  font-size: 0.75rem;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all var(--transition);
  font-family: inherit;
}
.event-type-chip:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
.event-type-chip.active[data-type="event"]        { border-color: var(--accent); background: var(--accent-light); color: var(--accent); font-weight: 600; }
.event-type-chip.active[data-type="followup"]     { border-color: var(--amber);  background: var(--amber-light);  color: var(--amber);  font-weight: 600; }
.event-type-chip.active[data-type="todo"]         { border-color: var(--teal);   background: var(--teal-light);   color: var(--teal);   font-weight: 600; }
.event-type-chip.active[data-type="availability"] { border-color: var(--rose);   background: var(--rose-light);   color: var(--rose);   font-weight: 600; }
@keyframes calEventIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* Gedaempfte Varianten von calEventIn fuer Zustands-Klassen auf
   .cal-event-block (Vorbehalt/erledigte Aufgabe: .5, abgelehnt/verschoben:
   .55, erledigte Wiedervorlage: .78) -- via `animation-name`-Override an der
   jeweiligen Zustands-Klasse referenziert, s. Kommentar bei .cal-event-block
   weiter oben. NICHT durch eine normale `opacity`-Deklaration ersetzen. */
@keyframes calEventInDim50 {
  from { opacity: 0;  }
  to   { opacity: .5; }
}
@keyframes calEventInDim55 {
  from { opacity: 0;   }
  to   { opacity: .55; }
}
@keyframes calEventInDim78 {
  from { opacity: 0;   }
  to   { opacity: .78; }
}

/* ── Show-As Status-Varianten ──────────────────────────────────
   Standard: .show-as-busy = wie bisher (voller heller Hintergrund + farbiger Balken links).
   Alle Varianten behalten die Event-Farbe als Hintergrund, nur der linke
   Balken + Transparenz variiert. */

/* Verfügbar: weißer linker Balken mit Rahmen, Farbe sonst beibehalten */
.cal-event-block.show-as-free {
  border-left-color: var(--bg-primary) !important;
  border-left-style: solid !important;
  box-shadow: inset 3px 0 0 0 var(--border);
}

/* Anderswo arbeiten: Punkt-Pattern als Hintergrund */
.cal-event-block.show-as-working-elsewhere {
  background-image: radial-gradient(
    color-mix(in srgb, currentColor 30%, transparent) 1px,
    transparent 1.5px
  );
  background-size: 6px 6px;
}

/* Mit Vorbehalt: Balken bleibt in voller Stärke, Eintrag wird 50% ausgeblendet
   damit man sieht, dass er nicht fest gebucht ist. */
.cal-event-block.show-as-tentative {
  opacity: .5;
}
/* .cal-event-block traegt calEventIn (fill-mode:both) -- die `opacity` oben
   ist dort strukturell wirkungslos, s. Kommentar bei .cal-event-block.
   animation-name-Override haelt den gedaempften Endwert. */
.cal-event-block.show-as-tentative {
  animation-name: calEventInDim50;
}
/* Auch in Event-Bars (Monats/All-Day-Zeile) -- .cal-event-bar hat keine
   Entry-Animation, `opacity` greift dort normal. */
.cal-event-bar.show-as-tentative {
  opacity: .5;
}

/* Abwesend: roter linker Balken, Farbe sonst beibehalten */
.cal-event-block.show-as-oof {
  border-left-color: var(--coral) !important;
}
/* Auch in Event-Bars (Monats/All-Day-Zeile) */
.cal-event-bar.show-as-oof {
  border-left-color: var(--coral) !important;
}
.cal-event-bar.show-as-free {
  border-left-color: var(--bg-primary) !important;
  box-shadow: inset 3px 0 0 0 var(--border);
}
/* All-Day-Chips: Show-As Varianten */
.cal-allday-chip.show-as-tentative { opacity: .5; }
.cal-allday-chip.show-as-oof { background: var(--coral) !important; }
.cal-allday-chip.show-as-free { opacity: .7; border: 1px solid var(--border); }

/* Ganztags + Abwesend: Spalte im Zeitraster leicht rot einfärben */
.cal-day-col.cal-day-col-oof {
  background: color-mix(in srgb, var(--coral) 6%, var(--bg-primary));
}
.cal-allday-cell.cal-allday-cell-oof {
  background: color-mix(in srgb, var(--coral) 8%, var(--bg-primary));
}

/* Resize handle – appears on hover at bottom of event block */
.cal-event-resize-handle {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  height: 8px;
  cursor: s-resize;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity var(--transition);
  z-index: 2;
}
.cal-event-resize-handle::after {
  content: '';
  display: block;
  width: 20px;
  height: 3px;
  border-radius: 2px;
  background: rgba(0,0,0,0.2);
}
.cal-event-block:hover .cal-event-resize-handle { opacity: 1; }

/* Top-edge resize handle – mirrors bottom handle, changes start_at */
.cal-event-resize-handle--top {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 8px;
  cursor: n-resize;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity var(--transition);
  z-index: 2;
}
.cal-event-resize-handle--top::after {
  content: '';
  display: block;
  width: 20px;
  height: 3px;
  border-radius: 2px;
  background: rgba(0,0,0,0.2);
}
.cal-event-block:hover .cal-event-resize-handle--top { opacity: 1; }

/* Read-only/fremd-organisierte Event-Bloecke (Drag-Sperre, Grid-Kontextmenü-
   Spec Aufgabe 1) — Klick oeffnet weiterhin den Flyout (Cursor bleibt
   "pointer", keine eigene Regel nötig). Resize-Handles werden serverseitig
   gar nicht gerendert; diese Klasse ist der greppable Marker + Defense-in-
   Depth falls doch mal ein Handle in den DOM rutscht. */
.cal-event-block--readonly .cal-event-resize-handle,
.cal-event-block--readonly .cal-event-resize-handle--top {
  display: none !important;
}

/* Touch: larger hit-areas on coarse-pointer devices */
@media (pointer: coarse) {
  .cal-event-resize-handle,
  .cal-event-resize-handle--top {
    height: 14px;
    opacity: 0.6;
  }
}
.cal-event-block-title {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cal-et-icon {
  flex-shrink: 0;
  vertical-align: -1px;
  color: var(--cal-color, currentColor);
}
.cal-event-block-time {
  font-size: 0.75rem;
  color: var(--text-secondary);
  line-height: 1.3;
}
.cal-event-block-loc {
  font-size: 0.72rem;
  color: var(--text-tertiary);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Availability window blocks in time grid – visuell identisch mit
   .cal-event-block[data-type="availability"] (dashed border, abgerundet) */
.cal-avail-block {
  position: absolute;
  cursor: default;
  pointer-events: none; /* click-through: Grid-Handler darunter soll Drag/Create empfangen */
  left: 2px; right: 2px;
  z-index: 0;
  border-left: var(--cal-event-border-width) solid transparent;
  border-top: 1px dashed transparent;
  border-bottom: 1px dashed transparent;
  border-right: 1px dashed transparent;
  border-radius: var(--cal-event-radius, 6px);
  padding: 2px 6px 2px 8px;
  overflow: hidden;
  box-sizing: border-box;
}
.cal-avail-block-bg {
  position: absolute;
  inset: 0;
  opacity: 0.12;
  pointer-events: none;
}
.cal-avail-block-label {
  position: relative;
  display: block;
  font-size: 0.64rem;
  font-weight: 600;
  padding: 2px 18px 0 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.3;
  pointer-events: auto; /* re-enable: Klick auf Label öffnet Avail-Panel */
  cursor: pointer;
}
.cal-avail-block-del {
  position: absolute;
  top: 1px; right: 2px;
  pointer-events: all; /* re-enable over pointer-events:none parent */
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1;
  padding: 1px 3px;
  border-radius: 2px;
  opacity: 0.55;
  transition: opacity var(--transition), background var(--transition);
}
.cal-avail-block-del:hover { opacity: 1; background: rgba(0,0,0,0.08); }
.cal-avail-block-blocked .cal-avail-block-bg { opacity: 0.08; }
.cal-avail-block-blocked .cal-avail-block-label { text-decoration: line-through; opacity: 0.7; }

/* ── Event Flyout (Outlook-Style Quick-Preview) ─────────────── */
/* Selektion in der Time-Grid (statt Auto-Create) */
.cal-selection {
  position: absolute;
  left: 2px;
  right: 2px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  border: 1px dashed var(--accent);
  border-radius: var(--radius-sm);
  pointer-events: none;
  z-index: 5;
}

.cal-flyout {
  position: fixed;
  z-index: 450;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  width: var(--cal-flyout-width);
  max-width: calc(100vw - 16px);
  animation: calFlyoutIn 150ms ease forwards;
  overflow: hidden;
  /* Höhenbegrenzung + eigener Scroll (Ticket 3.268, Muster aus Ticket 3.255
     Kontextmenü) — vorher konnte das Flyout bei vielen Teilnehmern unten aus
     dem Viewport laufen, der untere Teil (Video-Link, Aktionen) war dann gar
     nicht erreichbar. Header (Titel) bleibt fix sichtbar, nur .cal-flyout-body
     scrollt (s. dort) — Flex-Column-Split, kein position:sticky (keine
     Vorfahren-Padding-Fallstricke). Fallback-dann-dvh-Paar wie im
     Board-Mobile-/Context-Menu-Pattern: eine unbekannte Einheit macht die
     GESAMTE Deklaration ungültig, die Kaskade fällt dann auf die vh-Zeile
     zurück. */
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 16px);
  max-height: calc(100dvh - 16px);
}
@keyframes calFlyoutIn {
  from { opacity: 0; transform: scale(0.95); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes calFlyoutBottomIn {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}
/* Ticket 3.389: `animation-fill-mode` haelt den Endwert (opacity:1 bzw. die
   Bottom-Sheet-Position) dauerhaft ueber die Kaskade -- wird das Popover
   waehrend der laufenden 150/250ms-Animation neu gezeichnet (zweistufiger
   RSVP-Antwort-Ablauf, s. calendar/_flyout.js), kann es auf einem
   Zwischenwert stehen bleiben. `.cal-flyout--settled` wird per JS erst NACH
   `animationend` gesetzt (_flyout.js) und raeumt die Animation komplett aus
   dem Cascade -- ein spaeteres Neuzeichnen hat dann nichts mehr, auf dem es
   sitzen koennte. Zwei-Klassen-Selektor gewinnt per Spezifitaet gegen die
   Basisregel UND die @media-Bottom-Sheet-Variante unten, unabhaengig von
   der Quellreihenfolge (frontend.md "Media-Query erhoeht die Spezifitaet
   NICHT"). */
.cal-flyout.cal-flyout--settled { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .cal-flyout,
  .cal-event-block,
  .cal-time-grid-wrap,
  .cal-grid { animation: none; }
}
.cal-flyout-header {
  display: flex;
  align-items: flex-start;
  padding: 0.875rem 1rem 0.75rem;
  border-bottom: 1px solid var(--border);
  gap: 0.625rem;
  /* Bleibt fix sichtbar, wenn .cal-flyout-body wegen Höhenbegrenzung scrollt
     (Ticket 3.268) — Flex-Item darf im column-Layout des Elternelements nicht
     schrumpfen. */
  flex-shrink: 0;
}
.cal-source-icon {
  flex: 0 0 18px;
  width: 18px; height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 2px;
}
.cal-flyout-title-wrap { flex: 1; min-width: 0; }
.cal-flyout-title {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cal-flyout-location {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cal-flyout-close {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  padding: 2px;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  transition: color var(--transition), background var(--transition);
}
.cal-flyout-close:hover { color: var(--text-primary); background: var(--bg-secondary); }
.cal-flyout-body {
  padding: 0.75rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  /* Eigener Scrollbereich innerhalb der Höhenbegrenzung von .cal-flyout
     (Ticket 3.268) — min-height:0 ist Pflicht, sonst wächst ein Flex-Item in
     einer column-Achse per Default auf seine Inhaltsgröße (min-height:auto)
     und overflow-y:auto greift nie. overscroll-behavior:contain verhindert,
     dass ein durchscrollter Flyout die Seite dahinter mitscrollt (wie beim
     Kontextmenü-Muster aus Ticket 3.255). */
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.cal-flyout-row {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  font-size: 0.875rem;
  color: var(--text-primary);
}
.cal-flyout-row svg { flex-shrink: 0; margin-top: 2px; color: var(--text-tertiary); }
.cal-flyout-row-sub { color: var(--text-secondary); font-size: 0.8125rem; }
.cal-flyout-desc {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.cal-flyout-description-text {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  color: var(--text-secondary);
  font-size: 0.85rem;
  line-height: 1.35;
  white-space: pre-wrap;
}
.cal-flyout-footer {
  padding: 0.625rem 1rem 0.875rem;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.cal-flyout-delete {
  margin-left: auto;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.5rem;
  border-radius: var(--radius-sm);
  color: var(--coral);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition);
}
.cal-flyout-delete:hover { background: var(--danger-light); }

/* Attendees im Flyout + RSVP-Status */
.cal-flyout-attendees-list {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  flex: 1;
  min-width: 0;
}
.cal-flyout-attendee-row {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
}
.cal-flyout-attendee-status {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  margin-top: 1px;
}
.cal-flyout-attendee-status--accepted  { background: var(--teal); }
.cal-flyout-attendee-status--declined  { background: var(--coral); }
.cal-flyout-attendee-status--tentative { background: var(--amber); }
.cal-flyout-attendee-status--pending   { background: var(--text-tertiary); }
.cal-flyout-attendee-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cal-flyout-attendee-text > div:first-child {
  font-size: 0.875rem;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Dezentes "Organisator"-Label neben dem Namen in der Read-only-Teilnehmerliste
   (_showEventPanel: Organisator wird IMMER vorangestellt, auch ohne eigene
   Attendee-Row — Fix 2026-07-11). */
.cal-attendee-organizer-tag {
  margin-left: 0.375rem;
  font-size: 0.6875rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--text-tertiary);
}

/* Dezente Zusatzzeile(n) unter einem Teilnehmer bei Ablehnungs-Begruendung
   (response_comment) oder Alternativ-Terminvorschlag (counter_start/_end/
   _comment) — Migration 339, Spec 20260713. Externer Gast-Freitext, daher
   bewusst zurückhaltend (text-tertiary, klein) statt visuell betont. */
.cal-attendee-response-extra {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin-top: 0.25rem;
}
.cal-attendee-response-line {
  font-size: 0.75rem;
  line-height: 1.35;
  color: var(--text-tertiary);
}

/* RSVP-Buttons für eingegangene Einladungen */
.cal-flyout-rsvp-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.cal-flyout-rsvp-buttons {
  display: flex;
  gap: 0.375rem;
  flex-wrap: wrap;
}
/* Die einzelnen Buttons selbst rendert seit Ticket 3.388.1 die geteilte
   Komponente <ds-rsvp-buttons> (app/assets/js/components/ds-rsvp-buttons.js,
   CSS .ds-rsvp-btn* in _core.css) – EINE Darstellung fuer Kalender-Flyout,
   Kalender-Panel UND Mail-Anhang-Vorschau statt der vormals hier definierten,
   inzwischen entfernten Alt-Button-Klassen-Familie. Dieser Wrapper-Div bleibt als
   Abstands-Container bestehen, .cal-flyout-rsvp-buttons liefert dafuer
   dieselben display:flex/gap/flex-wrap-Werte, die <ds-rsvp-buttons> intern
   ohnehin nochmal setzt (redundant, aber unschaedlich). */

/* ── RSVP-Block im Event-Editor-Panel (Fix #5, 2026-06-10) ─────────── */
/* Wiederverwendet <ds-rsvp-buttons> (s.o.); eigener Wrapper für Abstände */
.cal-panel-rsvp-block {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .75rem 1rem;
  background: var(--accent-light);
  border-radius: var(--radius-sm);
  margin: .25rem .75rem;
}
/* Breiten-Abgleich mit .ds-info-box im Read-only-Termin-Panel (Ticket 3.296.4):
   .cal-event-panel-body ist eine Flex-Column (align-items:stretch) -- .ds-info-box
   hat dort keinen horizontalen Margin und fuellt die Spalte deshalb voll aus,
   waehrend .cal-panel-rsvp-block ueberall sonst (Editor-Panel, direktes Kind von
   .cal-editor-form -- ein normaler Block-Container mit eigenem Padding) bewusst
   seitlichen Margin traegt. Nur im Read-only-Panel-Kontext wird der Margin
   entfernt, damit beide Boxen exakt gleich breit sind -- der Editor-Panel-
   Kontext bleibt unveraendert. */
.cal-event-panel-body .cal-panel-rsvp-block {
  margin-left: 0;
  margin-right: 0;
}
.cal-panel-rsvp-label {
  display: flex;
  align-items: center;
  gap: .375rem;
  font-size: .8125rem;
  color: var(--text-secondary);
}
.cal-panel-rsvp-label svg { color: var(--accent); flex-shrink: 0; }

/* Dezente Info-Zeile für einen bereits abgeschickten Alternativ-Termin-Vorschlag
   (iTIP-COUNTER, ev.counter_start/_end/_comment) — unter den RSVP-Buttons im
   .cal-panel-rsvp-block, Punkt 2 2026-07-11. Klick auf die Zeile toggelt den
   Kommentar (falls vorhanden). Geteilte Render-Hilfe _renderCounterInfoRow()
   (P-5), genutzt im Read-only-Panel UND im Editor-Panel (isInvitePanel). */
.cal-panel-counter-info {
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
.cal-panel-counter-info-toggle {
  display: flex;
  align-items: flex-start;
  gap: .375rem;
  width: 100%;
  padding: 0;
  border: none;
  background: none;
  font-family: inherit;
  font-size: .75rem;
  line-height: 1.35;
  color: var(--text-tertiary);
  text-align: left;
  cursor: pointer;
  transition: color var(--transition);
}
.cal-panel-counter-info-toggle:hover:not(:disabled) { color: var(--text-secondary); }
.cal-panel-counter-info-toggle:disabled { cursor: default; }
.cal-panel-counter-info-toggle svg { flex-shrink: 0; margin-top: .0625rem; }
.cal-panel-counter-info-toggle span { flex: 1; }
.cal-panel-counter-info-chevron { flex-shrink: 0; margin-top: .0625rem; transition: transform var(--transition); }
.cal-panel-counter-info-chevron.is-open { transform: rotate(180deg); }
.cal-panel-counter-info-comment {
  padding: 0 0 0 1.1875rem;
  font-size: .75rem;
}

/* Sync-Zustands-Indikator ganz oben im Read-only-Termin-Panel (_showEventPanel,
   _renderPanelSyncStatus, 2026-07-17) — zeigt ob ein einem Kalender zugeordneter
   Termin dort tatsächlich existiert (ev.provider_synced). Basis .ds-info-box/
   --amber/--teal (aus _invoicing.css, app-weit verfuegbar) — hier nur das
   Icon in der teal-Variante ausrichten. */
.cal-panel-sync-status-icon {
  vertical-align: -1px;
  margin-right: .3rem;
}

/* Coral-Fehlerbanner für einen persistierten Sync-Fehlschlag
   (calendar_events.sync_error) -- geteilt zwischen dem Buchungs-Panel
   (_renderBookingDetail) und dem Read-only-Termin-Panel
   (_renderPanelSyncStatus), gerendert über _renderSyncErrorBanner()
   (Spec 20260803 S5, P-5). Neue, calendar-lokale Klasse statt einer
   Erweiterung der app-weiten .ds-info-box-Familie (kein --coral-Modifier
   dort vorhanden) -- Umfang dieser Aenderung ist auf _calendar.css begrenzt. */
.cal-sync-error-banner {
  background: var(--coral-light);
  border: 1px solid var(--coral);
  border-radius: var(--radius-md);
  padding: .65rem .8rem;
  margin-bottom: .75rem;
  font-size: .82rem;
}
.cal-sync-error-banner-title {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin-bottom: .25rem;
  font-weight: 700;
  color: var(--coral);
}
.cal-sync-error-banner-detail {
  color: var(--text-primary);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  word-break: break-word;
}

/* Prominenter Gegenvorschlag-Hinweis oben im Read-only-Termin-Panel (Punkt F.2,
   Spec 20260713) — JEDER Gast mit eigenem Alternativ-Terminvorschlag, nicht zu
   verwechseln mit .cal-panel-counter-info (das ist MEIN EIGENER, an einen
   fremd-organisierten Termin gesendeter Vorschlag). Basis .ds-info-box/--amber
   (aus _invoicing.css, app-weit in components.css verfuegbar) — hier nur
   Abstände für mehrere Vorschläge + den optionalen Kommentar. */
.cal-panel-counter-hint {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.cal-panel-counter-hint-row + .cal-panel-counter-hint-row {
  padding-top: .5rem;
  border-top: 1px solid var(--border);
}
.cal-panel-counter-hint-comment {
  margin-top: .25rem;
  color: var(--text-secondary);
  font-size: .8125rem;
}
/* "Termin uebernehmen"-Button je Vorschlag (Punkt 3, Spec 20260713) — nur im
   Read-only-Panel (_showEventPanel via canAdoptCounter), nicht im Editor. */
.cal-panel-counter-hint-actions {
  margin-top: .375rem;
}

/* Read-only Teilnehmerliste im Editor-Panel bei fremd-organisierten Events
   (Spec 20260710, F-6/S3) — wiederverwendet .cal-flyout-attendee-*-Familie,
   nur vertikaler Ausgleich zum .ds-form-row-icon (margin-top:.5rem). */
.cal-panel-attendees-readonly {
  padding-top: .375rem;
}

/* Read-only Info-Badge in der Toolbar des Split-Screen-Read-only-Termin-Panels
   (_showEventPanel: NUR noch Termin-Typ, seit Fix 2026-07-11 Punkt 4 — sehen
   aus wie .ds-toolbar-item, ist aber nicht interaktiv (keine Aktion, kein
   Dropdown). Beschäftigt-Status + Kategorie sind inzwischen klickbare
   .ds-toolbar-item-Dropdowns ohne diesen Modifier (_openPanelShowAsDropdown/
   _openPanelCategoryDropdown). Modifier statt eigener Klasse, damit
   Hoehe/Padding/Border/Font 1:1 mit den echten Toolbar-Buttons uebereinstimmen. */
.cal-panel-toolbar-badge {
  cursor: default;
}
.cal-panel-toolbar-badge:hover {
  background: var(--bg-primary);
}

/* Mobile-Toolbar im Read-only-Termin-Panel (_showEventPanel, Nutzer-Feedback #2,
   2026-07-18) — garantiert EINE Zeile: nur die primaere Kontext-Aktion (Bearbeiten /
   Alternativ-Termin) + ein Overflow-Button (⋯, oeffnet _openPanelOverflowMenu via
   ContextMenu) + optional Loeschen bleiben sichtbar, alle uebrigen Aktionen
   (Beschaeftigt/Kategorie/Kalender/Wiedervorlage/Verlauf/Zurueck) wandern ins
   Overflow-Menue. `.ds-panel-toolbar` selbst hat `flex-wrap:wrap` (Desktop-Default)
   — hier explizit ueberschrieben, da diese Variante nur bei isMobile() gerendert wird. */
.cal-panel-toolbar-mobile {
  flex-wrap: nowrap;
}
/* Overflow-/Loeschen-Button behalten ihre feste Groesse — nur die primaere
   Kontext-Aktion darf schrumpfen + truncaten (Sicherheitsnetz auf sehr
   schmalen Geraeten, in der Praxis passen alle drei Items locker in eine
   Zeile ab ~320px Viewport-Breite). */
.cal-panel-toolbar-mobile .ds-toolbar-item:not(.ds-toolbar-item--primary) {
  flex-shrink: 0;
}
.cal-panel-toolbar-mobile .ds-toolbar-item--primary {
  min-width: 0;
  flex-shrink: 1;
}
.cal-panel-toolbar-mobile .ds-toolbar-item--primary span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Editor-Overlay (Outlook-Stil) ───────────────────────────── */
.cal-editor-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  animation: calEditorIn 150ms ease both;
}
@keyframes calEditorIn { from { opacity: 0 } to { opacity: 1 } }
@media (prefers-reduced-motion: reduce) {
  .cal-editor-backdrop { animation: none; }
}
.cal-editor-overlay {
  width: min(1100px, 96vw);
  max-height: 90vh;
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.cal-editor-toolbar {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.625rem 0.875rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
}
.cal-editor-toolbar .cal-editor-spacer { flex: 1; }
.cal-editor-body {
  display: flex;
  flex: 1;
  min-height: 0;
}
.cal-editor-form {
  flex: 0 0 60%;
  padding: 1.25rem 1.5rem;
  overflow-y: auto;
}
.cal-editor-preview {
  flex: 1;
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Right-Panel-Tabbar: Tagesansicht | Kommentare ───────────────────── */
.cal-editor-right-tabs {
  display: flex;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
  flex-shrink: 0;
}
.cal-editor-right-tab {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.6rem 0.75rem;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: color var(--transition), border-color var(--transition);
}
.cal-editor-right-tab:hover:not(:disabled) {
  color: var(--text-primary);
}
.cal-editor-right-tab.is-active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.cal-editor-right-tab:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.cal-editor-right-tab-badge {
  background: var(--accent);
  color: #fff;
  font-size: 0.65rem;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 999px;
  line-height: 1.4;
  min-width: 18px;
  text-align: center;
}
.cal-editor-right-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: auto;
}
.cal-editor-preview-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--text-primary);
}
.cal-editor-preview-grid {
  flex: 1;
  overflow-y: auto;
  position: relative;
  background: var(--bg-primary);
}
.cal-editor-preview-hour {
  position: absolute;
  left: 0; right: 0;
  height: var(--cal-slot-height, 48px);
  border-top: 1px solid var(--border);
  font-size: 0.7rem;
  color: var(--text-tertiary);
  padding: 2px 6px;
  box-sizing: border-box;
  pointer-events: none;
}
.cal-editor-preview-half-hour {
  position: absolute;
  left: 0; right: 0;
  border-top: 1px dashed var(--border);
  opacity: .4;
  pointer-events: none;
}
.cal-editor-preview-event {
  position: absolute;
  left: 44px;
  right: 8px;
  border-radius: var(--radius-sm);
  padding: 2px 6px;
  font-size: 0.7rem;
  background: var(--bg-secondary);
  border-left: 3px solid var(--border);
  color: var(--text-primary);
  pointer-events: none;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.cal-editor-preview-event.is-current,
.cal-editor-preview-event.is-live {
  background: color-mix(in srgb, var(--accent) 22%, var(--bg-primary));
  border-left: 3px solid var(--accent);
  color: var(--text-primary);
  font-weight: 600;
  opacity: 1;
  box-shadow: 0 1px 4px rgba(0,0,0,.12);
  pointer-events: auto;
  z-index: 2;
  cursor: grab;
}
.cal-editor-preview-event.is-current.is-dragging {
  cursor: grabbing;
  box-shadow: var(--shadow-md);
}
.cal-editor-preview-event .resize-handle {
  position: absolute;
  left: 0; right: 0;
  height: 6px;
  cursor: ns-resize;
}
.cal-editor-preview-event .resize-handle.top    { top: 0; }
.cal-editor-preview-event .resize-handle.bottom { bottom: 0; }

/* ── ds-attendee-picker (Spec F2) ─────────────────────── */
.ds-attendee-picker {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .3rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .5rem .75rem;
  min-height: 42px;
  cursor: text;
  background: var(--bg-primary);
}
.ds-attendee-picker:focus-within { border-color: var(--accent); }

.attendee-settings-wrap { position: relative; display: inline-flex; }
.attendee-settings-btn {
  display: inline-flex;
  align-items: center;
  gap: .15rem;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-secondary);
  padding: 2px 4px;
  border-radius: var(--radius-sm);
}
.attendee-settings-btn:hover { background: var(--bg-secondary); color: var(--text-primary); }

.attendee-settings-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  min-width: 280px;
  padding: .35rem 0;
  z-index: 201;
}
.attendee-settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .5rem 1rem;
  font-size: .88rem;
  color: var(--text-primary);
  gap: 1rem;
}
.attendee-settings-divider { height: 1px; background: var(--border); margin: .25rem 0; }
.attendee-settings-action {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .5rem 1rem;
  cursor: pointer;
  font-size: .88rem;
  color: var(--accent);
}
.attendee-settings-action:hover { background: var(--accent-light); }

.attendee-chip {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: 2px 8px 2px 10px;
  border-radius: 999px;
  background: var(--accent-light);
  color: var(--accent);
  font-size: .82rem;
  white-space: nowrap;
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.attendee-chip.is-optional {
  background: var(--bg-secondary);
  color: var(--text-secondary);
  border: 1px solid var(--border);
}
.attendee-chip-remove {
  background: none; border: none; cursor: pointer;
  color: inherit; padding: 0 0 0 4px; line-height: 1;
  opacity: .6; font-size: 1rem;
}
.attendee-chip-remove:hover { opacity: 1; }
.attendee-chip-status {
  font-size: .7rem;
  line-height: 1;
  margin-left: 2px;
  font-weight: 700;
}
.attendee-chip-status.accepted  { color: var(--teal); }
.attendee-chip-status.pending   { color: var(--text-tertiary); }
.attendee-chip-status.declined  { color: var(--coral); }
.attendee-chip-status.tentative { color: var(--amber); }

.attendee-status-summary {
  font-size: .78rem;
  color: var(--text-secondary);
  padding: .3rem .25rem .1rem;
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
}

.attendee-input-wrap { position: relative; flex: 1 1 140px; min-width: 140px; }
.attendee-input {
  width: 100%;
  border: none;
  outline: none;
  background: transparent;
  color: var(--text-primary);
  font-size: .9rem;
  padding: 2px 0;
  font-family: inherit;
  min-height: 24px;
}

.attendee-suggest-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  min-width: 260px;
  max-height: 220px;
  overflow-y: auto;
  z-index: 200;
}
.attendee-suggest-item {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .45rem .75rem;
  cursor: pointer;
}
.attendee-suggest-item:hover,
.attendee-suggest-item.is-active { background: var(--accent-light); }
.attendee-suggest-avatar {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--bg-secondary);
  color: var(--text-secondary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: .75rem;
  font-weight: 600;
  flex-shrink: 0;
  overflow: hidden;
}
.attendee-suggest-avatar img { width: 100%; height: 100%; object-fit: cover; }
.attendee-suggest-name { font-size: .85rem; color: var(--text-primary); }
.attendee-suggest-email { font-size: .75rem; color: var(--text-tertiary); }

/* ── Kalender-Sidebar (Spec 1300) ─────────────────────── */
/* Host-Element: füllt die von cal-page-shell per flex-stretch zugewiesene Höhe.  */
/* Nur ab 901px aktiv — Mobile-Hide greift auf .ds-cal-sidebar (aside), nicht auf  */
/* das Host-Element; trotzdem in min-width kapseln um Konflikte zu vermeiden.       */
@media (min-width: 901px) {
  ds-cal-sidebar {
    display: flex;
    flex-direction: column;
    min-height: 0;
  }
}
.ds-cal-sidebar {
  width: 220px;
  flex-shrink: 0;
  background: var(--bg-secondary);
  display: flex;
  flex-direction: column;
  /* overflow-y gehört auf .cal-sidebar-mode-body — aside bekommt kein eigenes   */
  /* Scroll mehr, sonst doppelter Scrollbalken + margin-top:auto resolved zu 0.  */
  transition: width var(--transition-slow);
  flex: 1 1 auto;
  min-height: 0;
  position: relative; /* Containing Block fuer den Ziehgriff, Ticket 3.220.2 */
}
.ds-cal-sidebar.is-collapsed { width: 0; overflow: hidden; padding: 0; }
.cal-sidebar-header {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .75rem .75rem .5rem;
}
.cal-sidebar-header-label {
  font-size: .8rem;
  font-weight: 700;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .05em;
  flex: 1;
  text-align: left;
}

/* Toggle in der Gutter-Head-Zelle */
.btn-cal-sidebar-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  cursor: pointer;
  padding: 0;
  transition: background var(--transition), color var(--transition);
}
.btn-cal-sidebar-toggle:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}
.cal-sidebar-group-label {
  font-size: .7rem;
  font-weight: 700;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: .75rem .75rem .25rem;
}
.cal-sidebar-group-header {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .6rem .75rem .2rem;
}
.cal-sidebar-provider-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
}
.cal-sidebar-provider-initials {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: .6rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
.cal-sidebar-group-email {
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-secondary);
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cal-sidebar-gear {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  color: var(--text-tertiary);
  opacity: 0;
  transition: opacity var(--transition);
  border-radius: var(--radius-sm);
  padding: 2px;
  text-decoration: none;
}
.cal-sidebar-group-header:hover .cal-sidebar-gear { opacity: 1; }
.cal-sidebar-gear:hover {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}
.cal-sidebar-cal-row {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .3rem .75rem;
  cursor: pointer;
  border-radius: var(--radius-sm);
  margin: 0 .4rem;
}
.cal-sidebar-cal-row:hover { background: var(--bg-tertiary); }
.cal-sidebar-color-dot {
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 2px solid transparent;
  flex-shrink: 0;
  cursor: pointer;
  padding: 0;
  background: none;
}
.cal-sidebar-color-dot:hover { filter: brightness(.85); transform: scale(1.15); }
.cal-sidebar-cal-label {
  font-size: .85rem;
  color: var(--text-primary);
  flex: 1;
  user-select: none;
}
.cal-sidebar-cal-label.is-crossed-out {
  color: var(--text-tertiary);
  text-decoration: line-through;
}

/* ── Sidebar: Modus-Umschalter (B1, 2026-06-10) ─────────────────── */
/* Zwei Icon-Buttons oben im Sidebar-Header — macOS-artig.          */
.cal-sidebar-modeswitch {
  display: flex;
  align-items: center;
  gap: .25rem;
  flex: 1;
}
.cal-sidebar-mode-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  padding: 0;
  transition: background var(--transition), color var(--transition);
  flex-shrink: 0;
}
.cal-sidebar-mode-btn:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}
.cal-sidebar-mode-btn.is-active {
  color: var(--accent);
  background: var(--accent-light);
}
/* B1: Amber-Dot auf Mail-Icon wenn offene Einladungen > 0 */
.cal-sidebar-mode-dot {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--amber);
  border: 1.5px solid var(--bg-secondary);
  pointer-events: none;
}

/* ── Sidebar: Modus-Body-Wrapper ────────────────────────────────── */
/* Gemeinsamer flex-Wrapper für den scrollbaren Inhalt je Modus.   */
.cal-sidebar-mode-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* ── Sidebar: RSVP-Tab-Leiste (B3, 2026-06-10) ──────────────────── */
/* Nutzt globales .tab-filter-Pattern; leicht kompakter für Sidebar. */
.cal-sidebar-invite-tabs {
  margin: .5rem .5rem .25rem;
  gap: 0;
}
.cal-sidebar-invite-tabs .tab-filter-btn {
  flex: 1;
  font-size: .78rem;
  padding: .3rem .5rem;
  min-height: 30px;
  justify-content: center;
}

/* ── Sidebar: Einladungs-Liste (B3, 2026-06-10) ─────────────────── */
.cal-sidebar-invite-list {
  list-style: none;
  padding: .25rem .375rem;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .125rem;
}
.cal-sidebar-invite-item {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  padding: .5rem .625rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition);
  min-height: 48px; /* Touch-Target */
  justify-content: center;
}
.cal-sidebar-invite-item:hover {
  background: var(--bg-tertiary);
}
.cal-sidebar-invite-title {
  font-size: .8375rem;
  font-weight: 500;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 1.3;
}
.cal-sidebar-invite-time {
  font-size: .72rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}
.cal-sidebar-invite-badge {
  align-self: flex-start;
  font-size: .65rem;
  padding: .1rem .35rem;
  line-height: 1.4;
  border-radius: 999px;
  margin-top: .1rem;
}

/* ── Sidebar: RSVP Empty-State (B3, 2026-06-10) ─────────────────── */
.cal-sidebar-invite-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: 1.5rem .75rem;
  color: var(--text-tertiary);
  font-size: .8125rem;
  text-align: center;
  line-height: 1.4;
}
.cal-sidebar-invite-empty-icon {
  opacity: .35;
  flex-shrink: 0;
}

/* ── Sidebar: Mini-Kalender Wrapper (B5, 2026-06-10) ─────────────── */
/* Haftung: immer sichtbar, modus-unabhängig; im collapsed-Zustand   */
/* verschwunden durch .ds-cal-sidebar.is-collapsed { overflow:hidden }*/
/* margin-top:auto klebt den Mini-Kal ans untere Ende der flex-column */
.cal-sidebar-mini-cal {
  flex-shrink: 0;
  margin-top: auto;
  border-top: 1px solid var(--border);
  padding: .75rem .375rem .625rem;
}

/* ── ds-mini-calendar Component (B5, 2026-06-10) ─────────────────── */
/* Eigenständige Klassen-Familie .ds-mini-cal-*                       */
/* Nutzt dasselbe visuelle Vokabular wie .cal-dp-* (day-Typen/Farben) */
.ds-mini-cal {
  display: flex;
  flex-direction: column;
  gap: .1875rem;
  user-select: none;
}

.ds-mini-cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .25rem;
  padding: 0 .125rem;
  margin-bottom: .1875rem;
}

.ds-mini-cal-label {
  flex: 1;
  text-align: center;
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-primary);
  background: none;
  border: none;
  cursor: pointer;
  padding: .2rem .25rem;
  border-radius: var(--radius-sm);
  transition: background var(--transition), color var(--transition);
  white-space: nowrap;
}
.ds-mini-cal-label:hover {
  background: var(--bg-tertiary);
  color: var(--accent);
}

.ds-mini-cal-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  transition: background var(--transition), color var(--transition);
}
.ds-mini-cal-arrow:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}

.ds-mini-cal-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0;
  margin-bottom: .125rem;
}
.ds-mini-cal-weekdays span {
  text-align: center;
  font-size: .65rem;
  font-weight: 600;
  color: var(--text-tertiary);
  padding: .1rem 0;
  letter-spacing: .01em;
}

.ds-mini-cal-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
}

.ds-mini-cal-day {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 1;
  max-width: 28px;
  margin: 0 auto;
  font-size: .72rem;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-primary);
  cursor: pointer;
  padding: 0;
  transition: background var(--transition), color var(--transition);
  line-height: 1;
}
.ds-mini-cal-day:hover {
  background: var(--bg-tertiary);
}
.ds-mini-cal-other {
  color: var(--text-tertiary);
}
/* Analog .cal-dp-today: accent-BG, weiß */
.ds-mini-cal-today {
  background: var(--accent);
  color: #fff;
  font-weight: 700;
}
.ds-mini-cal-today:hover {
  background: var(--accent-dark);
}
/* Ausgewählter Tag: accent-light BG, accent Text — nicht über Heute-Markierung */
.ds-mini-cal-selected:not(.ds-mini-cal-today) {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
}

/* Event-Formular: Ort / Videokonferenz kombiniert */
.event-location-field {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  padding: .5rem 0;
}
.event-location-tabs {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.event-location-tab {
  width: 28px; height: 28px;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--text-tertiary);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition), color var(--transition);
  padding: 0;
}
.event-location-tab.active,
.event-location-tab:hover {
  background: var(--accent-light);
  color: var(--accent);
}
.event-location-body { flex: 1; min-width: 0; }
.event-location-input {
  border: none;
  background: transparent;
  padding: .3rem 0;
  font-size: .875rem;
  color: var(--text-primary);
  width: 100%;
  font-family: inherit;
  outline: none;
}
.event-video-provider-list {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  padding: .25rem 0;
}
.event-video-provider-btn {
  display: flex;
  align-items: center;
  gap: .3rem;
  padding: .3rem .6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  font-size: .8rem;
  color: var(--text-primary);
  cursor: pointer;
  transition: background var(--transition);
}
.event-video-provider-btn:hover {
  background: var(--accent-light);
  border-color: var(--accent);
}
.event-video-selected {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .875rem;
}
.event-video-selected-label {
  display: flex;
  align-items: center;
  gap: .3rem;
  font-weight: 600;
  white-space: nowrap;
}
.event-video-auto-note {
  color: var(--text-tertiary);
  font-size: .8rem;
  font-style: italic;
}

/* Event-Formular: Kalender-Selektor */
.event-cal-selector { position: relative; display: inline-block; }
.event-cal-selector-btn {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .5rem .6rem;
  min-height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  cursor: pointer;
  font-size: .8rem;
  color: var(--text-primary);
  transition: background var(--transition);
  box-sizing: border-box;
}
.event-cal-selector-btn:hover { background: var(--bg-tertiary); }
.event-cal-selector-btn:disabled { opacity: .5; cursor: default; }
/* Volle Breite (Ticket 3.388.4) – Mail-Einladungs-Vorschau stellt den Kalender-Auswaehler
   neben ein Kategorie-<select>, das per .select bereits width:100% traegt; ohne diesen
   Modifier bleibt der Button auf seiner natuerlichen Inhaltsbreite (s. Kalender-Editor,
   wo der kompakte Trigger bewusst schmal bleibt). */
.event-cal-selector-btn--full { width: 100%; }
.event-cal-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  display: inline-block;
}
.event-cal-name { flex: 1; white-space: nowrap; }
.event-cal-popover {
  position: fixed;
  min-width: 240px;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  z-index: 500;
  padding: .25rem 0;
  max-height: 320px;
  overflow-y: auto;
}
.event-cal-popover-group {
  font-size: .7rem;
  font-weight: 700;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .03em;
  padding: .5rem .75rem .15rem;
}
.event-cal-popover-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .35rem .75rem;
  width: 100%;
  background: none;
  border: none;
  cursor: pointer;
  font-size: .82rem;
  color: var(--text-primary);
  text-align: left;
}
.event-cal-popover-item:hover { background: var(--bg-secondary); }
.event-cal-popover-item.is-active { font-weight: 600; color: var(--accent); }

/* Farb-Picker (innerhalb von ds-dropdown) – kein eigenes Popover-Chrome,
   ds-dropdown liefert Hintergrund + Shadow + Position. Wir liefern nur das
   Grid-Layout der Swatches und die Swatch-Optik. */
.cal-color-picker-grid {
  display: grid;
  grid-template-columns: repeat(8, 22px);
  gap: .35rem;
  padding: .5rem;
  justify-content: center;
}
.cal-color-swatch {
  --color: var(--accent);
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid transparent;
  background: var(--color);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: transform 120ms ease, box-shadow 120ms ease;
}
.cal-color-swatch.is-active {
  border-color: var(--text-primary);
  box-shadow: 0 0 0 2px var(--bg-primary), 0 0 0 3px var(--color);
}
.cal-color-swatch:hover { transform: scale(1.15); }

@media (max-width: 900px) {
  .ds-cal-sidebar { display: none; }
}

/* Editor-Panel: Ganztags-Bereich (Spec E, S2) */
.cal-editor-allday-bar {
  flex-shrink: 0;
  min-height: 28px;
  padding: 3px 4px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
}
.cal-editor-allday-chip {
  font-size: .68rem;
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-primary));
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  max-width: 120px;
  text-overflow: ellipsis;
}
.cal-editor-allday-chip.is-holiday {
  background: color-mix(in srgb, var(--rose) 12%, var(--bg-primary));
  color: var(--rose);
}
.cal-editor-allday-chip.is-followup {
  background: color-mix(in srgb, var(--amber) 12%, var(--bg-primary));
  color: var(--amber);
}

/* Editor-Panel-Toolbar (Spec B, S3) */
.cal-editor-panel-toolbar {
  display: flex;
  align-items: center;
  gap: .35rem;
  padding: .6rem 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
  flex-shrink: 0;
}
.cal-editor-panel-toolbar .toolbar-divider {
  width: 1px;
  height: 20px;
  background: var(--border);
  margin: 0 .15rem;
}
.cal-editor-panel-toolbar .select-sm {
  height: 28px;
  padding: 0 .5rem;
  font-size: .8125rem;
}
.cal-editor-panel-toolbar .toolbar-show-as {
  max-width: 140px;
  min-width: 0;
}
/* Ort-Feld mit Action-Icon (Maps / Video-Call) */
.cal-editor-loc-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.cal-editor-loc-row .input { flex: 1; min-width: 0; }
.cal-editor-loc-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  color: var(--accent);
  text-decoration: none;
  transition: background var(--transition), color var(--transition);
}
.cal-editor-loc-icon:hover {
  background: var(--accent-light);
  color: var(--accent-dark);
}
/* Flyout: Expand-Icon (Spec D, S3) – wie .cal-flyout-close, ohne Rahmen */
.cal-flyout-expand {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  padding: 2px;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  margin-left: auto;
  transition: color var(--transition), background var(--transition);
}
.cal-flyout-expand:hover {
  color: var(--text-primary);
  background: var(--bg-secondary);
}

/* Ort-Link (Google Maps) im Flyout / Slide-In */
.cal-loc-link { color: var(--accent); text-decoration: none; }
.cal-loc-link:hover { text-decoration: underline; }

/* Avail- und Block-Range innerhalb der Mini-Tagesansicht: gleiche Klassen
   wie Tages-/Wochenansicht, aber an die 44px-Stundenleiste angepasst. */
.cal-editor-preview-grid .cal-avail-block,
.cal-editor-preview-grid .cal-block-range {
  left: 44px;
  right: 4px;
  pointer-events: none;
}
.cal-editor-preview-grid .cal-avail-block { cursor: default; }

/* Ganztägige Sperre */
.cal-editor-preview-fullblock {
  position: absolute;
  inset: 0 4px 0 44px;
  background: color-mix(in srgb, var(--coral) 18%, var(--bg-primary));
  border: 1px dashed var(--coral);
  color: var(--coral);
  font-weight: 600;
  font-size: 0.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  pointer-events: none;
  z-index: 3;
}

/* Header: Pfeil-Buttons + Datum-Label rechts */
.cal-editor-preview-header {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
.cal-editor-preview-header .btn-icon {
  padding: 0.25rem;
}
@media (max-width: 900px) {
  .cal-editor-overlay { width: 100%; height: 100%; max-height: none; border-radius: 0; }
  .cal-editor-preview { display: none; }
  .cal-editor-form { flex: 1; padding: 1rem; }
}

/* Editor-Layout im Slide-In-Panel: hebelt das Padding des Panel-Bodys aus
   und nutzt das gleiche Toolbar+2-Spalten-Layout wie das Modal-Overlay. */
.ds-cal-panel-body:has(> .cal-editor-panel) {
  padding: 0;
}
.cal-editor-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}
.cal-editor-panel .cal-editor-body {
  display: flex;
  flex: 1;
  min-height: 0;
}
.cal-editor-panel .cal-editor-form {
  flex: 0 0 60%;
  padding: .75rem 1.25rem;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.cal-editor-panel .cal-editor-form > .ds-form-row:not(.ds-form-row--description) {
  flex-shrink: 0;
}
.cal-editor-panel .cal-editor-form > .event-toolbar,
.cal-editor-panel .cal-editor-form > div:not(.ds-form-row--description) {
  flex-shrink: 0;
}
/* Read-only Termin-Panel (_showEventPanel): anders als der Editor hat das
   linke .cal-editor-form hier kein einzelnes flex:1-Element mit eigenem
   internen Scroll (Editor: .ds-form-row--description/ds-rich-editor). Der
   Inhalt ist stattdessen ein einziger, natuerlich hoher .cal-event-panel-body-
   Block (unveraendert wiederverwendet, inkl. seines eigenen gap-Rhythmus) —
   .cal-editor-form selbst wird deshalb zum Scroll-Container (ersetzt das
   overflow-y:auto, das vorher auf .ds-cal-panel-body lag, bevor der Inhalt in
   .cal-editor-panel gewrappt wurde). overflow-x bleibt über die Basisregel
   oben (overflow:hidden) unveraendert versteckt. */
.cal-editor-panel--readonly .cal-editor-form {
  overflow-y: auto;
}
.cal-editor-panel .cal-editor-preview {
  flex: 1;
}
@media (max-width: 900px) {
  .cal-editor-panel .cal-editor-preview { display: none; }
  .cal-editor-panel .cal-editor-form    { flex: 1; }
}

/* Calendar right-click context menu */
.cal-ctx-menu {
  position: fixed;
  z-index: 460;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: 0.25rem;
  min-width: 180px;
}
.cal-ctx-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  color: var(--text-primary);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.cal-ctx-menu-item:hover { background: var(--bg-secondary); }

/* ──────────────────────────────────────────────────────────────
   ds-dropdown – wiederverwendbares Popover/Dropdown
   Wird body-level via Dropdown.open() gerendert,
   Position via JS gesetzt (top/left), kein overflow-clipping.
   ────────────────────────────────────────────────────────────── */
.ds-dropdown {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 500;
  min-width: 220px;
  max-width: min(360px, calc(100vw - 16px));
  max-height: min(420px, calc(100vh - 16px));
  overflow-y: auto;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, .04),
    0 12px 32px rgba(0, 0, 0, .14);
  padding: .25rem 0;
  opacity: 0;
  transform: translateY(-4px) scale(.98);
  transform-origin: top left;
  transition:
    opacity 180ms cubic-bezier(.16, 1, .3, 1),
    transform 180ms cubic-bezier(.16, 1, .3, 1);
  will-change: opacity, transform;
}
.ds-dropdown.is-open {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.ds-dropdown.is-closing {
  opacity: 0;
  transform: translateY(-4px) scale(.98);
}
.ds-dropdown[data-flipped="1"] {
  transform-origin: bottom left;
}
.ds-dropdown[data-flipped="1"].is-open {
  transform: translateY(0) scale(1);
}
:root[data-theme="dark"] .ds-dropdown,
:root:not([data-theme="light"]) .ds-dropdown {
  box-shadow:
    0 1px 2px rgba(0, 0, 0, .4),
    0 14px 36px rgba(0, 0, 0, .55);
}
/* Standard-Item-Klassen, optional verwendbar im Dropdown-Inhalt */
.ds-dropdown-group {
  font-size: .68rem;
  font-weight: 700;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: .55rem .85rem .2rem;
}
.ds-dropdown-item {
  display: flex;
  align-items: center;
  gap: .55rem;
  width: 100%;
  padding: .45rem .85rem;
  background: none;
  border: none;
  font-size: .82rem;
  color: var(--text-primary);
  text-align: left;
  cursor: pointer;
  transition: background 120ms ease;
}
.ds-dropdown-item:hover { background: var(--bg-secondary); }
.ds-dropdown-item.is-active {
  font-weight: 600;
  color: var(--accent);
}
.ds-dropdown-item .ds-dropdown-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.ds-dropdown-sep {
  height: 1px;
  background: var(--border);
  margin: .25rem 0;
  border: 0;
}
/* Modifier: dropdown item ist eine "danger"-Aktion (z.B. „entfernen") */
.ds-dropdown-item.is-danger { color: var(--danger); }
.ds-dropdown-item.is-danger:hover { background: var(--danger-light); }
/* Helper: 1fr-Layout für Item-Label, Check-Icon rechts ausgerichtet */
.ds-dropdown-item-label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-dropdown-item-label-muted { opacity: .7; }

/* ──────────────────────────────────────────────────────────────
   Toolbar „Kalender-Links teilen"-Dropdown (cal-share-menu-*)
   Tabellarisches Grid (Name | Kopieren | Öffnen), damit Icon-Spalten
   über beliebig lange Namen hinweg vertikal fluchten.
   Genutzt in: pages/calendar.js _renderShareMenuContent()/_renderShareMenuLoading().
   ────────────────────────────────────────────────────────────── */
.cal-share-menu-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: .25rem;
  padding: .375rem .85rem;
  transition: background 120ms ease;
}
.cal-share-menu-row:hover { background: var(--bg-secondary); }
.cal-share-menu-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .82rem;
  color: var(--text-primary);
}
.cal-share-menu-icon-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.cal-share-menu-icon-btn:hover { background: var(--bg-tertiary); color: var(--accent); }
.cal-share-menu-empty {
  display: block;
  width: 100%;
  padding: .5rem .85rem;
  background: none;
  border: none;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--accent);
  text-align: left;
  cursor: pointer;
  transition: background 120ms ease;
}
.cal-share-menu-empty:hover { background: var(--accent-light); }
.cal-share-menu-loading {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .75rem .85rem;
  font-size: .82rem;
  color: var(--text-secondary);
}

/* ──────────────────────────────────────────────────────────────
   ds-dropdown – Account-Group + Sub-Calendar Indent Pattern
   Dieselbe visuelle Sprache wie in ds-cal-sidebar:
   – Gruppen-Header bündig links
   – Sub-Kalender-Items minimal eingerückt durch margin-left
   ────────────────────────────────────────────────────────────── */
.ds-dropdown-account-group {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .65rem .85rem .25rem;
  font-size: .68rem;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.ds-dropdown-account-group + .ds-dropdown-account-group {
  margin-top: .2rem;
}
.ds-dropdown-account-group-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  width: 14px;
  height: 14px;
}
.ds-dropdown-account-group-icon img {
  border-radius: 50%;
}
.ds-dropdown-account-group-label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-transform: none;        /* Email/Account nicht uppercase */
  font-weight: 600;
  letter-spacing: 0;
  font-size: .72rem;
  color: var(--text-secondary);
}
.ds-dropdown-account-group-label-provider {
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-right: .25rem;
}
/* Sub-Kalender-Zeile innerhalb einer Account-Gruppe – leicht eingerückt */
.ds-dropdown-subcal-row {
  display: flex;
  align-items: center;
  gap: .55rem;
  width: calc(100% - 1.1rem);
  margin: 0 .55rem;
  padding: .4rem .55rem;
  background: none;
  border: none;
  font-size: .82rem;
  color: var(--text-primary);
  text-align: left;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background 120ms ease;
}
.ds-dropdown-subcal-row:hover { background: var(--bg-secondary); }
.ds-dropdown-subcal-row.is-active {
  font-weight: 600;
  color: var(--accent);
}
.ds-dropdown-subcal-row .ds-dropdown-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 2px solid transparent;
}
.ds-dropdown-subcal-row.is-active .ds-dropdown-dot {
  box-shadow: 0 0 0 2px var(--bg-primary), 0 0 0 3px currentColor;
}
.ds-dropdown-subcal-row-label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-dropdown-subcal-row-check {
  flex-shrink: 0;
  display: inline-flex;
  color: var(--accent);
}

/* ──────────────────────────────────────────────────────────────
   Dynamic-Color Helper
   Für Stellen, an denen die Hintergrundfarbe aus Daten kommt
   (z.B. Kalender-Farbe). Inline ausschließlich `style="--color:#xxx"`,
   die Klasse übernimmt das Rendering.
   ────────────────────────────────────────────────────────────── */
.ds-color-dot {
  --color: var(--accent);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color);
  flex-shrink: 0;
  display: inline-block;
}

/* ──────────────────────────────────────────────────────────────
   Calendar Editor – Form-Layout-Klassen
   Wiederverwendbares Layout für das Slide-In-Panel des
   Termin-Editors. Vermeidet Inline-Styles im Lit-Template.
   ────────────────────────────────────────────────────────────── */

/* Titel-Zeile: großer Titel + rechts der Sub-Cal-Selector */
.cal-editor-title-row {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.cal-editor-title-input {
  flex: 1;
  min-width: 0;
  font-size: 1.125rem;
  font-weight: 500;
}

/* Ganztägig-Toggle-Zeile (im Slide-In-Panel) */
.cal-editor-allday-row {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.cal-editor-allday-label {
  font-size: .875rem;
  color: var(--text-primary);
  cursor: default;
  user-select: none;
}
/* Custom Toggle-Größen für Editor (über CSS Custom Properties) */
.cal-editor-allday-toggle {
  --toggle-width: 2rem;
  --toggle-height: 1.1rem;
}

/* Form-group Modifier: kompakter Bottom-Margin (für Toggle-Reihen) */
.form-group--compact {
  margin-bottom: .75rem;
}
/* Form-group Modifier: extra Top-Margin (z.B. Speichern-Button) */
.form-group--push-top {
  margin-top: 1rem;
}
.form-group--push-top-sm {
  margin-top: .5rem;
}

/* Von/Bis 2-Spalten-Raster */
.cal-editor-datetime-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

/* Standort/Video-Zeile: Input + Video-Picker rechts */
.cal-editor-location-row {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.cal-editor-location-input {
  flex: 1;
  min-width: 0;
}

/* Aktiver Video-Provider Hinweis-Badge unter dem Input */
.cal-editor-vc-badge {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin-top: .35rem;
  font-size: .8rem;
  color: var(--accent);
}
.cal-editor-vc-link-wrap {
  margin-top: .35rem;
}
.cal-editor-vc-link-input {
  font-size: .85rem;
}

/* Speichern-Button im Editor */
.cal-editor-save-btn {
  width: 50%;
}
@media (max-width: 600px) {
  .cal-editor-save-btn { width: 100%; }
}

/* Hilfsklasse: Element via Klasse ausblenden (wechselt mit JS) */
.is-hidden { display: none !important; }

/* ──────────────────────────────────────────────────────────────
   Calendar Page – Utility-Klassen-Katalog
   Gruppiert sämtliche wiederkehrenden Layout-/Typografie-Patterns
   aus calendar.js. Statisches Styling lebt hier; dynamische Werte
   (Position aus Daten, Color aus DB) laufen über CSS Custom
   Properties (--cal-top, --cal-color, …) und bleiben pro Element
   minimal als `style="--var:value"`.
   ────────────────────────────────────────────────────────────── */

/* ── Layout-Helfer ─────────────────────────────────────────── */
.cal-row             { display: flex; align-items: center; gap: .5rem; }
.cal-row--start      { align-items: flex-start; }
.cal-row--gap-sm     { gap: .375rem; }
.cal-row--gap-md     { gap: .625rem; }
.cal-row--gap-lg     { gap: .75rem; }
.cal-row--wrap       { flex-wrap: wrap; }
.cal-row--space-between { justify-content: space-between; }
.cal-col             { display: flex; flex-direction: column; gap: .5rem; }
.cal-col--gap-sm     { gap: .375rem; }
.cal-col--gap-md     { gap: .625rem; }
.cal-col--gap-lg     { gap: .875rem; }
.cal-flex-1          { flex: 1 1 auto; min-width: 0; }
.cal-flex-fill       { flex: 1; min-width: 0; }
.cal-shrink-0        { flex-shrink: 0; }
.cal-grid-2col       { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.cal-grid-2col--sm   { gap: .75rem; }
.cal-grid-3col       { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: .5rem; }
.cal-grid-end-row    { display: grid; grid-template-columns: 1fr auto; gap: 1rem; align-items: end; }

/* ── Page-Layout (calendar.js render()) ────────────────────── */
.cal-page-shell {
  display: flex;
  flex: 1;
  min-height: 0;
}
.cal-page-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.cal-content-host {
  flex: 1;
  min-height: 0;
}
.cal-card-flush > .card-body { padding: 0; }
.cal-card-body--flush { padding: 0; }
.cal-toolbar { position: relative; }

/* ── Backdrop für Flyouts ──────────────────────────────────── */
.cal-overlay-backdrop {
  position: fixed;
  inset: 0;
  z-index: 449;
}

/* ── Flyout dynamische Position via CSS-Vars ───────────────── */
.cal-flyout--positioned {
  --cal-flyout-x: 0px;
  --cal-flyout-y: 0px;
  left: var(--cal-flyout-x);
  top: var(--cal-flyout-y);
}

/* ── Color-Dot Varianten (alle nutzen --color) ─────────────── */
.cal-color-square {
  --color: var(--accent);
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 3px;
  background: var(--color);
  flex-shrink: 0;
}
.cal-color-square--sm { width: 10px; height: 10px; }
.cal-color-square--lg { width: 14px; height: 14px; }
.cal-color-circle {
  --color: var(--accent);
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--color);
  flex-shrink: 0;
}
.cal-color-circle--sm { width: 8px; height: 8px; }

/* ── Typografie-Helfer ─────────────────────────────────────── */
.cal-text-primary    { color: var(--text-primary); }
.cal-text-secondary  { color: var(--text-secondary); }
.cal-text-tertiary   { color: var(--text-tertiary); }
.cal-text-accent     { color: var(--accent); }
.cal-text-coral      { color: var(--coral); }
.cal-text-amber      { color: var(--amber); }
.cal-text-bold       { font-weight: 600; }
.cal-text-medium     { font-weight: 500; }
.cal-text-mono       { font-family: monospace; }
.cal-text-italic     { font-style: italic; }
.cal-text-pre        { white-space: pre-wrap; }
.cal-text-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cal-fs-xxs { font-size: .75rem; }
.cal-fs-xs  { font-size: .78rem; }
.cal-fs-sm  { font-size: .8125rem; }
.cal-fs-md  { font-size: .85rem; }
.cal-fs-base { font-size: .875rem; }
.cal-fs-lg  { font-size: .9375rem; }
.cal-fs-xl  { font-size: 1rem; }

/* ── Section-Header (uppercase Sub-Header in Panels) ───────── */
.cal-section-label {
  font-size: .8rem;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin: 0 0 .625rem;
}
.cal-section-label--push-top {
  margin-top: 1.25rem;
}

/* ── Inline-Code-Pille (für Variablen-Übersicht) ───────────── */
.cal-inline-code {
  background: var(--bg-secondary);
  padding: 1px 4px;
  border-radius: 3px;
}

/* ── Panel-Footer (Aktion-Reihe unten im Slide-In) ─────────── */
.cal-panel-footer {
  display: flex;
  gap: .5rem;
  margin-top: 1.25rem;
  padding-top: .75rem;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}
.cal-panel-footer--push-only {
  margin-top: 1.25rem;
  padding-top: .75rem;
  border-top: 1px solid var(--border);
}
.cal-panel-back-btn {
  margin-bottom: .75rem;
  padding-left: 0;
}

/* ── Followup-Card (Slide-In) ──────────────────────────────── */
.cal-followup-header {
  display: flex;
  align-items: center;
  gap: .625rem;
  margin-bottom: .875rem;
}
.cal-followup-title {
  font-size: 1rem;
  font-weight: 600;
}
.cal-followup-meta {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  font-size: .875rem;
}
.cal-followup-note {
  color: var(--text-secondary);
  white-space: pre-wrap;
  margin-top: .25rem;
}
.cal-followup-status-badge {
  align-self: flex-start;
}
.cal-followup-virtual-hint {
  font-size: .8rem;
  color: var(--text-tertiary);
  margin-top: .375rem;
}

/* ── Event-Detail-Panel (`_showEventPanel`) ────────────────── */
.cal-event-panel-header {
  display: flex;
  align-items: center;
  gap: .625rem;
  margin-bottom: .875rem;
}
.cal-event-panel-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-primary);
}
.cal-event-panel-body {
  display: flex;
  flex-direction: column;
  gap: .625rem;
  font-size: .875rem;
}
.cal-event-panel-row {
  display: flex;
  gap: .5rem;
  align-items: flex-start;
}
.cal-event-panel-row--center { align-items: center; }
.cal-event-panel-icon {
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--text-tertiary);
}
.cal-event-panel-icon--center {
  margin-top: 0;
}
.cal-event-panel-vc-card {
  background: var(--accent-light);
  border-radius: var(--radius-md);
  padding: .75rem;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.cal-event-panel-vc-header {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .8rem;
  font-weight: 600;
  color: var(--accent);
}
.cal-event-panel-vc-join {
  align-self: flex-start;
  text-decoration: none;
}
.cal-event-panel-vc-meta {
  font-size: .78rem;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: .375rem;
}
.cal-event-panel-vc-host {
  font-size: .78rem;
  color: var(--accent);
}
.cal-event-panel-copy-btn {
  padding: 1px 5px;
  font-size: .75rem;
}
.cal-event-panel-loc-link {
  word-break: break-all;
}
.cal-event-panel-link {
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
}
.cal-event-panel-link:hover { text-decoration: underline; }
.cal-event-panel-description {
  display: block;
  white-space: pre-wrap;
  word-wrap: break-word;
}
/* Ticket 3.360.3: "Naechster Schritt"-Zeile im Read-only-Termin-Panel –
   manueller Gegenpart zum automatischen event_followup-Auslöser (3.360.4).
   Drei Zustaende: Skeleton waehrend des Ladens, Anlegen-Formular (Datum +
   Button), Verweis wenn bereits vorhanden (.cal-event-panel-link, s.o.). */
.cal-panel-next-step-loading {
  flex: 1;
  display: flex;
  align-items: center;
  min-width: 0;
}
.cal-panel-next-step-loading .skeleton-bar { max-width: 9rem; }
.cal-panel-next-step-form {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  flex: 1;
  min-width: 0;
}
.cal-panel-next-step-label {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--text-primary);
}
.cal-panel-next-step-controls {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}
.cal-panel-next-step-date { max-width: 10.5rem; }
.cal-panel-next-step-btn { flex-shrink: 0; }
.cal-panel-next-step-error {
  font-size: .8125rem;
  color: var(--coral);
}
/* Ticket 3.296.6: dezente Herkunftszeile unter dem Mail-Body-Fallback-Text
   (nur sichtbar, wenn die Einladung selbst keine eigene Beschreibung traegt
   -- s. modules/calendar.md). */
.cal-event-panel-description-source {
  margin-top: .25rem;
  font-size: .72rem;
  font-style: italic;
  color: var(--text-tertiary);
}
.cal-event-panel-status {
  font-size: .8125rem;
  color: var(--text-secondary);
}
.cal-event-panel-status strong { color: var(--text-primary); }
.cal-event-panel-badge {
  align-self: flex-start;
}

/* ── Booking-Detail-Panel ──────────────────────────────────────
   Lineage-Sicht beim Klick auf ein Booking-Event oder eine Booking-Liste-Row.
   Sektionen: Booker / Termin / Form-Submission (Schema-Snapshot) / Tracking.
   Karten-Pattern auf bg-secondary mit Label-links/Wert-rechts-Grid pro Zeile. */
.booking-detail-section {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .75rem .875rem;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.booking-detail-section-title {
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  margin-bottom: .125rem;
}
.booking-detail-kv-list {
  display: flex;
  flex-direction: column;
  gap: .375rem;
}
.booking-detail-kv {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: .75rem;
  align-items: start;
  font-size: .8125rem;
  line-height: 1.4;
}
.booking-detail-kv-label {
  color: var(--text-tertiary);
  font-weight: 500;
}
.booking-detail-kv-value {
  color: var(--text-primary);
  word-break: break-word;
  min-width: 0;
}
.booking-detail-kv-value a {
  color: var(--accent);
  text-decoration: none;
}
.booking-detail-kv-value a:hover { text-decoration: underline; }
.booking-detail-section-meta {
  font-size: .7rem;
  color: var(--text-tertiary);
  margin-top: .125rem;
}
.booking-detail-status {
  margin-left: auto;
}
.booking-detail-contact-link {
  color: var(--accent);
  text-decoration: none;
  cursor: pointer;
}
.booking-detail-contact-link:hover { text-decoration: underline; }
.booking-detail-contact-name {
  display: block;
  color: var(--text-primary);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  font-size: .875rem;
  line-height: 1.3;
}
.booking-detail-contact-name:hover {
  color: var(--accent);
}
.booking-detail-error {
  padding: 1rem;
  background: var(--coral-light);
  color: var(--coral);
  border-radius: var(--radius-md);
  font-size: .875rem;
}
.booking-detail-skeleton {
  display: flex;
  flex-direction: column;
  gap: .625rem;
  padding-top: .5rem;
}
.booking-detail-skeleton .skeleton-bar { height: .875rem; }
.booking-detail-skeleton-h { height: 1.25rem !important; width: 55%; }
.booking-detail-skeleton-l { width: 80%; }
.booking-detail-skeleton-m { width: 65%; }
.booking-detail-skeleton-s { width: 45%; }
.booking-detail-skeleton-mt { margin-top: 1.25rem; }

/* ── Booking-Detail Inline-Layout (Redesign 2026-04-30) ────────
   Alle Sektionen folgen dem cal-event-panel-row Icon-Row-Pattern.
   Keine Boxen, keine grauen Hintergruende — nur Icon + strukturierter Inhalt.
   Das Form-Submission-Snapshot wird als <dl> gerendert (semantisch korrekt). */
.booking-detail-form-row {
  align-items: flex-start;
}
.booking-detail-form-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .375rem;
}
.booking-detail-form-title {
  font-size: .875rem;
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: -0.005em;
  line-height: 1.3;
}
.booking-detail-form-list {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(6rem, max-content) 1fr;
  gap: .25rem .875rem;
  font-size: .8125rem;
  line-height: 1.45;
}
.booking-detail-form-list dt {
  color: var(--text-tertiary);
  font-weight: 500;
  margin: 0;
}
.booking-detail-form-list dd {
  color: var(--text-primary);
  margin: 0;
  word-break: break-word;
  min-width: 0;
}
.booking-detail-form-meta {
  font-size: .7rem;
  color: var(--text-tertiary);
  margin-top: .125rem;
}
@media (max-width: 600px) {
  .booking-detail-form-list {
    grid-template-columns: 1fr;
    gap: .125rem;
  }
  .booking-detail-form-list dt { margin-top: .25rem; }
  .booking-detail-form-list dt:first-child { margin-top: 0; }
}

/* Person-Name: klickbar mit dezentem External-Link-Icon. Pattern an Deal-Card
   angelehnt — Affordance dass der Klick zu einer anderen Seite fuehrt. */
.booking-detail-person-name {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  font-size: .9rem;
  font-weight: 600;
  color: var(--text-primary);
  text-decoration: none;
  cursor: pointer;
  letter-spacing: -0.005em;
  line-height: 1.3;
  margin-bottom: .375rem;
}
.booking-detail-person-name:hover {
  color: var(--accent);
}
.booking-detail-person-name:hover .booking-detail-person-link-icon {
  color: var(--accent);
  transform: translate(1px, -1px);
}
.booking-detail-person-name--static {
  cursor: default;
}
.booking-detail-person-name--static:hover { color: var(--text-primary); }
.booking-detail-person-link-icon {
  color: var(--text-tertiary);
  flex-shrink: 0;
  transition: color 150ms ease, transform 150ms ease;
}
.booking-detail-person-msg-cell {
  font-style: italic;
  white-space: pre-line;
  color: var(--text-secondary);
}

/* Inline-Deal-Row (Hover/Focus konsistent zur Booking-Liste) */
.booking-detail-deal-row-inline {
  cursor: pointer;
  padding: .375rem .5rem;
  margin: 0 -.5rem;
  border-radius: var(--radius-md);
  transition: background 150ms ease;
}
.booking-detail-deal-row-inline:hover {
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.booking-detail-deal-row-inline:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.booking-detail-deal-row-inline .booking-detail-deal-main {
  flex: 1;
  min-width: 0;
}

.booking-detail-cancel-btn {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
}
.booking-detail-cancel-btn svg {
  flex-shrink: 0;
}

/* Verknuepfter Deal — Karten-Variante als klickbare Section */
.booking-detail-deal--linked {
  cursor: pointer;
  transition: border-color 150ms ease, background 150ms ease;
}
.booking-detail-deal--linked:hover {
  border-color: color-mix(in srgb, var(--accent) 35%, var(--border));
  background: var(--bg-primary);
}
.booking-detail-deal--linked:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.booking-detail-deal-row {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.booking-detail-deal-main {
  flex: 1;
  min-width: 0;
}
.booking-detail-deal-create {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: .375rem;
}

/* Deal-Form Booking-Banner (Pre-Fill-Hinweis) */
.deal-form-booking-banner {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .625rem .875rem;
  background: var(--accent-light);
  border-radius: var(--radius-md);
  font-size: .8125rem;
  color: var(--accent-dark, var(--accent));
}
.deal-form-booking-banner svg {
  flex-shrink: 0;
}

/* Deal-Detail "Aus Buchung"-Link */
.deal-detail-booking-link {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  color: var(--accent);
  cursor: pointer;
  font-size: .875rem;
}
.deal-detail-booking-link:hover { text-decoration: underline; }
.deal-detail-booking-link svg { flex-shrink: 0; }

/* Klickbare Booking-Row in der Bookings-Liste (Tab 2) */
.cal-bookingrow {
  cursor: pointer;
  transition: border-color 150ms ease, box-shadow 150ms ease, transform 150ms ease;
}
.cal-bookingrow:hover {
  border-color: color-mix(in srgb, var(--accent) 35%, var(--border));
  box-shadow: var(--shadow-sm);
}
.cal-bookingrow:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Mobile: Label/Value untereinander statt Grid */
@media (max-width: 600px) {
  .booking-detail-kv {
    grid-template-columns: 1fr;
    gap: .125rem;
  }
}

/* ── Avail-Slot-Panel ──────────────────────────────────────── */
.cal-avail-panel-header {
  display: flex;
  align-items: center;
  gap: .625rem;
  margin-bottom: 1rem;
}
.cal-avail-panel-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-primary);
}
.cal-avail-panel-meta {
  display: flex;
  flex-direction: column;
  gap: .625rem;
  font-size: .875rem;
}
.cal-avail-panel-meta-row {
  display: flex;
  gap: .5rem;
  align-items: center;
}
.cal-avail-panel-icon {
  flex-shrink: 0;
  color: var(--text-tertiary);
}
.cal-avail-panel-blocked-hint {
  font-size: .8125rem;
  color: var(--text-secondary);
  margin: 0 0 .75rem;
}
.cal-avail-panel-actions {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
}
.cal-avail-panel-actions .btn-primary { flex: 1; }
.badge--blocked-coral {
  background: var(--coral-light);
  color: var(--coral);
}

/* ── Banner für ganztägige Sperre ──────────────────────────── */
.cal-fullday-block-banner {
  background: var(--coral-light);
  border: 1px solid var(--coral);
  border-radius: var(--radius-sm);
  padding: .5rem .75rem;
  margin-bottom: .75rem;
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .875rem;
  color: var(--coral);
}
.cal-fullday-block-banner-icon {
  flex-shrink: 0;
}
.cal-fullday-block-banner-label {
  font-weight: 600;
}

/* ── Holiday-/Followup-Bar in Day-Panel-AllDay-Bereich ─────── */
.cal-allday-bar-full {
  width: 100%;
  height: auto;
  line-height: 1.4;
  padding: 6px 10px;
  margin: 0 0 .375rem;
  font-size: .8125rem;
}

/* ── All-Day-Chip-Reihe (Day-Panel) ────────────────────────── */
.cal-allday-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem;
  margin: -.125rem 0 .75rem;
}
.cal-allday-chip {
  --color: var(--accent);
  background: var(--color);
  color: #fff;
  border-radius: var(--radius-sm);
  padding: 2px 8px;
  font-size: .75rem;
  cursor: pointer;
}

/* ── Day-Panel Footer ──────────────────────────────────────── */
.cal-daypanel-footer {
  padding: .875rem 0 0;
  margin-top: .875rem;
  border-top: 1px solid var(--border);
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
}

/* ── Day-Panel Inline-Day-Grid Wrapper ─────────────────────── */
.cal-daypanel-grid-wrap {
  margin: 0 -1rem;
  border-top: 1px solid var(--border);
  overflow-y: auto;
  max-height: calc(100dvh - 220px);
  /* Touch: allow momentum scroll; touch-action pan-y lets browser handle
     vertical swipes for scroll before long-press arms the drag handler */
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
}
.cal-daypanel-grid-row {
  --cal-grid-h: 0px;
  display: flex;
  position: relative;
  min-height: var(--cal-grid-h);
}
.cal-day-single--full {
  flex: 1;
  position: relative;
  /* Inherit pan-y from scroll container; once long-press arms the drag
     handler the non-passive touchmove listener takes over via preventDefault */
  touch-action: pan-y;
}

/* ── Dynamic position helpers via CSS Custom Properties ───── */
.cal-pos-top {
  --cal-top: 0px;
  top: var(--cal-top);
}
.cal-pos-top-height {
  --cal-top: 0px;
  --cal-h: 0px;
  top: var(--cal-top);
  height: var(--cal-h);
}
.cal-pos-block {
  --cal-top: 0px;
  --cal-h: 0px;
  --cal-color: var(--accent);
  --cal-bg: var(--bg-primary);
  --cal-left: 0%;
  --cal-w: 100%;
  --cal-dash: transparent;
  top: var(--cal-top);
  height: var(--cal-h);
}
.cal-event-block.cal-pos-block {
  background: var(--cal-bg);
  border-left-color: var(--cal-color);
  left: var(--cal-left);
  width: var(--cal-w);
}
.cal-avail-block.cal-pos-block {
  border-left-color: var(--cal-color);
  border-top-color: var(--cal-dash);
  border-right-color: var(--cal-dash);
  border-bottom-color: var(--cal-dash);
}
.cal-avail-block-bg.cal-pos-color { background: var(--cal-color); }
.cal-avail-block-label.cal-pos-color { color: var(--cal-color); }
.cal-avail-block-del.cal-pos-color { color: var(--cal-color); }
.cal-event-bar.cal-pos-block {
  background: var(--cal-bg);
  border-left-color: var(--cal-color);
  /* Event-Bars in der All-Day-Zeile sind NICHT absolut positioniert —
     cal-pos-block setzt height:0 als Default, das muss überschrieben werden */
  top: auto;
  height: auto;
  position: static;
}
.cal-editor-preview-event.cal-pos-block {
  background: var(--cal-bg);
  border-left: 3px solid var(--cal-color);
  color: var(--text-primary);
}
.cal-editor-preview-grid--sized {
  --cal-slot-height: 48px;
  --cal-grid-h: 1152px;
  height: var(--cal-grid-h);
}
.cal-day--weekend { opacity: .7; }
.cal-day--clickable { cursor: pointer; }
.cal-cursor-pointer { cursor: pointer; }
.cal-no-vc-hint {
  font-size: .825rem;
  color: var(--text-tertiary);
  padding: .5rem .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
}
.cal-color-input-bare {
  height: 38px;
  padding: 2px;
  width: 80px;
}
.cal-editor-preview-label {
  flex: 1;
  text-align: right;
}
.cal-blockform-hint {
  font-size: .8rem;
  color: var(--text-tertiary);
  margin: -.25rem 0 .75rem;
}
.cal-bookings-filter { margin-bottom: 1rem; }

/* ── Booking-row "isPast" Modifier ─────────────────────────── */
.cal-card--past { opacity: .7; }
.cal-card--mb-md { margin-bottom: .5rem; }
.cal-card--mb-lg { margin-bottom: .75rem; }

/* ── Card-Body Layouts ─────────────────────────────────────── */
.cal-card-body--row {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
}
.cal-card-empty {
  text-align: center;
  padding: 2rem;
  color: var(--text-secondary);
}
.cal-bookingrow-meta {
  font-size: .85rem;
  color: var(--text-secondary);
}
.cal-bookingrow-sub {
  font-size: .82rem;
  color: var(--text-tertiary);
  margin-top: .125rem;
}
.cal-bookingrow-message {
  font-size: .82rem;
  color: var(--text-tertiary);
  margin-top: .25rem;
  font-style: italic;
}
.cal-bookingrow-titlerow {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  margin-bottom: .25rem;
}

/* ── Type-Card (Buchungstyp-Karte) ────────────────────────── */
.cal-type-card {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  overflow: hidden;
  margin-bottom: .75rem;
  transition: box-shadow var(--transition), border-color var(--transition);
}
.cal-type-card:hover {
  box-shadow: var(--shadow-md);
  border-color: color-mix(in srgb, var(--border) 60%, var(--text-tertiary));
}
.cal-type-card--inactive {
  opacity: .65;
}
.cal-type-card-accent {
  width: 5px;
  flex-shrink: 0;
}
.cal-type-card-body {
  flex: 1;
  min-width: 0;
  padding: 1rem 1.125rem;
  display: flex;
  flex-direction: column;
  gap: .625rem;
}

/* Header row: title left, badge right */
.cal-type-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
}
.cal-type-card-titlerow {
  display: flex;
  align-items: center;
  gap: .375rem;
  min-width: 0;
}
.cal-type-card-star {
  flex-shrink: 0;
}
.cal-type-card-title {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Info chips row */
.cal-type-card-chips {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
}
.cal-type-chip {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .1875rem .5rem;
  font-size: .75rem;
  font-weight: 500;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  white-space: nowrap;
}
.cal-type-chip svg {
  flex-shrink: 0;
  opacity: .6;
}
.cal-type-chip--lang {
  padding: .1875rem .375rem;
  font-size: .7rem;
}

/* Booking link row */
.cal-type-card-link-row {
  display: flex;
  align-items: center;
  gap: .375rem;
  padding: .375rem .5rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
}
.cal-type-card-link-icon {
  flex-shrink: 0;
  color: var(--text-tertiary);
}
.cal-type-card-link {
  font-size: .75rem;
  color: var(--accent);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}
.cal-type-card-copy {
  flex-shrink: 0;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  padding: .125rem;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
  display: flex;
}
.cal-type-card-copy:hover {
  color: var(--accent);
  background: var(--accent-light);
}

/* Action bar */
.cal-type-card-actions {
  display: flex;
  align-items: center;
  gap: .25rem;
  padding-top: .5rem;
  border-top: 1px solid var(--border);
}
.cal-type-action {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .3125rem .625rem;
  font-size: .75rem;
  font-weight: 500;
  color: var(--text-secondary);
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: color var(--transition), background var(--transition);
  white-space: nowrap;
}
.cal-type-action:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.cal-type-action--danger:hover {
  background: var(--coral-light);
  color: var(--coral);
}
.cal-type-action svg {
  flex-shrink: 0;
}
/* Push delete button to the right */
.cal-type-card-actions > .cal-type-action--danger {
  margin-left: auto;
}

/* Mobile: Type-Card stacks action labels away, keeps icons */
@media (max-width: 900px) {
  .cal-type-card-body { padding: .75rem .875rem; }
  .cal-type-card-actions { flex-wrap: wrap; }
}
@media (max-width: 600px) {
  .cal-type-card-actions { gap: .125rem; }
  .cal-type-action { padding: .3125rem .4rem; font-size: .7rem; }
}

/* ── Booking-Type Form / Loctype Buttons ───────────────────── */
.tf-loctype-row {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  justify-content: flex-start;
}
.tf-loctype-btn {
  --border-color: var(--border);
  --bg: transparent;
  --color: var(--text-primary);
  padding: .5rem .25rem;
  border: 1.5px solid var(--border-color);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: .8125rem;
  font-weight: 500;
  background: var(--bg);
  color: var(--color);
}
.tf-loctype-btn.is-active {
  --border-color: var(--accent);
  --bg: var(--accent-light);
  --color: var(--accent);
}
.tf-loctype-select-hidden { display: none; }
.tf-loctype-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .2rem;
}
.tf-loctype-default {
  background: none;
  border: none;
  cursor: pointer;
  font-size: .7rem;
  color: var(--text-tertiary);
  padding: 0;
  line-height: 1;
  transition: color 120ms ease;
}
.tf-loctype-default:hover { color: var(--amber); }
.tf-loctype-default.is-default { color: var(--amber); font-size: .75rem; }
.cal-form-helper-text {
  font-size: .775rem;
  color: var(--text-tertiary);
  margin-top: .3rem;
  line-height: 1.5;
}
.cal-form-helper-text-secondary {
  margin-top: .4rem;
  font-size: .8rem;
  color: var(--text-secondary);
}
.cal-form-helper-text-primary {
  color: var(--text-primary);
}
.cal-form-color-input {
  width: 44px;
  height: 38px;
  padding: 2px 4px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  background: none;
}
.form-group--no-bottom { margin-bottom: 0; }
.cal-form-toggle-section {
  margin-top: 1.25rem;
  border-top: 1px solid var(--border);
  padding-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: .875rem;
}
.cal-form-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.cal-form-toggle-label-tight {
  margin-bottom: .125rem;
}
.cal-form-toggle-hint {
  font-size: .78rem;
  color: var(--text-tertiary);
}
.cal-form-actions-row {
  display: flex;
  gap: .5rem;
  margin-top: 1.5rem;
}
.cal-form-actions-row > .btn { flex: 1; }

/* ── Buchungstyp: Tab-System ─────────────────────────────────── */
.bt-tab-bar {
  margin-bottom: 1.125rem;
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg-primary);
  padding-bottom: .125rem;
}
.bt-tab-bar .tab-filter-btn:disabled {
  opacity: .35;
  cursor: not-allowed;
  pointer-events: none;
}

/* Sprach-Umschalter (modul-agnostisch) */
.ds-lang-bar {
  display: flex;
  gap: .25rem;
  padding: .1875rem;
  background: var(--bg-tertiary);
  border-radius: var(--radius-md);
  margin-bottom: 1.125rem;
}
.ds-lang-bar .tab-filter-btn {
  flex: 1;
  text-align: center;
  min-height: 32px;
  font-size: .8rem;
}


/* Kompaktere Form-Groups in Text-Editor */
.form-group--compact {
  margin-bottom: .625rem;
}
.form-group--compact:last-child {
  margin-bottom: .125rem;
}
.form-label--sm {
  font-size: .78rem;
  font-weight: 500;
  margin-bottom: .1875rem;
  color: var(--text-secondary);
}
.input--sm,
.textarea--sm {
  font-size: .8125rem;
  padding: .375rem .5rem;
  line-height: 1.4;
}
.textarea--sm {
  resize: vertical;
  min-height: 2.5rem;
}

/* ── Rules Sheet / Day Editor ──────────────────────────────── */
.cal-rules-day-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--border);
}
.cal-rules-day-name {
  width: 72px;
  font-size: .85rem;
  color: var(--text-secondary);
  flex-shrink: 0;
}
.cal-rules-day-slots {
  flex: 1;
  display: flex;
  gap: .375rem;
  flex-wrap: wrap;
}
.cal-rules-day-empty {
  color: var(--text-tertiary);
  font-size: .82rem;
}
.cal-rules-empty-text {
  color: var(--text-tertiary);
  font-size: .85rem;
  margin: 0 0 .75rem;
}
.cal-rules-override-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem 0;
  border-bottom: 1px solid var(--border);
}
.cal-rules-override-label {
  flex: 1;
  font-size: .85rem;
}
.cal-rules-section-card {
  margin-top: 1.25rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.cal-rules-section-card--push-sm {
  margin-top: .75rem;
}
.cal-rules-section-card-header {
  font-size: .8rem;
  font-weight: 600;
  margin-bottom: .75rem;
}
.cal-rules-section-card-header--teal { color: var(--teal); }
.cal-rules-section-card-header--coral { color: var(--coral); }
.cal-rules-section-card-hint {
  font-size: .78rem;
  color: var(--text-tertiary);
  margin: 0 0 .75rem;
}
.cal-rules-block-btn {
  width: 100%;
  margin-top: .875rem;
  color: var(--coral);
  border-color: var(--coral-light);
}
.cal-rules-save-btn {
  width: 100%;
  margin-top: .875rem;
}
.cal-rules-day-back-btn {
  display: flex;
  align-items: center;
  gap: .375rem;
  margin-bottom: 1rem;
}
.cal-rules-day-list {
  margin-bottom: 1rem;
}
.cal-rules-day-listrow {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem 0;
  border-bottom: 1px solid var(--border);
}
.cal-rules-day-listrow-remove {
  color: var(--coral);
  margin-left: auto;
}
.cal-rules-day-add-section {
  border-top: 1px solid var(--border);
  padding-top: 1rem;
}
.cal-rules-day-save-wrap {
  margin-top: 1.5rem;
}
.cal-rules-day-save-btn { width: 100%; }
.cal-rules-empty-block {
  border-top: 1px solid var(--border);
  padding-top: 1rem;
}

/* ── Embed-Panel ───────────────────────────────────────────── */
.cal-embed-warn {
  padding: .75rem;
  background: var(--amber-light);
  border-radius: var(--radius-sm);
  font-size: .875rem;
  color: var(--amber);
  margin-bottom: 1rem;
}
.cal-embed-section {
  margin-bottom: 1.25rem;
}
.cal-embed-section-label {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: .5rem;
}
.cal-embed-link-row {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.cal-embed-code-inline {
  flex: 1;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: .5rem .625rem;
  font-size: .8125rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block;
}
.cal-embed-code-wrap { position: relative; }
.cal-embed-code-pre {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .75rem;
  font-size: .75rem;
  line-height: 1.6;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-all;
  margin: 0;
}
.cal-embed-copy-btn {
  position: absolute;
  top: .5rem;
  right: .5rem;
}
.cal-embed-hint {
  font-size: .8125rem;
  color: var(--text-tertiary);
  margin-top: .625rem;
  line-height: 1.5;
}
.cal-embed-platform-section {
  border-top: 1px solid var(--border);
  padding-top: 1rem;
}
.cal-embed-platform-list {
  font-size: .8125rem;
  color: var(--text-secondary);
  line-height: 1.6;
}
.cal-embed-platform-list > div {
  margin-bottom: .5rem;
}
.cal-embed-platform-list > div:last-child { margin-bottom: 0; }

/* ── Manual-Booking Form / Contact-Picker ──────────────────── */
.cal-mbf-headerrow {
  display: flex;
  align-items: center;
  gap: .625rem;
  margin-bottom: 1rem;
}
.cal-mbf-title {
  font-size: .9375rem;
  font-weight: 600;
}
.cal-mbf-subtitle {
  font-size: .8125rem;
  color: var(--text-secondary);
}
.cal-contact-picker-wrap { position: relative; }
.cal-contact-picker-clear {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  font-size: 1rem;
  line-height: 1;
}
.cal-contact-picker-results {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  z-index: 100;
  max-height: 220px;
  overflow-y: auto;
}
.cal-contact-picker-loading {
  padding: .75rem;
  color: var(--text-tertiary);
  font-size: .875rem;
}
.cal-contact-picker-row {
  padding: .625rem .875rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: .5rem;
}
.cal-contact-picker-row-name {
  font-size: .875rem;
  font-weight: 500;
}
.cal-contact-picker-row-email {
  font-size: .75rem;
  color: var(--text-tertiary);
}
.cal-mbf-actions {
  display: flex;
  gap: .5rem;
  margin-top: 1rem;
}
.cal-mbf-actions .btn-primary { flex: 1; }

/* ── Followup undo-toast button ────────────────────────────── */
.cal-undo-btn {
  margin-left: auto;
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
  text-decoration: underline;
  font-size: .8125rem;
  padding: 0 0 0 4px;
  flex-shrink: 0;
}

/* ── Flyout-Icon-Helper ────────────────────────────────────── */
.cal-flyout-loc-icon {
  color: var(--text-tertiary);
  vertical-align: -2px;
  margin-right: 4px;
}
.cal-flyout-vc-link {
  color: var(--accent);
  font-size: .875rem;
}
/* "Zur Mail öffnen" im Popover (Ticket 3.358.1) -- Button-Reset auf einem
   <button>-Klick-Handler (kein synchroner href, s. _openInviteMailTab), soll
   aber wie ein dezenter Inline-Link innerhalb der .cal-flyout-row aussehen,
   nicht wie der grosse .btn.btn-ghost.btn-sm-Button im Read-only-Panel. */
.cal-flyout-mail-link {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: var(--accent);
  font-size: .875rem;
  cursor: pointer;
  text-align: left;
}
.cal-flyout-mail-link:hover {
  text-decoration: underline;
}
.cal-flyout-source-badge {
  align-self: flex-start;
  margin-top: .25rem;
}

/* Kontakt/Projekt-Verknüpfung im Event-Formular (Spec 20260416_1200) —
   Single-Select-Picker im Teilnehmer-Look (wiederverwendet .ds-attendee-picker). */
.event-link-picker { min-height: 38px; }
.event-link-picker .attendee-chip { max-width: 100%; }

/* Klickbare Pill im Event-Flyout (Kontakt/Projekt-Navigation) */
.cal-flyout-link-pill {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .2rem .55rem;
  background: var(--accent-light);
  border-radius: var(--radius-sm);
  font-size: .825rem;
  color: var(--accent);
  text-decoration: none;
  font-weight: 500;
}
.cal-flyout-link-pill:hover {
  background: color-mix(in srgb, var(--accent) 20%, var(--bg-primary));
}

/* Booking-Quick-Info Meta-Zeile (Location-Type + Sprache als kleine Badges) */
.cal-flyout-booking-meta {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
  align-items: center;
}
.cal-flyout-booking-meta .badge {
  font-size: .7rem;
  padding: .125rem .5rem;
}

/* Kontaktname im Event-Block (wenn Höhe reicht) */
.cal-event-contact {
  font-size: .65rem;
  opacity: .75;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 1px;
}

/* Typ-Aktions-Buttons unten im Flyout (Spec 20260416_1000, Schritt 4) */
.cal-flyout-type-actions {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  margin-top: .5rem;
  padding-top: .5rem;
  border-top: 1px solid var(--border);
}
.cal-flyout-type-action {
  background: none;
  border: none;
  text-align: left;
  padding: .375rem .5rem;
  font-size: .82rem;
  color: var(--text-primary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  font-family: inherit;
}
.cal-flyout-type-action:hover {
  background: var(--bg-secondary);
  color: var(--accent);
}

/* ── Mobile day list entry (cal-mobile-day-entry) ──────────── */
.cal-mobile-day-entry-time {
  font-size: .8rem;
  color: var(--text-secondary);
}

/* ── Mobile day-list date clickable + push-top action ──────── */
.cal-mobile-day-list-date--clickable { cursor: pointer; }
.cal-mobile-day-list-action { margin-top: .75rem; }

/* ── Cal-Sidebar-Logo (Lokal-Header) ───────────────────────── */
.cal-sidebar-logo {
  border-radius: 50%;
}

/* ── Calendar Categories – Verwaltungsseite ────────────────── */
.cat-row {
  display: flex;
  align-items: center;
  gap: .65rem;
  padding: .625rem .5rem;
  border-bottom: 1px solid var(--border);
  transition: background 120ms ease;
  /* Ticket 3.208.1: position:relative verankert .is-drop-target::before;
     touch-action:pan-y lässt vertikales Scrollen der Liste zu (der
     Long-Press-Touch-Drag unterscheidet selbst zwischen Scroll und Ziehen,
     s. _onRowTouchStart/-Move in calendar-categories.js). */
  position: relative;
  touch-action: pan-y;
}
.cat-row:last-child { border-bottom: none; }
.cat-row:hover { background: var(--bg-secondary); }
.cat-row.is-dragging {
  opacity: .45;
}
.cat-row.is-dragging .cat-drag-handle { cursor: grabbing; }
.cat-row.is-drop-target::before {
  content: '';
  position: absolute;
  left: .25rem;
  right: .25rem;
  top: -1px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
}
/* Dauerhaft sichtbarer Griff (kein Hover-Reveal, Ticket 3.208.1 Auflage 2 —
   analog .todo-nav-drag-handle in ds-todo-project-nav.js). */
.cat-drag-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.125rem;
  height: 1.5rem;
  flex-shrink: 0;
  color: var(--text-tertiary);
  cursor: grab;
}
.cat-row--editing {
  flex-wrap: wrap;
  gap: .5rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  padding: .75rem;
  margin: .25rem 0;
}
.cat-row-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
}
.cat-row-name {
  flex: 1;
  font-size: .9rem;
  font-weight: 500;
  color: var(--text-primary);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cat-row-input {
  flex: 1;
  min-width: 120px;
  font-size: .875rem;
}
.cat-row-star,
.cat-row-edit,
.cat-row-delete {
  flex-shrink: 0;
  color: var(--text-tertiary);
  transition: color 120ms ease;
}
.cat-row-star:hover   { color: var(--amber); }
.cat-row-edit:hover   { color: var(--accent); }
.cat-row-delete:hover { color: var(--danger); }
/* Freie Farbwahl (Ticket 3.261.3): der Trigger für den geteilten
   Farb-Picker (window.ColorPicker) nutzt die bestehende
   .cal-sidebar-color-dot-Klasse — kein eigenes CSS nötig (identisches
   Muster wie ds-cal-sidebar.js/ds-todo-project-panel.js). Die vormalige
   eigene Preset-Palette (.cat-color-swatches) + das native Farb-Input
   (.cat-color-custom-row/-label) dieser Seite sind damit entfallen. */
/* Raster-Vorschau (Ticket 3.208.3 Auflage 3) — Mini-Nachbau der Grid-
   Termin-Optik aus calendar.js _renderMonthGrid(): Fläche = gewählte
   Farbe 12% mit --bg-primary gemischt, linker Rand = Farbe pur, Text
   bleibt --text-primary (theme-ehrlich in Hell UND Dunkel, keine
   erzwungene helle Fläche). --cal-color/--cal-bg werden inline per Style
   gesetzt (s. calendar-categories.js _renderEditRow). */
.cat-color-preview {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  margin-top: .125rem;
}
.cat-color-preview-label {
  font-size: .75rem;
  color: var(--text-tertiary);
  flex-shrink: 0;
}
.cat-color-preview-pill {
  display: inline-flex;
  align-items: center;
  height: 1.75rem;
  padding: 0 .625rem 0 .5rem;
  border-radius: 3px;
  border-left: 3px solid var(--cal-color);
  background: var(--cal-bg);
  color: var(--text-primary);
  font-size: .8125rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 14rem;
}

/* ── ds-recurrence-picker ──────────────────────────────────── */
.recurrence-picker {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .875rem;
}
.recurrence-picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .75rem;
}
.recurrence-activate-btn {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
}
.recurrence-freq-tabs {
  display: flex;
  gap: .25rem;
  margin-bottom: .75rem;
}
.recurrence-freq-tab {
  flex: 1;
  padding: .35rem .4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  font-size: .75rem;
  font-weight: 600;
  cursor: pointer;
  text-align: center;
  color: var(--text-primary);
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.recurrence-freq-tab.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.recurrence-freq-tab:hover:not(.active) {
  background: var(--bg-tertiary);
}
.recurrence-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: .5rem;
}
.recurrence-interval-input {
  width: 60px;
  text-align: center;
  font-size: .85rem;
  padding: .3rem .4rem;
}
.recurrence-day-chips {
  display: flex;
  gap: .3rem;
  margin: .5rem 0 .75rem;
}
.recurrence-day-chip {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-primary);
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-primary);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.recurrence-day-chip.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.recurrence-day-chip:hover:not(.active) {
  background: var(--bg-tertiary);
}
.recurrence-month-opts {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin: .5rem 0 .75rem;
}
.recurrence-radio-row {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .82rem;
  color: var(--text-primary);
  cursor: pointer;
}
.recurrence-radio-row input[type="radio"] {
  accent-color: var(--accent);
}
.recurrence-select-sm {
  font-size: .8rem;
  padding: .25rem .4rem;
  min-width: auto;
}
.recurrence-monthday-input {
  width: 52px;
  text-align: center;
  font-size: .82rem;
  padding: .25rem .35rem;
}
.recurrence-end-section {
  margin-top: .75rem;
  padding-top: .75rem;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.recurrence-date-input {
  font-size: .82rem;
  padding: .25rem .4rem;
  max-width: 160px;
}
.recurrence-count-input {
  width: 60px;
  text-align: center;
  font-size: .82rem;
  padding: .25rem .35rem;
}

/* ── Outlook-Style Collapsed Time-Row ──────────────────────── */
.event-time-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .625rem 0;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background 120ms ease;
}
.event-time-row:hover { background: var(--bg-secondary); border-radius: var(--radius-sm); }
.event-time-row-icon {
  flex-shrink: 0;
  color: var(--text-tertiary);
  width: 20px;
  display: flex;
  justify-content: center;
}
.event-time-row-text {
  flex: 1;
  font-size: .875rem;
  color: var(--text-primary);
}

/* ── Outlook-Style Expanded Time-Details ───────────────────── */
.event-time-details {
  padding: .625rem 0 .625rem 1.75rem;
  border-bottom: 1px solid var(--border);
}
.event-time-details-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: .75rem;
  margin-bottom: .625rem;
}
.event-time-details-grid--allday {
  grid-template-columns: 1fr 1fr;
}
.event-time-details-footer {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-top: .5rem;
}
.event-time-allday-check {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  font-size: .82rem;
  color: var(--text-primary);
  cursor: pointer;
}
.event-time-allday-check input[type="checkbox"] {
  accent-color: var(--accent);
  width: 16px;
  height: 16px;
}
.event-time-recur-btn {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: .8rem;
  color: var(--text-secondary);
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .25rem .5rem;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.event-time-recur-btn:hover { background: var(--bg-tertiary); }
.event-time-recur-btn--active {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-light);
}

/* Recurrence-Summary (Outlook-Style) */
.event-recurrence-summary {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .82rem;
  color: var(--accent);
  padding: .35rem 0 .35rem 1.75rem;
  border-bottom: 1px solid var(--border);
}
.event-recurrence-summary svg { flex-shrink: 0; }

/* ──────────────────────────────────────────────────────────────
   ds-context-menu – wiederverwendbares Right-Click-Menü
   Body-level via ContextMenu.open(event, items)
   ────────────────────────────────────────────────────────────── */
.ds-context-menu {
  position: fixed;
  top: 0;
  left: 0;
  /* Muss über dem .ds-context-menu-backdrop (z-index:1099, _core.css) liegen,
     sonst faengt das Backdrop alle Item-Klicks ab und das Menue schliesst ohne
     Action auszuloesen (Regression 2026-06-09 durch Backdrop-Einfuehrung). */
  z-index: 1100;
  min-width: 200px;
  max-width: min(320px, calc(100vw - 16px));
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, .04),
    0 14px 36px rgba(0, 0, 0, .18);
  padding: .25rem;
  opacity: 0;
  transform: translateY(-2px) scale(.97);
  transform-origin: top left;
  transition:
    opacity 140ms cubic-bezier(.16, 1, .3, 1),
    transform 140ms cubic-bezier(.16, 1, .3, 1);
}
/* Höhenbegrenzung + Scroll (Ticket 3.255) — NUR im schmalen/Accordion-Zustand
   (`.is-narrow`, von ds-context-menu.js beim Öffnen gesetzt, spiegelt
   `_isNarrowScreen()` ≤480px 1:1, s. dortiger Kommentar). Bewusst NICHT
   ungescoped auf `.ds-context-menu` selbst: `overflow-y:auto` zwingt laut
   CSS-Overflow-Spezifikation auch `overflow-x` auf `auto` (man kann die Achsen
   nicht mischen, sobald eine von `visible` abweicht) — das würde die
   Desktop-Flyout-Untermenüs (`.ds-context-menu-submenu`, `position:absolute`,
   ragen bewusst ÜBER den rechten Rand des Root-Rahmens hinaus) auf einen
   4px-Streifen zusammenschneiden, empirisch verifiziert (`elementFromPoint`
   traf an der visuellen Submenü-Position auf `<body>` statt auf das Submenü).
   Im schmalen Zustand rendern Untermenüs dagegen als Inline-Accordion
   (`position:static`, normaler Fluss, s. `.ds-context-menu-submenu--inline`
   in _core.css) — dort ist kein Flyout im Spiel, Scroll-Clipping ist
   gefahrlos. Fallback-dann-dvh-Paar wie im Board-Mobile-Pattern
   (`_todos.css`): eine unbekannte Einheit macht die GESAMTE Deklaration
   ungültig, die Kaskade fällt dann auf die vh-Zeile zurück. */
.ds-context-menu.is-narrow {
  max-height: calc(100vh - 16px);
  max-height: calc(100dvh - 16px);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.ds-context-menu.is-open {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.ds-context-menu.is-closing {
  opacity: 0;
  transform: translateY(-2px) scale(.97);
}
:root[data-theme="dark"] .ds-context-menu,
:root:not([data-theme="light"]) .ds-context-menu {
  box-shadow:
    0 1px 2px rgba(0, 0, 0, .4),
    0 14px 36px rgba(0, 0, 0, .6);
}
.ds-context-menu-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.ds-context-menu-item {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .5rem .7rem;
  font-size: .82rem;
  color: var(--text-primary);
  border-radius: var(--radius-sm);
  cursor: pointer;
  user-select: none;
  transition: background 120ms ease, color 120ms ease;
}
.ds-context-menu-item:hover {
  background: var(--bg-secondary);
}
.ds-context-menu-item.is-danger {
  color: var(--danger);
}
.ds-context-menu-item.is-danger:hover {
  background: var(--danger-light);
}
.ds-context-menu-item.is-disabled {
  color: var(--text-tertiary);
  cursor: not-allowed;
  opacity: .55;
}
.ds-context-menu-item.is-disabled:hover {
  background: transparent;
}
.ds-context-menu-icon {
  display: inline-flex;
  width: 16px;
  height: 16px;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--text-secondary);
}
.ds-context-menu-item.is-danger .ds-context-menu-icon { color: var(--danger); }
.ds-context-menu-label {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-context-menu-shortcut {
  font-size: .72rem;
  color: var(--text-tertiary);
  margin-left: .5rem;
}
.ds-context-menu-sep {
  height: 1px;
  background: var(--border);
  margin: .25rem .35rem;
}

/* ── Mobile view-select (Schritt 16) – sichtbar nur < 600px ── */
.cal-view-select {
  display: none;
  appearance: none;
  -webkit-appearance: none;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.25rem 1.75rem 0.25rem 0.625rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-primary);
  cursor: pointer;
  /* chevron via background */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' viewBox='0 0 24 24' stroke='%23999' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 6px center;
}

/* ── Inline-Erstellung (Schritt 11) ── */
.cal-inline-create {
  position: absolute;
  left: 2px; right: 2px;
  background: color-mix(in srgb, var(--accent) 10%, var(--bg-primary));
  border-left: var(--cal-event-border-width) solid var(--accent);
  border-radius: var(--cal-event-radius);
  padding: 6px 8px;
  z-index: 20;
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
  gap: 4px;
  box-sizing: border-box;
}
.cal-inline-input {
  width: 100%;
  border: none;
  background: transparent;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-primary);
  outline: none;
  padding: 0;
}
.cal-inline-input::placeholder { color: var(--text-tertiary); }
.cal-inline-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.75rem;
  color: var(--text-secondary);
}
.cal-inline-more {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 0.75rem;
  cursor: pointer;
  padding: 0;
  text-decoration: underline;
  flex-shrink: 0;
}
.cal-inline-more:hover { opacity: 0.8; }
.cal-inline-actions {
  display: flex;
  gap: 4px;
  margin-top: 2px;
}

/* ── Calendar Mobile (Schritt 16) ── */
@media (max-width: 900px) {
  /* Toolbar compact */
  .cal-toolbar { padding: 0.375rem 0.75rem; gap: 0.5rem; }
  .cal-toolbar-date { font-size: 0.9375rem; }
  /* "Neuer Termin"-Button ausblenden – FAB übernimmt */
  .cal-toolbar-new-btn { display: none; }

  /* View-Switcher Buttons kleinere Schrift */
  .cal-view-switcher { flex-wrap: wrap; }
  .cal-view-btn { padding: 0.2rem 0.4rem; font-size: 0.75rem; }

  /* Spalten-Header */
  .cal-week-hd-dow { font-size: 0.62rem; }
  .cal-week-hd-num { font-size: 0.82rem; width: 22px; height: 22px; }

  /* Zeitraster Mobile: Sticky Time-Gutter bleibt bei vertikalem Scroll fixiert.
     3-Tage-View braucht kein horizontales Scrollen (3 Spalten passen). */
  .cal-time-grid-wrap {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
  }
  page-calendar .cal-time-scroll {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
  }
  .cal-day-col { min-width: 0; }

  /* Mobile Kalender-Navbar – Pill-Navigation + flache Icon-Actions.
     Design: kompakt, CD-konform, klare Trennung zwischen Date-Nav
     (pillförmig in der Mitte) und Actions (Icon-Buttons rechts). */
  .cal-mobile-navbar {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .75rem;
    border-bottom: 1px solid var(--border);
    background: var(--bg-primary);
    flex-shrink: 0;
    position: relative;
  }

  .cal-mobile-nav-pill {
    flex: 1;
    display: flex;
    align-items: stretch;
    min-width: 0;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 999px;
    overflow: hidden;
    height: 36px;
  }
  .cal-mobile-nav-arrow,
  .cal-mobile-nav-date-btn {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-primary);
    padding: 0 .625rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background var(--transition), color var(--transition);
  }
  .cal-mobile-nav-arrow {
    flex-shrink: 0;
    color: var(--text-secondary);
  }
  .cal-mobile-nav-arrow:active,
  .cal-mobile-nav-arrow:hover { background: var(--bg-primary); color: var(--accent); }
  /* Datum-Label-Button — oeffnet den Datums-Picker (Nutzer-Feedback #6,
     2026-07-18; ersetzt den vormaligen "springt zu Heute"-Klick — die
     Heute-Funktion sitzt jetzt im separaten .cal-mobile-nav-today-btn daneben). */
  .cal-mobile-nav-date-btn {
    flex: 1;
    min-width: 0;
    padding: 0 .5rem;
    font-weight: 600;
  }
  .cal-mobile-nav-date-btn:active { background: var(--accent-light); }
  .cal-mobile-nav-date-btn.active {
    background: var(--accent-light);
    color: var(--accent);
  }
  .cal-mobile-nav-label {
    display: block;
    font-size: .85rem;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* Separates Heute-Icon direkt neben der Pill (Nutzer-Feedback #6) — nutzt
     dieselbe .cal-mobile-action-Optik wie Sync/Teilen/Menue. */
  .cal-mobile-nav-today-btn { flex-shrink: 0; }

  .cal-mobile-action {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border: 1px solid var(--border);
    background: var(--bg-secondary);
    border-radius: var(--radius-md);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    cursor: pointer;
    transition: color var(--transition), background var(--transition), border-color var(--transition);
  }
  .cal-mobile-action:hover,
  .cal-mobile-action:active {
    color: var(--accent);
    border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
    background: var(--bg-primary);
  }
  .cal-mobile-action:disabled { opacity: .55; cursor: default; }
  .cal-mobile-action.spin svg { animation: spin 1s linear infinite; }
  .cal-mobile-action[aria-expanded="true"] {
    color: var(--accent);
    background: var(--accent-light);
    border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
  }

  /* Terminanfragen-Badge in der Mobile-Navbar */
  .cal-mobile-appt-badge {
    position: relative;
    color: var(--amber);
    border-color: var(--amber);
    background: var(--amber-light);
  }
  .cal-mobile-appt-badge:hover,
  .cal-mobile-appt-badge:active {
    color: var(--amber);
    background: var(--amber-light);
    border-color: var(--amber);
    opacity: .85;
  }
  .cal-mobile-appt-dot {
    position: absolute;
    top: 3px;
    right: 3px;
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: var(--amber);
    border: 1.5px solid var(--bg-primary);
    pointer-events: none;
  }

  /* Mobile: Card-Overflow aufheben, damit Dropdowns aus der Navbar
     herausragen dürfen. */
  page-calendar .cal-page-main > .cal-content-host .card { overflow: visible; }

  .cal-mobile-menu-wrap {
    position: relative;
  }
  .cal-mobile-menu-backdrop {
    position: fixed; inset: 0; z-index: 50; background: transparent;
  }
  .cal-mobile-menu {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    z-index: 51;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    min-width: 180px;
    padding: .375rem 0;
    animation: calMenuIn 140ms ease both;
  }
  @keyframes calMenuIn {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  .cal-mobile-menu-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    width: 100%;
    padding: .625rem 1rem;
    background: none;
    border: none;
    text-align: left;
    font-size: .875rem;
    color: var(--text-primary);
    cursor: pointer;
  }
  .cal-mobile-menu-item:hover { background: var(--bg-secondary); }
  .cal-mobile-menu-item.active { color: var(--accent); font-weight: 600; }
  .cal-mobile-menu-item svg { color: var(--accent); flex-shrink: 0; }
  .cal-mobile-menu-item-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .cal-mobile-menu-group-title {
    padding: .5rem 1rem .25rem;
    font-size: .65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text-tertiary);
  }
  .cal-mobile-menu-divider {
    height: 1px;
    margin: .375rem 0;
    background: var(--border);
  }
  .cal-mobile-menu-subdivider {
    height: 1px;
    margin: .25rem 1rem;
    background: var(--border);
  }
  .cal-mobile-menu-cal {
    display: flex;
    align-items: center;
    gap: .625rem;
    width: 100%;
    padding: .5rem 1rem;
    background: none;
    border: none;
    text-align: left;
    font-size: .85rem;
    color: var(--text-primary);
    cursor: pointer;
  }
  .cal-mobile-menu-cal:hover { background: var(--bg-secondary); }
  .cal-mobile-menu-cal-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--color, var(--accent));
    flex-shrink: 0;
  }
  .cal-mobile-menu-cal-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-primary);
  }
  /* Check-Icon-Slot immer gleich breit, Icon selbst nur wenn active */
  .cal-mobile-menu-cal-check {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .cal-mobile-menu-cal-check svg { color: var(--accent); }

  /* Flyout als Bottom-Sheet */
  .cal-flyout {
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    top: auto !important;
    width: 100% !important;
    max-width: 100% !important;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    animation: calFlyoutBottomIn 250ms ease forwards;
    max-height: 80vh;
    overflow-y: auto;
  }
}

/* ── Agenda-View (Mobile-first Monats-Mini + Tages-Liste) ───────────
   Funktioniert auch auf Desktop falls manuell gewählt.
   flex:1 + min-height:0 reihen sich in die bestehende Flex-Chain
   (card-body → .cal-agenda → .cal-agenda-list) ein. */
.cal-agenda {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  background: var(--bg-primary);
}

.cal-agenda-mini {
  padding: .75rem .75rem .5rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-primary);
  flex-shrink: 0;
}
.cal-agenda-mini-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: .5rem;
}
.cal-agenda-mini-month {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-primary);
  text-transform: capitalize;
  letter-spacing: -.01em;
}
.cal-agenda-mini-grid-head {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 2px;
  margin-bottom: .125rem;
}
.cal-agenda-mini-dow {
  text-align: center;
  font-size: .65rem;
  font-weight: 600;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.cal-agenda-mini-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 2px;
}
.cal-agenda-mini-cell {
  position: relative;
  aspect-ratio: 1;
  border: none;
  background: none;
  border-radius: 50%;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-primary);
  font-size: .85rem;
  transition: background var(--transition), color var(--transition);
  padding: 0;
}
.cal-agenda-mini-cell--other {
  /* Nachbarmonats-Zellen (Ticket 3.390.1): gedaempfte, aber weiterhin
     anklickbare Tageszahl -- ohne Farbpunkte, da fuer Nachbarmonate keine
     Events geladen sind (s. modules/calendar.md). */
  color: var(--text-tertiary);
}
.cal-agenda-mini-cell:hover { background: var(--bg-secondary); }
.cal-agenda-mini-num {
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.cal-agenda-mini-dots-row {
  position: absolute;
  bottom: 3px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 2px;
  align-items: center;
  pointer-events: none;
}
.cal-agenda-mini-dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--color, var(--accent));
}
.cal-agenda-mini-cell.is-today {
  color: var(--accent);
  font-weight: 700;
}
.cal-agenda-mini-cell.is-sel {
  background: var(--accent);
  color: #fff;
  font-weight: 600;
}
.cal-agenda-mini-cell.is-sel .cal-agenda-mini-dot {
  background: #fff;
}
.cal-agenda-mini-cell.is-today.is-sel { color: #fff; }

.cal-agenda-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: .25rem 0 2rem;
}
.cal-agenda-empty {
  padding: 3rem 1rem;
  text-align: center;
  color: var(--text-tertiary);
  font-size: .9rem;
}
.cal-agenda-day {
  display: flex;
  flex-direction: column;
  border-bottom: 1px solid var(--border);
}
.cal-agenda-day-head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: baseline;
  gap: .625rem;
  padding: .75rem 1rem .375rem;
  background: color-mix(in srgb, var(--bg-primary) 94%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.cal-agenda-day-num {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
.cal-agenda-day-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  line-height: 1;
}
.cal-agenda-day-dow {
  font-size: .7rem;
  font-weight: 600;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .06em;
}
.cal-agenda-day-month {
  font-size: .7rem;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.cal-agenda-day.is-today .cal-agenda-day-num { color: var(--accent); }
.cal-agenda-day-today-pill {
  margin-left: auto;
  padding: 2px 8px;
  background: var(--accent);
  color: #fff;
  font-size: .65rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  border-radius: 999px;
}
.cal-agenda-day-body {
  display: flex;
  flex-direction: column;
  padding: 0 1rem .625rem;
  gap: .375rem;
}
.cal-agenda-entry {
  display: grid;
  grid-template-columns: 54px 4px 1fr;
  align-items: stretch;
  gap: .625rem;
  padding: .625rem .5rem;
  background: none;
  border: none;
  border-radius: var(--radius-md);
  text-align: left;
  cursor: pointer;
  transition: background var(--transition);
  width: 100%;
  /* iOS-Long-Press-Hardening: verhindert, dass der native Callout/Text-
     Auswahl-Long-Press unseren 500ms-Kontextmenü-Timer kapert (analog
     .cal-event-block/.cal-event-bar). */
  -webkit-touch-callout: none;
  user-select: none;
}
.cal-agenda-entry:hover,
.cal-agenda-entry:active { background: var(--bg-secondary); }
.cal-agenda-entry-time {
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  padding-top: 2px;
}
.cal-agenda-entry-bar {
  width: 4px;
  border-radius: 999px;
  background: var(--ev-color, var(--accent));
}
.cal-agenda-entry-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.cal-agenda-entry-title {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  font-size: .9rem;
  font-weight: 500;
  color: var(--text-primary);
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cal-agenda-entry-loc {
  font-size: .75rem;
  color: var(--text-tertiary);
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cal-agenda-entry.is-holiday .cal-agenda-entry-time {
  color: var(--rose);
  font-weight: 700;
}
.cal-agenda-entry.is-followup .cal-agenda-entry-time {
  color: var(--amber);
  font-weight: 600;
}
.cal-agenda-day.is-empty { opacity: 0.55; }
.cal-agenda-day.is-empty .cal-agenda-day-num { font-weight: 500; }
.cal-agenda-empty-day {
  font-size: .8rem;
  color: var(--text-tertiary);
  padding: .25rem .5rem .5rem;
}

/* ── Endless-Agenda: Rand-Sentinels + Lade-Indikator (Ticket 3.390.2) ───
   .cal-agenda-month-nav (Vorheriger/Naechster-Monat-Buttons) entfaellt --
   die Liste scrollt seither durchgehend ueber Monatsgrenzen, s.
   pages/calendar/_agenda.js::_agendaLoadMore(). */
.cal-agenda-edge-sentinel {
  height: 1px;
  visibility: hidden;
  pointer-events: none;
}
.cal-agenda-loadmore {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: .75rem;
}

/* ── Mobile-Monatsansicht: Bar + Dot-Marker pro Tag ─────────────── */
.cal-day-mob-markers {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  margin-top: 2px;
  width: 100%;
}
.cal-day-mob-bar {
  display: block;
  width: 100%;
  height: 4px;
  border-radius: 2px;
  background: var(--color, var(--accent));
}
.cal-day-mob-bar-more {
  font-size: .58rem;
  color: var(--text-tertiary);
  line-height: 1;
  padding-left: 1px;
}
.cal-day-mob-dots {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  align-items: center;
  padding-left: 1px;
}
.cal-day-mob-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color, var(--accent));
  flex-shrink: 0;
}
.cal-day-mob-dot-more {
  font-size: .58rem;
  color: var(--text-tertiary);
  line-height: 1;
  margin-left: 1px;
}

/* Mobile-only Anpassungen: knappere Abstände */
@media (max-width: 600px) {
  .cal-agenda-mini { padding: .625rem .625rem .375rem; }
  .cal-agenda-mini-cell { font-size: .8rem; }
  .cal-agenda-day-head { padding: .625rem .75rem .25rem; }
  .cal-agenda-day-body { padding: 0 .75rem .5rem; }
  .cal-agenda-entry { grid-template-columns: 48px 3px 1fr; gap: .5rem; padding: .5rem .375rem; }
}

/* Sehr kleine Screens (< 600px): native Select statt Pill-Buttons */
@media (max-width: 600px) {
  .cal-view-switcher { display: none; }
  .cal-view-select   { display: block; }
}

/* Mobile overrides */
@media (max-width: 900px) {
  /* Full-width native list card (busts out of #app horizontal padding) */
  .native-list-card {
    border-radius: 0 !important;
    border-left:   none !important;
    border-right:  none !important;
    box-shadow:    none !important;
    margin-left:  -1rem !important;
    margin-right: -1rem !important;
    width: calc(100% + 2rem) !important;
  }
  /* Hide desktop "Neu erstellen" buttons — FAB handles this on mobile */
  .page-header-actions { display: none; }
  /* Hide per-page selector in pagination */
  .pagination-perpage  { display: none; }
}
@media (max-width: 600px) {
  .native-list-card {
    margin-left:  -0.75rem !important;
    margin-right: -0.75rem !important;
    width: calc(100% + 1.5rem) !important;
  }
}

/* ── Calendar Slide-In Panel ──────────────────────────────────── */
/* Ticket 3.354: die eigenstaendige ds-calendar-panel-Komponente ist entfernt
   (durch components/ds-cal-panel.js ersetzt) — deren "display:contents"-Regel
   war eine reine Wiederholung der ds-cal-panel-Regel weiter unten (Zeile
   ~6047) und ist ersatzlos gestrichen, keine Verhaltensaenderung. */

.ds-cal-panel-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.35);
  z-index: 400;
}
.ds-cal-panel-backdrop.open { display: block; }

.ds-cal-panel {
  position: fixed;
  top: 0;
  right: -100%;
  bottom: 0;
  width: clamp(480px, calc((100vw - var(--sidebar-width, 240px)) * 0.7), 900px);
  background: var(--bg-primary);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  z-index: 401;
  display: flex;
  flex-direction: column;
  transition: right var(--transition-slow);
  overflow: hidden;
}
.ds-cal-panel.open { right: 0; }

.ds-cal-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 1rem 1rem 0.75rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.ds-cal-panel-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-primary);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Sync-Zustands-Icon vor dem Titel im Read-only Termin-Panel (Punkt 6,
   `_showEventPanel`). Gegenstueck zum Grid-Warn-Badge `.cal-event-sync-badge`.
   Nur bei extern zugeordneten, NICHT synchronisierten Events
   (ev.calendar_connection_id && !synced): Warn-Dreieck (amber). Die positive
   "synchronisiert"-Anzeige wurde entfernt (Nutzer-Feedback 2026-07-18) —
   `--synced` bleibt als CSS bestehen (DEPRECATED, nicht mehr gerendert). */
.cal-panel-title-sync-icon {
  display: inline-flex;
  vertical-align: middle;
  margin-right: .375rem;
  flex-shrink: 0;
}
.cal-panel-title-sync-icon--synced   { color: var(--teal); } /* DEPRECATED — nicht mehr gerendert, s.o. */
.cal-panel-title-sync-icon--unsynced { color: var(--amber); }
.ds-cal-panel-body {
  flex: 1;
  overflow-y: auto;
  padding: 0.875rem 1rem;
}

/* Panel event list */
.ds-panel-event {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 0.625rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition);
}
.ds-panel-event:hover { background: var(--bg-secondary); }
.ds-panel-event-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.ds-panel-event-title {
  flex: 1;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-panel-event-time {
  font-size: 0.8rem;
  color: var(--text-secondary);
  flex-shrink: 0;
}
.ds-panel-empty {
  font-size: 0.875rem;
  color: var(--text-tertiary);
  padding: 0.5rem 0;
}

/* Mobile: panel takes full width */
@media (max-width: 900px) {
  .ds-cal-panel {
    width: 100%;
    top: 0;
  }
  .ds-cal-panel-backdrop.open { display: block; }
  /* Griff antippen schliesst zusaetzlich zum Ziehen (Paket 2, Ticket
     3.254.2) -- .ds-cal-panel-title ist bereits der Wisch-Griff (s.
     ds-cal-panel.js _attachSwipe()), NUR mobil aktiv
     (Desktop bleibt reiner Text, kein Cursor-Wechsel). */
  .ds-cal-panel-title { cursor: pointer; }
}

/* ── ds-cal-panel custom element (Invoicing + Settings) ─────────── */
ds-cal-panel { display: contents; }

/* Secondary panel: same dimensions as primary, higher z-index, slightly offset */
.ds-cal-panel-secondary {
  z-index: 403; /* above primary (401) + its backdrop (400) */
  /* Slide offset: starts 100% right (same as primary), settles at same position */
}
.ds-cal-panel-secondary.open { right: 0; }

/* Secondary backdrop: sits between primary panel and secondary panel */
.ds-cal-panel-secondary-backdrop {
  z-index: 402;
  background: rgba(0,0,0,0.2); /* lighter than primary backdrop */
}

/* Secondary panel header: back-arrow left, title center, close right */
.ds-cal-panel-secondary .ds-cal-panel-header {
  gap: 0.25rem;
}
.ds-cal-panel-secondary .ds-cal-panel-title {
  text-align: center;
}

@media (max-width: 900px) {
  .ds-cal-panel-secondary {
    width: 100%;
    top: 0;
  }
}

/* ── Calendar Mobile Split-Layout (Step 11) ────────────────────── */
.cal-mobile-day-list { display: none; }

@media (max-width: 900px) {
  .cal-mobile-split {
    display: flex;
    flex-direction: column;
    gap: 0;
  }
  .cal-mobile-split .cal-grid {
    border-bottom: 1px solid var(--border);
  }
  .cal-mobile-day-list {
    display: block;
    padding: 0.75rem 0.875rem;
    min-height: 120px;
  }
  .cal-mobile-day-list-date {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 0.5rem;
  }
  .cal-mobile-day-entry {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.3125rem 0;
    border-bottom: 1px solid var(--border);
    font-size: 0.875rem;
  }
  .cal-mobile-day-entry:last-child { border-bottom: none; }
}

/* ── Phase B: Mobile Monatsansicht iOS-Stil (.cal-month-mobile-*) ──────────
   Nur aktiv auf ≤900px. Desktop-Monatsansicht (.cal-mobile-split / .cal-grid)
   bleibt vollständig unverändert.
   Neue Klassen-Familie: .cal-month-mobile* (kein Konflikt mit bestehenden Klassen).
   Reuse: .cal-agenda-day / .cal-agenda-entry / .cal-agenda-day-head (unverändert). */

/* Basis-Deklaration (Desktop: Klasse wird nicht gerendert) */
.cal-month-mobile { display: none; }

@media (max-width: 900px) {
  /* ── Äußerer Wrapper: füllt den Card-Body vollständig */
  .cal-month-mobile {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    background: var(--bg-primary);
  }

  /* ── Kompaktes Raster (oberer Bereich, feste Höhe) */
  .cal-month-mobile-grid {
    flex-shrink: 0;
    border-bottom: 1px solid var(--border);
    padding: .375rem .5rem .25rem;
    background: var(--bg-primary);
  }

  .cal-month-mobile-weekdays {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 2px;
    margin-bottom: .125rem;
  }

  .cal-month-mobile-dow {
    text-align: center;
    font-size: .6rem;
    font-weight: 600;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: .04em;
    padding: .125rem 0;
  }

  .cal-month-mobile-cells {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 2px;
  }

  /* Basis-Tageszelle: rund, kompakt, Touch-Target ≥ 40 px */
  .cal-month-mobile-cell {
    position: relative;
    aspect-ratio: 1;
    min-width: 0;
    border: none;
    background: transparent;
    border-radius: 50%;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    padding: 0;
    color: var(--text-primary);
    font-size: .8rem;
    font-weight: 400;
    transition: background var(--transition), color var(--transition);
    /* Touch-Target: mind. 40×40px — aspect-ratio 1 + min container breite */
    min-height: 36px;
  }

  .cal-month-mobile-cell--other {
    color: var(--text-tertiary);
    pointer-events: none;
    font-size: .75rem;
    opacity: .45;
  }

  .cal-month-mobile-cell:hover {
    background: var(--bg-secondary);
  }

  .cal-month-mobile-cell.is-weekend {
    color: var(--text-tertiary);
  }

  /* Heute: accent-Kreis */
  .cal-month-mobile-cell.is-today .cal-month-mobile-num {
    background: var(--accent);
    color: #fff;
    border-radius: 50%;
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: .8rem;
  }

  /* Ausgewählter Tag: accent-light Ring + accent Text */
  .cal-month-mobile-cell.is-sel:not(.is-today) .cal-month-mobile-num {
    background: var(--accent-light);
    color: var(--accent);
    border-radius: 50%;
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: .8rem;
    outline: 2px solid var(--accent);
    outline-offset: 1px;
  }

  /* Heute UND ausgewählt: volle accent-Farbe */
  .cal-month-mobile-cell.is-today.is-sel .cal-month-mobile-num {
    background: var(--accent-dark);
    color: #fff;
    border-radius: 50%;
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: .8rem;
  }

  .cal-month-mobile-num {
    line-height: 1;
  }

  /* Event-Dots unter der Tageszahl */
  .cal-month-mobile-dot-row {
    display: flex;
    gap: 2px;
    align-items: center;
    justify-content: center;
  }

  .cal-month-mobile-dot {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--color, var(--accent));
    flex-shrink: 0;
  }

  /* ── Scrollbare Tagesagenda (unterer Bereich) */
  .cal-month-mobile-agenda {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: var(--bg-primary);
  }

  /* Ausgewählter Tag in der Agenda: leichte Hervorhebung (nicht ablenkend) */
  .cal-month-mobile-agenda-day.is-sel > .cal-agenda-day-head {
    background: var(--accent-light);
  }

  .cal-month-mobile-agenda-day.is-sel > .cal-agenda-day-head .cal-agenda-day-num {
    color: var(--accent);
    font-weight: 700;
  }

  /* Sticky Day-Header in der Agenda (wie bestehende Agenda-View) */
  .cal-month-mobile-agenda .cal-agenda-day-head {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--bg-primary);
  }

  /* Monatstrennlinie — visuell deutlich wenn Monatsgrenze im Scroll */
  .cal-month-mobile-agenda-day:first-child,
  .cal-month-mobile-agenda-day[data-iso$="-01"] {
    border-top: 2px solid var(--border);
    margin-top: .25rem;
  }
  .cal-month-mobile-agenda-day:first-child {
    border-top: none;
    margin-top: 0;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   MAIL – E-Mail-Client Dreispalter
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Calendar-Invite-Block (ICS-Einladung im Mail-Detail) ─────────────
   Outlook-Style: Termin-Kopf, Meta-Zeilen, Kalender-Dropdown, RSVP-Buttons.
   Sitzt zwischen Image-Banner und Mail-Body, wirkt wie eine Aktions-Card. */
.mail-invite-block {
  margin: .75rem 1.25rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg-secondary);
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.mail-invite-header {
  display: flex;
  align-items: center;
  gap: .5rem;
  color: var(--accent);
  font-weight: 600;
  font-size: .875rem;
}
.mail-invite-title { letter-spacing: .02em; }
.mail-invite-body {
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
.mail-invite-summary {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: .25rem;
}
.mail-invite-meta-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  color: var(--text-secondary);
  font-size: .85rem;
}
.mail-invite-meta-row svg { flex-shrink: 0; opacity: .8; }
.mail-invite-form {
  display: flex;
  gap: .75rem;
  flex-wrap: wrap;
}
.mail-invite-actions {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
}
@media (max-width: 600px) {
  .mail-invite-block { margin: .5rem .75rem; padding: .75rem; }
  .mail-invite-form  { flex-direction: column; }
  .mail-invite-actions .btn { flex: 1; }
}

.mail-iframe {
  width: 100%;
  height: 100%;
  min-height: 400px;
  border: none;
  display: block;
}

.mail-text-body {
  padding: 1rem 1.25rem;
  font-size: 0.875rem;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: inherit;
  color: var(--text-primary);
  margin: 0;
}

.mail-attachments {
  padding: 0.75rem 1.25rem;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

.mail-attach-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.5rem;
}

.mail-attach-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}

.mail-attach-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.375rem 0.75rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  font-size: 0.8125rem;
  color: var(--text-primary);
  background: var(--bg-secondary);
  text-decoration: none;
  cursor: pointer;
  transition: all var(--transition);
}
.mail-attach-chip:hover { background: var(--bg-tertiary); border-color: var(--accent); }

.mail-attach-size {
  color: var(--text-tertiary);
  font-size: 0.75rem;
}

/* ── Booking-RSVP-Workflow (Spec 20260511_1200) ─────────────────────────── */

/* RSVP-Selectbox in der Event-Editor-Toolbar */
.cal-rsvp-select {
  min-width: 8.5rem;
}

/* Strikethrough-Darstellung für verschobene / stornierte Events */
.cal-event-rescheduled {
  opacity: .55;
}
/* Wird ausschliesslich auf .cal-event-block gesetzt (Zeitraster) -- die
   opacity oben ist dort durch calEventIn (fill-mode:both) strukturell
   wirkungslos, s. Kommentar bei .cal-event-block. animation-name-Override
   haelt den gedaempften Endwert. */
.cal-event-block.cal-event-rescheduled {
  animation-name: calEventInDim55;
}
.cal-event-rescheduled .cal-event-block-title {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

/* Teilnahme-basierte Darstellung für fremd-organisierte Events, abgelehnt
   (Spec 20260710, F-9/Schritt 8) — analoge Optik zu .cal-event-rescheduled */
.cal-event-declined {
  opacity: .55;
}
/* .cal-event-bar hat keine Entry-Animation (opacity oben greift dort
   normal); .cal-event-block traegt calEventIn und braucht den Override. */
.cal-event-block.cal-event-declined {
  animation-name: calEventInDim55;
}
.cal-event-declined .cal-event-block-title {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}
/* Monatsansicht: Titel-Text liegt direkt im .cal-event-bar (kein Title-Span) */
.cal-event-bar.cal-event-declined {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

/* ── Wiedervorlage im Kalenderraster: zurueckgenommener Zustand (Ticket 3.377.2) ──
   Erledigte Wiedervorlagen bleiben im Raster stehen (Domenico 26.08.2026: "zurueck-
   genommen darstellen, wie vorgeschlagen" -- Ausblenden ist ausdruecklich verworfen),
   ruecken aber optisch zurueck: Position/Hoehe/Reihenfolge bleiben unveraendert.
   Bewusst SCHWAECHER gedaempft als .cal-event-declined/-rescheduled (opacity .55) --
   der schwaechere Wert ist nach der Mobile-Lesbarkeitspruefung (375px, klein
   geschriebener durchgestrichener Text) gewaehlt, siehe Umsetzungsreport. Verschoben
   ist ein DRITTER, eigener Zustand (weder offen noch erledigt, Termin bleibt aktiv
   und faellig) -- eigene, dezente Kennzeichnung ueber die vorhandene amber-
   Statusfarbe (FOLLOWUP_STATUS_COLORS.snoozed in calendar.js), kein Durchstreichen,
   keine Daempfung. Klassen werden zentral von followupStatusCls(ev) vergeben
   (calendar.js) -- ein Aufrufer je Grid-Renderstelle, P-5. */
.cal-event-bar.cal-followup-done,
.cal-event-block.cal-followup-done,
.cal-followup-bar.cal-followup-done,
.cal-agenda-entry.cal-followup-done {
  opacity: .78;
}
/* 🔒 .cal-event-block traegt calEventIn (Entry-Fade, fill-mode:both) --
   eine gefuellte Animation gewinnt in der Kaskade IMMER gegen die normale
   `opacity`-Deklaration oben, das Dimmen war fuer diese Renderstelle
   (Zeitraster Tag/Woche) dadurch strukturell wirkungslos (Klasse wurde
   korrekt gesetzt, computed opacity blieb 1). .cal-event-bar/.cal-followup-
   bar/.cal-agenda-entry haben keine Entry-Animation und sind NICHT
   betroffen. Fix: eigenes animation-name, das NUR den Endwert aendert und
   Dauer/Timing/Fill-Mode von .cal-event-block erbt -- NICHT durch eine
   normale opacity-Deklaration "aufraeumen", das macht es wieder wirkungslos.
   Ticket 3.377.2 Nachtrag, 2026-08-27. */
.cal-event-block.cal-followup-done {
  animation-name: calEventInDim78;
}
.cal-event-bar.cal-followup-done,
.cal-followup-done .cal-event-block-title,
.cal-followup-bar.cal-followup-done span,
.cal-followup-done .cal-agenda-entry-title {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}
.cal-month-mobile-dot.cal-followup-done { opacity: .5; }

.cal-event-bar.cal-followup-snoozed,
.cal-event-block.cal-followup-snoozed,
.cal-followup-bar.cal-followup-snoozed {
  /* Gleiches Ring-Muster wie .cal-event-has-counter oben -- outline statt
     box-shadow (haelt Hover-box-shadow intakt, unabhaengig von position:static). */
  outline: 1px solid var(--amber);
  outline-offset: -1px;
}
.cal-agenda-entry.cal-followup-snoozed .cal-agenda-entry-bar {
  background: var(--amber);
}
.cal-month-mobile-dot.cal-followup-snoozed {
  box-shadow: 0 0 0 1.5px var(--amber);
}

/* Pfeil-Icon für Events die einen Nachfolger haben (replaced_by_event_id) */
.cal-event-replaced {
  position: relative;
}
.cal-event-replaced-arrow {
  position: absolute;
  top: 2px;
  right: 4px;
  width: 14px;
  height: 14px;
  color: var(--text-tertiary);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
}
.cal-event-replaced-arrow:hover { color: var(--accent); }

/* Reschedule-Badge in Event-Blocks (z.B. offene Anfrage) */
.cal-reschedule-badge {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .125rem .375rem;
  font-size: .68rem;
  background: var(--amber-light);
  color: var(--amber);
  border-radius: var(--radius-sm);
  margin-left: .25rem;
  white-space: nowrap;
}

/* Gast-Gegenvorschlag über die öffentliche RSVP-Antwortseite (`has_attendee_counter`,
   Migration 339, Spec 20260713 F). Grid-Rahmen-Markierung — outline statt box-shadow,
   damit .cal-event-block:hover (setzt eigenen box-shadow) den Ring nicht wegwischt;
   outline ist ausserdem unabhaengig von position:static (.cal-event-bar.cal-pos-block).
   Faerbt NICHT die Fläche — --cal-bg/--cal-color bleiben Kategorie-/Provider-Farbe. */
.cal-event-block.cal-event-has-counter,
.cal-event-bar.cal-event-has-counter {
  outline: 1px solid var(--amber);
  outline-offset: -1px;
}

/* Gegenvorschlag-Badge im Titel (`_counterBadge()`) — analog .cal-event-recur-badge/
   .cal-event-cat-badge Layout-Regeln (P-5: gleiches Flex-Push-Rechts-Muster in
   Titel-Zeile/Bar), nur amber statt currentColor. Reihenfolge im Titel seit
   Fix 2026-07-18: counter, recurrence, sync, category
   (`${counterBadge}${recurrenceBadge}${syncBadge}${categoryBadge}`) — deshalb
   erhaelt nur der jeweils ERSTE vorhandene Badge `margin-left:auto`, alle
   direkt folgenden `margin-left:0` (sonst reissen mehrere auto-Margins die
   Badges auseinander statt sie rechtsbuendig zu gruppieren). */
.cal-event-counter-badge {
  color: var(--amber);
  opacity: .9;
  line-height: 1;
  flex-shrink: 0;
  pointer-events: none;
}
.cal-event-block-title .cal-event-counter-badge,
.cal-event-bar .cal-event-counter-badge {
  margin-left: auto;
}
.cal-event-block-title .cal-event-counter-badge + .cal-event-recur-badge,
.cal-event-bar .cal-event-counter-badge + .cal-event-recur-badge,
.cal-event-block-title .cal-event-counter-badge + .cal-event-cat-badge,
.cal-event-bar .cal-event-counter-badge + .cal-event-cat-badge {
  margin-left: 0;
}

/* Sync-Warn-Badge im Grid-Titel (`_syncBadge()`, Fix 2026-07-18) — Warn-Dreieck
   für extern zugeordnete Events (ev.calendar_connection_id), die (noch) NICHT
   beim Provider existieren (`_isEventSynced(ev)` false). Synchronisierte + rein
   lokale Termine bekommen KEIN Icon (ruhiges Grid). Gleiches Flex-Push-Rechts-
   Muster wie counter-/recur-/cat-Badge — die Kombinations-Selektoren decken
   jede Position ab, an der der sync-Badge im Titel auftauchen kann (nach
   counter ODER recur, mit cat direkt danach). */
.cal-event-sync-badge {
  color: var(--amber);
  opacity: .95;
  line-height: 1;
  flex-shrink: 0;
  pointer-events: none;
}
.cal-event-block-title .cal-event-sync-badge,
.cal-event-bar .cal-event-sync-badge {
  margin-left: auto;
}
.cal-event-block-title .cal-event-counter-badge + .cal-event-sync-badge,
.cal-event-bar .cal-event-counter-badge + .cal-event-sync-badge,
.cal-event-block-title .cal-event-recur-badge + .cal-event-sync-badge,
.cal-event-bar .cal-event-recur-badge + .cal-event-sync-badge,
.cal-event-block-title .cal-event-sync-badge + .cal-event-cat-badge,
.cal-event-bar .cal-event-sync-badge + .cal-event-cat-badge {
  margin-left: 0;
}

/* Booking-Info-Boxen oben im Editor-Panel */
.cal-booking-info-boxes {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .5rem .25rem .25rem;
}

/* Link in der replaced_by-Info-Box */
.cal-booking-replaced-link {
  color: var(--accent);
  margin-left: .25rem;
}
.cal-booking-replaced-link:hover { text-decoration: underline; }

/* Sub-Mode-Block (Reschedule-Anfrage / Stornierung) im Editor-Panel */
.cal-booking-submode {
  border-top: 2px solid var(--border);
  margin-top: 1rem;
  padding: 1rem .25rem .5rem;
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.cal-booking-submode--danger .cal-booking-submode-header {
  color: var(--coral);
}
.cal-booking-submode-header {
  display: flex;
  align-items: center;
  gap: .375rem;
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-primary);
  margin-bottom: .125rem;
}
.cal-booking-submode-textarea {
  min-height: 9rem;
  resize: vertical;
  font-family: inherit;
  font-size: .875rem;
}
.cal-booking-submode-radios {
  display: flex;
  flex-direction: column;
  gap: .375rem;
}
.cal-booking-submode-radio {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .875rem;
  cursor: pointer;
  color: var(--text-primary);
}
.cal-booking-submode-radio input[type="radio"] {
  accent-color: var(--accent);
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
}

/* Mobile-Anpassungen für RSVP-Workflow */
@media (max-width: 900px) {
  .cal-rsvp-select {
    min-height: 44px; /* Touch-Target-Mindestgröße */
  }
  /* ds-date-range im Sub-Mode vertikal stapeln (P1) */
  .cal-booking-submode .ds-date-range {
    flex-direction: column;
    align-items: stretch;
    gap: .375rem;
  }
  .cal-booking-submode .ds-date-range-sep { display: none; }
  .cal-booking-submode .ds-date-range > .input { width: 100%; }

  /* Cancel-Anfrage-Button in der Info-Box: Touch-Target auf 44px anheben (P Pflicht) */
  .ds-info-box--with-action .btn-sm {
    min-height: 44px;
    padding: 0 .875rem;
  }

  /* Pfeil-Icon in Event-Blocks: Hit-Area auf 24x24 vergroessern via Padding-Trick */
  .cal-event-replaced-arrow {
    width: 24px;
    height: 24px;
    top: 0;
    right: 0;
    padding: 5px;
  }
}

/* ── Booking-Overlay (Polish: Reschedule/Cancel als Overlay-Panel) ──────── */
/* Scoped innerhalb page-calendar, z-index über Primär-Panel (.ds-cal-panel = 401) */

.cal-booking-overlay-backdrop {
  position: fixed;
  inset: 0;
  z-index: 500;
  background: rgba(0, 0, 0, .25);
  backdrop-filter: blur(1px);
  animation: cal-overlay-fade-in 150ms ease;
}

.cal-booking-overlay-panel {
  position: fixed;
  inset-inline-end: 0;
  top: 0;
  bottom: 0;
  z-index: 501;
  width: clamp(320px, 90vw, 520px);
  background: var(--bg-primary);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  animation: cal-overlay-slide-in 200ms ease;
}

.cal-booking-overlay-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .875rem 1rem;
  border-bottom: 1px solid var(--border);
  gap: .5rem;
  flex-shrink: 0;
}

.cal-booking-overlay-title {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--text-primary);
}

.cal-booking-overlay-close {
  width: 32px;
  height: 32px;
  min-width: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  background: transparent;
  border: none;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.cal-booking-overlay-close:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}

.cal-booking-overlay-body {
  flex: 1;
  overflow-y: auto;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: .75rem;
}

.cal-booking-overlay-footer {
  padding: .75rem 1rem;
  border-top: 1px solid var(--border);
  display: flex;
  gap: .5rem;
  flex-shrink: 0;
}

/* Animations */
@keyframes cal-overlay-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes cal-overlay-slide-in {
  from { transform: translateX(100%); }
  to   { transform: translateX(0); }
}

/* Mobile: Overlay nimmt volle Breite */
@media (max-width: 900px) {
  .cal-booking-overlay-panel {
    width: 100%;
    inset-inline-end: 0;
  }
  /* Touch-Target 44px auf Close-Button */
  .cal-booking-overlay-close {
    width: 44px;
    height: 44px;
    min-width: 44px;
  }
  /* Footer-Buttons auf Mobile voll breit */
  .cal-booking-overlay-footer .ds-toolbar-item {
    flex: 1;
    justify-content: center;
    min-height: 44px;
  }
  /* ds-date-range im Overlay vertikal stapeln */
  .cal-booking-overlay-body .ds-date-range {
    flex-direction: column;
    align-items: stretch;
    gap: .375rem;
  }
  .cal-booking-overlay-body .ds-date-range-sep { display: none; }
  .cal-booking-overlay-body .ds-date-range > .input { width: 100%; }
}

/* ── Calendar Shares Tab ─────────────────────────────────── */

.cal-share-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 3rem 1rem;
  text-align: center;
  color: var(--text-secondary);
}
.cal-share-empty-title {
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: .375rem;
}
.cal-share-empty-sub {
  font-size: .875rem;
  color: var(--text-secondary);
  max-width: 26rem;
  line-height: 1.5;
  margin-bottom: 1.25rem;
}

.cal-share-list {
  display: flex;
  flex-direction: column;
  gap: .875rem;
}

.cal-share-card {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: .625rem;
}
.cal-share-card.is-expired {
  opacity: .65;
}

.cal-share-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  flex-wrap: wrap;
}
.cal-share-card-name {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--text-primary);
}
.cal-share-card-badges {
  display: flex;
  gap: .375rem;
  flex-wrap: wrap;
}

.cal-share-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: .625rem .875rem;
  font-size: .8125rem;
  color: var(--text-secondary);
}
.cal-share-card-range,
.cal-share-card-time,
.cal-share-card-expiry {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
}
.cal-share-card-range svg,
.cal-share-card-time svg,
.cal-share-card-expiry svg {
  flex-shrink: 0;
  color: var(--text-tertiary);
}

.cal-share-card-url {
  display: flex;
  gap: .5rem;
  align-items: center;
}
.cal-share-url-input {
  flex: 1;
  font-size: .8125rem;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  cursor: text;
  min-width: 0;
}
.cal-share-copy-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: .375rem;
}

.cal-share-card-actions {
  display: flex;
  gap: .5rem;
  padding-top: .25rem;
  border-top: 1px solid var(--border);
}

@media (max-width: 600px) {
  .cal-share-card-url {
    flex-direction: column;
    align-items: stretch;
  }
  .cal-share-copy-btn {
    justify-content: center;
    min-height: 44px; /* Touch-Target-Mindestgröße */
  }
}

@media (max-width: 900px) {
  /* Touch-Target auch bei Tablet-Breite (600–900px) */
  .cal-share-copy-btn {
    min-height: 44px;
  }
}

/* Quick-date shortcuts under expires_at picker */
.cal-share-quick-dates {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
  margin-top: .5rem;
}
.cal-share-quick-date-btn {
  font-size: .75rem;
  padding: .25rem .625rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg-secondary);
  color: var(--text-secondary);
  cursor: pointer;
  line-height: 1.4;
  transition: var(--transition);
}
.cal-share-quick-date-btn:hover {
  background: var(--accent-light);
  color: var(--accent);
  border-color: var(--accent-light);
}

/* Inactive share card */
.cal-share-card.is-inactive {
  opacity: .6;
}
.cal-share-card.is-inactive .cal-share-card-url {
  pointer-events: none;
  opacity: .5;
}

/* Tab-Content-Kopfzeile mit einzelner Primär-Aktion (Buchungstypen/Freigaben-Tab,
   rechtsbündig — konsistent zur "Neu"-Button-Position in .cal-poll-header) */
.cal-tab-actions {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 1rem;
}

/* ── Terminabstimmung (Meeting Polls) Tab ─────────────────────────────────── */

/* Header: Sub-Tabs links, "Neu"-Button rechts */
.cal-poll-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}
.cal-poll-header .tab-filter {
  margin-bottom: 0;
}
.cal-poll-header-new {
  flex-shrink: 0;
}

/* Response counter in meta row */
.cal-poll-response-count {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .8125rem;
  color: var(--text-secondary);
}
.cal-poll-response-count svg {
  color: var(--text-tertiary);
  flex-shrink: 0;
}

/* Individual-links hint (per_participant mode) */
.cal-poll-individual-links-hint {
  display: flex;
  align-items: center;
  gap: .375rem;
  font-size: .8125rem;
  color: var(--text-tertiary);
  padding: .375rem .5rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  border: 1px dashed var(--border);
}
.cal-poll-individual-links-hint svg {
  flex-shrink: 0;
  color: var(--text-tertiary);
}

/* Slot editor rows in the form */
.cal-poll-slot-row {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  margin-bottom: .625rem;
  flex-wrap: wrap;
}
.cal-poll-slot-inputs {
  display: flex;
  align-items: center;
  gap: .375rem;
  flex: 1;
  min-width: 0;
  flex-wrap: wrap;
}
.cal-poll-slot-dt {
  flex: 1;
  min-width: 10rem;
  font-size: .875rem;
}
.cal-poll-slot-remove {
  flex-shrink: 0;
  padding: .3rem .5rem;
  color: var(--text-tertiary);
}
.cal-poll-slot-remove:hover {
  color: var(--coral);
  background: var(--coral-light);
  border-color: var(--coral-light);
}
.cal-poll-slot-error {
  width: 100%;
  font-size: .75rem;
  color: var(--coral);
  margin-top: -.25rem;
  margin-bottom: .25rem;
}

/* "+ Slot hinzufügen" link button */
.cal-poll-add-slot-btn {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  font-size: .8125rem;
  color: var(--text-tertiary);
  background: none;
  border: none;
  padding: .25rem 0;
  cursor: pointer;
  transition: color var(--transition);
}
.cal-poll-add-slot-btn:hover {
  color: var(--accent);
}

/* Mobile: hide "Neue Terminabstimmung" header button on mobile (FAB takes over) */
@media (max-width: 900px) {
  .cal-poll-header-new {
    display: none;
  }
}

/* Mobile: stack slot datetime inputs vertically */
@media (max-width: 600px) {
  .cal-poll-slot-inputs {
    flex-direction: column;
    align-items: stretch;
  }
  .cal-poll-slot-dt {
    min-width: 0;
    width: 100%;
  }
  .cal-poll-slot-inputs .ds-date-range-sep {
    display: none;
  }
}

/* ── Poll Results (Session 5b) ─────────────────────────────────────────────── */

/* Results panel meta row: progress + finalized info */
.cal-poll-results-meta {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin-bottom: 1rem;
}

.cal-poll-results-progress {
  font-size: .875rem;
  color: var(--text-secondary);
}

.cal-poll-results-finalized-badge {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .375rem;
  padding: .5rem .75rem;
  background: var(--teal-light);
  color: var(--teal);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
  font-weight: 500;
  border: 1px solid transparent;
}

/* Finalized slot meta in card list */
.cal-poll-finalized-slot-meta {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .8125rem;
  color: var(--teal);
  font-weight: 500;
}
.cal-poll-finalized-slot-meta svg {
  flex-shrink: 0;
  color: var(--teal);
}

/* ── Votes matrix ────────────────────────────────────────────────────────── */

.cal-poll-matrix-loading {
  padding: .5rem 0;
}

/* Scroll container — matrix scrolls horizontally; page body must not */
.cal-poll-matrix-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-bottom: 1rem;
}

.cal-poll-matrix {
  border-collapse: collapse;
  width: 100%;
  min-width: 400px;
  font-size: .8125rem;
}

.cal-poll-matrix th,
.cal-poll-matrix td {
  padding: .5rem .625rem;
  border-bottom: 1px solid var(--border);
  border-right: 1px solid var(--border);
  vertical-align: middle;
  white-space: nowrap;
}

.cal-poll-matrix th:last-child,
.cal-poll-matrix td:last-child {
  border-right: none;
}

.cal-poll-matrix tbody tr:last-child td,
.cal-poll-matrix tbody tr:last-child th {
  border-bottom: none;
}

/* Slot label column header */
.cal-poll-matrix-slot-th {
  font-weight: 600;
  font-size: .8125rem;
  color: var(--text-secondary);
  text-align: left;
  min-width: 12rem;
  background: var(--bg-secondary);
  position: sticky;
  left: 0;
  z-index: 2;
}

/* Participant column headers */
.cal-poll-matrix-participant-th {
  font-weight: 500;
  text-align: center;
  min-width: 5rem;
  max-width: 8rem;
  background: var(--bg-secondary);
  color: var(--text-primary);
}

.cal-poll-matrix-participant-name {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 7rem;
  margin: 0 auto;
}

/* Tally column header */
.cal-poll-matrix-tally-th {
  font-weight: 600;
  font-size: .8125rem;
  text-align: center;
  min-width: 8rem;
  background: var(--bg-secondary);
  color: var(--text-secondary);
}

/* Action column header */
.cal-poll-matrix-action-th {
  min-width: 10rem;
  background: var(--bg-secondary);
}

/* Slot label cells (sticky left) */
.cal-poll-matrix-slot {
  font-weight: 500;
  color: var(--text-primary);
  text-align: left;
  position: sticky;
  left: 0;
  background: var(--bg-primary);
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: .25rem;
  min-width: 12rem;
}

/* Vote cells */
.cal-poll-matrix-cell {
  text-align: center;
}

.cal-poll-cell--yes {
  color: var(--teal);
  background: var(--teal-light);
}

.cal-poll-cell--maybe {
  color: var(--amber);
  background: var(--amber-light);
}

.cal-poll-cell--no {
  color: var(--coral);
  background: var(--coral-light);
}

.cal-poll-cell--none {
  color: var(--text-tertiary);
  background: transparent;
}

/* Tally cells */
.cal-poll-matrix-tally {
  text-align: center;
  white-space: nowrap;
}

.cal-poll-tally-yes,
.cal-poll-tally-maybe,
.cal-poll-tally-no {
  display: inline-flex;
  align-items: center;
  gap: .125rem;
  font-size: .8125rem;
  font-weight: 500;
  margin-right: .25rem;
}

.cal-poll-tally-yes   { color: var(--teal);  }
.cal-poll-tally-maybe { color: var(--amber); }
.cal-poll-tally-no    { color: var(--coral); }

/* Best-slot row highlight */
.cal-poll-matrix-best .cal-poll-matrix-slot,
.cal-poll-matrix-best td {
  background: var(--accent-light);
}
.cal-poll-matrix-best .cal-poll-matrix-slot {
  background: var(--accent-light);
}
.cal-poll-matrix-best .cal-poll-cell--yes {
  background: color-mix(in srgb, var(--accent-light) 60%, var(--teal-light) 40%);
}
.cal-poll-matrix-best .cal-poll-cell--maybe {
  background: color-mix(in srgb, var(--accent-light) 60%, var(--amber-light) 40%);
}
.cal-poll-matrix-best .cal-poll-cell--no {
  background: color-mix(in srgb, var(--accent-light) 60%, var(--coral-light) 40%);
}

/* Finalized row highlight */
.cal-poll-matrix-finalized-row .cal-poll-matrix-slot,
.cal-poll-matrix-finalized-row td {
  background: var(--teal-light);
}
.cal-poll-matrix-finalized-row .cal-poll-cell--yes {
  background: color-mix(in srgb, var(--teal-light) 80%, var(--teal) 20%);
}

/* Badges inside slot cell */
.cal-poll-best-badge {
  display: inline-flex;
  align-items: center;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: .1rem .4rem;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  white-space: nowrap;
  margin-bottom: .1rem;
}

.cal-poll-fin-badge {
  display: inline-flex;
  align-items: center;
  gap: .2rem;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: .1rem .4rem;
  border-radius: 999px;
  background: var(--teal);
  color: #fff;
  white-space: nowrap;
  margin-bottom: .1rem;
}

/* Action cells */
.cal-poll-matrix-action {
  text-align: right;
  white-space: nowrap;
}

.cal-poll-finalize-btn {
  font-size: .75rem;
  padding: .25rem .625rem;
  min-height: 32px;
}

/* Footer actions row */
.cal-poll-results-footer {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-top: .75rem;
  flex-wrap: wrap;
  padding-top: .75rem;
  border-top: 1px solid var(--border);
}

/* ── Finalize overlay: enrichment fields (Beschreibung/Ort/VC/Kalender) ──── */

.cal-poll-finalize-enrich {
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: .875rem 0;
  margin-bottom: .875rem;
  display: flex;
  flex-direction: column;
  gap: .625rem;
}

.cal-poll-finalize-enrich .form-group {
  margin-bottom: 0;
}

.cal-poll-finalize-enrich .input,
.cal-poll-finalize-enrich .select,
.cal-poll-finalize-enrich .textarea {
  width: 100%;
  min-height: 40px;
  box-sizing: border-box;
}

.cal-poll-finalize-enrich .textarea {
  min-height: 72px;
  resize: vertical;
}

/* Mobile: touch-targets + no overflow */
@media (max-width: 600px) {
  .cal-poll-finalize-enrich .input,
  .cal-poll-finalize-enrich .select {
    min-height: 44px;
  }
}

/* ── Finalize overlay toggle rows ────────────────────────────────────────── */

.cal-poll-finalize-toggle-row {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  margin-bottom: .875rem;
}

.cal-poll-finalize-toggle-label {
  display: flex;
  flex-direction: column;
  gap: .1875rem;
  font-size: .875rem;
}

.cal-poll-finalize-toggle-label strong {
  font-weight: 600;
  color: var(--text-primary);
}

.cal-poll-finalize-toggle-label span {
  font-size: .8125rem;
  color: var(--text-tertiary);
  line-height: 1.4;
}

/* ── Mobile: results panel adjustments ───────────────────────────────────── */
@media (max-width: 900px) {
  .cal-poll-matrix {
    min-width: 360px;
  }
  .cal-poll-matrix-slot-th,
  .cal-poll-matrix-slot {
    min-width: 9rem;
  }
  .cal-poll-finalize-btn {
    min-height: 44px;
    padding: .5rem .75rem;
  }
  .cal-poll-results-footer {
    flex-direction: column;
    align-items: stretch;
  }
  .cal-poll-results-footer .btn {
    min-height: 44px;
    justify-content: center;
  }
}

/* ── Terminanfragen (Appointment Requests) — Session 4 ───────────────────── */

/* Badge-Button im Shares-Tab-Header */
.cal-appt-badge-btn {
  display: inline-flex;
  align-items: center;
  gap: .4375rem;
  color: var(--amber);
  border-color: var(--amber);
  background: var(--amber-light);
  font-weight: 500;
}
.cal-appt-badge-btn:hover {
  background: var(--amber);
  color: #fff;
  border-color: var(--amber);
}

/* Zähler-Pille im Badge-Button */
.cal-appt-badge-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 .3rem;
  border-radius: 999px;
  font-size: .6875rem;
  font-weight: 700;
  background: var(--amber);
  color: #fff;
  line-height: 1;
}
.cal-appt-badge-btn:hover .cal-appt-badge-count {
  background: #fff;
  color: var(--amber);
}

/* Liste im Panel */
.cal-appt-list {
  display: flex;
  flex-direction: column;
  gap: .875rem;
  padding: .25rem 0;
}

.cal-appt-card {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .875rem 1rem;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

.cal-appt-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  flex-wrap: wrap;
}

.cal-appt-card-name {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--text-primary);
}

.cal-appt-card-meta {
  display: flex;
  flex-direction: column;
  gap: .25rem;
}

.cal-appt-card-range,
.cal-appt-card-contact,
.cal-appt-card-received {
  display: inline-flex;
  align-items: center;
  gap: .3125rem;
  font-size: .8125rem;
  color: var(--text-secondary);
}

.cal-appt-card-range svg,
.cal-appt-card-contact svg {
  color: var(--text-tertiary);
  flex-shrink: 0;
}

.cal-appt-card-received {
  color: var(--text-tertiary);
  font-size: .75rem;
}

.cal-appt-card-message {
  font-size: .875rem;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  padding: .5rem .625rem;
  white-space: pre-wrap;
  border-left: 3px solid var(--border);
  line-height: 1.5;
}

.cal-appt-card-actions {
  display: flex;
  gap: .5rem;
  padding-top: .375rem;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}

.cal-appt-decline-btn {
  color: var(--coral);
}
.cal-appt-decline-btn:hover {
  background: var(--coral-light);
  color: var(--coral);
  border-color: var(--coral-light);
}

/* RSVP-Verlauf-Notiz (source='rsvp', Spec 20260713 Punkt C) — dezente
   Notiz-Zeile im Änderungsverlauf statt Diff/Revert. Reused .cal-appt-card
   als Karten-Rahmen; -rsvp-card leicht abgesetzt (bg-secondary statt
   bg-primary) damit sie optisch von echten Bearbeitungen unterscheidbar ist. */
.cal-appt-card.cal-history-rsvp-card {
  background: var(--bg-secondary);
}

.cal-history-rsvp-note {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  font-size: .875rem;
  line-height: 1.5;
  color: var(--text-secondary);
}

.cal-history-rsvp-note svg {
  flex-shrink: 0;
  margin-top: .1875rem;
  color: var(--text-tertiary);
}

.cal-history-rsvp-note strong {
  color: var(--text-primary);
  font-weight: 600;
}

.cal-history-rsvp-note--accepted svg { color: var(--teal); }
.cal-history-rsvp-note--declined svg { color: var(--coral); }
.cal-history-rsvp-note--tentative svg { color: var(--amber); }
.cal-history-rsvp-note--counter svg,
.cal-history-rsvp-note--counter_adopted svg { color: var(--accent); }

/* Empty-State */
.cal-appt-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 3rem 1.5rem;
}

.cal-appt-empty-title {
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: .375rem;
}

.cal-appt-empty-sub {
  font-size: .875rem;
  color: var(--text-secondary);
  max-width: 26rem;
  line-height: 1.5;
}

/* Accept/Decline Sub-Panel Body */
.cal-appt-accept-body,
.cal-appt-decline-body {
  padding: .75rem 0;
  display: flex;
  flex-direction: column;
}

.cal-appt-accept-info {
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  padding: .625rem .875rem;
  font-size: .875rem;
  line-height: 1.5;
  margin-bottom: .25rem;
  border-left: 3px solid var(--accent);
}

/* Notify-Toggle-Zeile im Decline-Panel */
.cal-appt-notify-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .75rem 0;
}

.cal-appt-notify-label {
  font-size: .875rem;
  color: var(--text-primary);
}

/* Terminanfragen-Konfiguration im Share-Form */
.cal-share-appt-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .25rem 0;
  min-height: 44px;
}

/* 2-Spalten-Grid für Dauer + Vorlaufzeit */
.cal-share-appt-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .625rem;
  margin-top: .5rem;
}

/* Mobile: Badge-Button voll breit + Stack */
@media (max-width: 900px) {
  .cal-appt-card-actions .btn {
    min-height: 44px;
    flex: 1;
    justify-content: center;
  }
  .cal-appt-notify-row {
    padding: .875rem 0;
  }
}

@media (max-width: 600px) {
  .cal-share-appt-grid {
    grid-template-columns: 1fr;
  }
}

/* ── Poll-Form: P1 Termindauer + P2 Expiry + P3 Timeline ────────────────── */

/* P1: Dauer-Zeile (Icon + Controls) */
.cal-poll-duration-row {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  margin-bottom: .875rem;
}
.cal-poll-duration-controls {
  flex: 1;
  min-width: 0;
}
.cal-poll-duration-wrap {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-top: .25rem;
  flex-wrap: wrap;
}
.cal-poll-duration-select {
  flex: 1;
  min-width: 0;
  max-width: 14rem;
}
.cal-poll-duration-custom {
  width: 5rem;
  min-width: 0;
}
.cal-poll-duration-unit {
  font-size: .8125rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* P1: Slot leere-State Hinweis */
.cal-poll-slots-empty {
  color: var(--text-tertiary);
  font-size: .8125rem;
  margin: .25rem 0 .75rem;
  line-height: 1.5;
}

/* P1: Endzeit-Label neben Startzeit (read-only) */
.cal-poll-slot-end-label {
  font-size: .8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
  align-self: center;
  padding: 0 .25rem;
  flex-shrink: 0;
}

/* Mobile: Slot-Inputs stapeln wenn Platz eng */
@media (max-width: 600px) {
  .cal-poll-duration-select {
    max-width: 100%;
    flex: 1 1 100%;
  }
  .cal-poll-slot-end-label {
    display: block;
    padding: 0;
  }
}

/* P3: Timeline-Wrapper */
.cal-poll-timeline-wrap {
  margin-top: .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  overflow: hidden;
}
.cal-poll-timeline-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .5rem .75rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
}
.cal-poll-timeline-label {
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.cal-poll-timeline-loading {
  display: inline-flex;
  align-items: center;
  color: var(--text-tertiary);
  animation: cal-poll-tl-spin 1s linear infinite;
}
@keyframes cal-poll-tl-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* P3: Timeline-Körper */
.cal-poll-timeline {
  position: relative;
  height: var(--tl-h);
  overflow: hidden;
  padding-left: 2.75rem; /* Platz für Stunden-Labels */
  margin: .5rem 0;
}

/* Stunden-Rasterlinien */
.cal-poll-tl-line {
  position: absolute;
  left: 2.75rem;
  right: .5rem;
  height: 1px;
  background: var(--border);
  pointer-events: none;
}

/* Stunden-Labels */
.cal-poll-tl-hour {
  position: absolute;
  left: 0;
  width: 2.5rem;
  font-size: .625rem;
  color: var(--text-tertiary);
  text-align: right;
  padding-right: .375rem;
  transform: translateY(-50%);
  pointer-events: none;
  line-height: 1;
  white-space: nowrap;
}

/* Jetzt-Linie */
.cal-poll-tl-now {
  position: absolute;
  left: 2.75rem;
  right: .5rem;
  height: 2px;
  background: var(--coral);
  pointer-events: none;
  z-index: 3;
}
.cal-poll-tl-now::before {
  content: '';
  position: absolute;
  left: -3px;
  top: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--coral);
}

/* Kalender-Events (belegte Zeiten) */
.cal-poll-tl-event {
  position: absolute;
  left: 2.75rem;
  right: .5rem;
  background: color-mix(in srgb, var(--accent) 18%, var(--bg-primary));
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  overflow: hidden;
  z-index: 2;
  min-height: 4px;
  cursor: default;
}
.cal-poll-tl-event-title {
  display: block;
  font-size: .625rem;
  color: var(--accent);
  padding: .125rem .25rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}

/* Ausgewählte Slot-Blöcke */
.cal-poll-tl-slot {
  position: absolute;
  left: 2.75rem;
  right: .5rem;
  background: color-mix(in srgb, var(--teal) 22%, var(--bg-primary));
  border-left: 3px solid var(--teal);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  z-index: 1;
  min-height: 4px;
  pointer-events: none;
}

/* P3: Tag-Navigations-Buttons */
.cal-poll-timeline-nav {
  display: flex;
  gap: .375rem;
  flex-wrap: wrap;
  padding: .5rem .75rem;
  border-top: 1px solid var(--border);
  background: var(--bg-secondary);
}
.cal-poll-tl-day-btn {
  font-size: .75rem;
  padding: .25rem .625rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg-primary);
  color: var(--text-secondary);
  cursor: pointer;
  white-space: nowrap;
  min-height: 28px;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.cal-poll-tl-day-btn:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.cal-poll-tl-day-btn.is-active {
  background: var(--accent-light);
  color: var(--accent);
  border-color: var(--accent);
  font-weight: 600;
}

/* Mobile: Timeline etwas kompakter */
@media (max-width: 600px) {
  .cal-poll-tl-day-btn {
    min-height: 36px;
  }
}

/* ── Poll-Editor 2-Spalten-Vorschau (Session poll-2col 2026-06-04) ─────────
   Verwendet die shared cal-editor-preview-grid + cal-editor-preview-event
   Klassen aus dem Event-Editor. Neue Klassen nur für Poll-spezifische Elemente.
   .cal-poll-timeline-* sind DEPRECATED (inline-Timeline ersetzt durch rechte Spalte). */

/* Jetzt-Linie in der rechten Vorschau-Spalte (analog cal-poll-tl-now, aber
   im cal-editor-preview-grid Kontext ohne eigenes Padding-left) */
.cal-poll-preview-now-line {
  position: absolute;
  left: 2.5rem;
  right: 0;
  height: 2px;
  background: var(--coral);
  pointer-events: none;
  z-index: 3;
}
.cal-poll-preview-now-line::before {
  content: '';
  position: absolute;
  left: -3px;
  top: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--coral);
}

/* Teal-Block für gewählte Slots in der rechten Vorschau-Spalte */
.cal-poll-preview-slot-block {
  background: color-mix(in srgb, var(--teal) 22%, var(--bg-primary));
  border-left: 3px solid var(--teal);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  z-index: 2;
  min-height: 6px;
  pointer-events: none;
  overflow: hidden;
}
.cal-poll-preview-slot-label {
  display: block;
  font-size: .625rem;
  color: var(--teal);
  padding: .125rem .25rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

/* Slot-Sprung-Buttons unter der rechten Vorschau-Spalte */
.cal-poll-preview-slot-nav {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
  padding: .5rem .75rem;
  border-top: 1px solid var(--border);
  background: var(--bg-secondary);
  flex-shrink: 0;
}

/* Mobile: rechte Spalte bleibt ausgeblendet (erbt cal-editor-panel Regel) */
@media (max-width: 900px) {
  .cal-poll-preview-slot-nav { display: none; }
}

/* Poll-Editor: Formular-Spalte scrollt (hat viele Sektionen, kein Rich-Editor
   der die gesamte restliche Höhe beansprucht wie der Event-Editor) */
.cal-editor-panel .cal-poll-form-scroll {
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}

/* ── Poll Slot-Datum/Zeit-Picker ─────────────────────────────────────── */
/* Wrapper: position:relative als Anker für absoluten Popover */
.cal-poll-slot-dt-wrap {
  position: relative;
  display: inline-block;
}

/* Trigger-Button */
.cal-poll-slot-dt-btn {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .375rem .75rem;
  min-height: 36px;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: .875rem;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
  white-space: nowrap;
}
.cal-poll-slot-dt-btn:hover {
  background: var(--bg-secondary);
  border-color: var(--accent);
}
.cal-poll-slot-dt-btn.has-value {
  color: var(--text-primary);
}
.cal-poll-slot-dt-btn svg {
  flex-shrink: 0;
  color: var(--text-tertiary);
}

/* Backdrop: transparent, schließt Picker bei Klick außerhalb */
.cal-poll-slot-picker-backdrop {
  position: fixed;
  inset: 0;
  z-index: 399;
}

/* Popover-Fenster */
.cal-poll-slot-picker-popover {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 400;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 240px;
  overflow: hidden;
  animation: calDpIn 150ms ease both;
}

/* Kalender-Grid im Picker (nutzt .cal-dp-* Klassen) */
.cal-poll-slot-picker-cal {
  padding: .625rem .625rem .375rem;
}

/* Ausgewählter Tag (kein Heute-Kreis, aber accent-light Hintergrund) */
.cal-poll-slot-picker-sel {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
  border-radius: 50%;
}
.cal-poll-slot-picker-sel:hover {
  background: var(--accent);
  color: #fff;
}
/* P3: Wochenend-Tage disabled (nur idx 0 — erster Slot) */
.cal-poll-slot-picker-disabled {
  opacity: .3;
  cursor: not-allowed;
  pointer-events: none;
}

/* Uhrzeit-Zeile */
.cal-poll-slot-picker-time-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem .625rem;
  border-top: 1px solid var(--border);
}
.cal-poll-slot-picker-time-label {
  font-size: .8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
  flex-shrink: 0;
}
.cal-poll-slot-picker-time-select {
  flex: 1;
  font-size: .8125rem;
  min-height: 32px;
  padding: .25rem .5rem;
}

/* Footer: Abbrechen + Übernehmen */
.cal-poll-slot-picker-footer {
  display: flex;
  gap: .375rem;
  justify-content: flex-end;
  padding: .5rem .625rem;
  border-top: 1px solid var(--border);
  background: var(--bg-secondary);
}

/* Mobile (≤900px): Bottom-Sheet statt absolutem Popover */
@media (max-width: 900px) {
  .cal-poll-slot-picker-backdrop {
    background: rgba(0,0,0,.35);
  }
  .cal-poll-slot-picker-popover {
    position: fixed;
    top: auto;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    border-bottom: none;
    animation: calDpBottomIn 200ms ease both;
    z-index: 460;
    max-height: 80dvh;
    overflow-y: auto;
  }
  .cal-poll-slot-picker-backdrop {
    z-index: 459;
  }
  .cal-poll-slot-dt-btn {
    min-height: 44px;
    font-size: .9375rem;
  }
  .cal-poll-slot-picker-footer .btn {
    flex: 1;
    min-height: 44px;
    justify-content: center;
  }
  .cal-poll-slot-picker-time-select {
    min-height: 44px;
  }
}

/* ── Terminanfragen: 2-Spalten-Editor-Layout (Session 5, 2026-06-04) ──── */

/* Linke Spalte erhält overflow-y:auto für scrollbare Liste */
.cal-appt-editor-form {
  overflow-y: auto;
}

/* Auswahl-Highlight auf Anfrage-Karten */
.cal-appt-card {
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.cal-appt-card:hover {
  border-color: var(--accent);
  background: var(--accent-light);
}
.cal-appt-card.is-selected {
  border-color: var(--accent);
  background: var(--accent-light);
}

/* Angefragter Zeitraum — Amber-Block in Tagesvorschau */
.cal-appt-preview-block {
  position: absolute;
  left: 2.75rem;
  right: .5rem;
  background: var(--amber-light);
  border-left: 3px solid var(--amber);
  border-radius: var(--radius-sm);
  pointer-events: none;
  z-index: 3;
  overflow: hidden;
  display: flex;
  align-items: flex-start;
  padding: .125rem .25rem;
}
.cal-appt-preview-block-label {
  font-size: .625rem;
  font-weight: 600;
  color: var(--amber);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Mobile: rechte Spalte ausgeblendet (erbt .cal-editor-panel Regel);
   Touch-Targets für Annehmen/Ablehnen Buttons werden von bestehendem
   @media-Block bei Z.6448 abgedeckt */

/* ── Poll-Editor: Freie Slot-Vorschläge ─────────────────────────────────── */

.cal-poll-free-slots-row {
  display: flex;
  flex-direction: column;
  gap: .4375rem;
  padding: .5rem 0 .25rem;
}

.cal-poll-free-slots-label {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
}

.cal-poll-free-slots-label svg {
  color: var(--accent);
}

.cal-poll-free-slots-chips {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
}

/* Chip: verfügbarer freier Slot */
.cal-poll-suggest-chip {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .3125rem .625rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: .8125rem;
  cursor: pointer;
  min-height: 36px;
  transition: border-color var(--transition), background var(--transition), color var(--transition);
  white-space: nowrap;
}

.cal-poll-suggest-chip:hover {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
}

/* Chip: bereits als Slot hinzugefügt → ausgegraut */
.cal-poll-suggest-chip--used {
  opacity: .45;
  cursor: not-allowed;
  pointer-events: none;
}

/* Hinweis-Box (keine Arbeitszeiten / keine Slots) */
.cal-poll-free-slots-hint {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .5rem .625rem;
  border-left: 3px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  font-size: .8125rem;
  color: var(--text-secondary);
  margin: .375rem 0;
}

.cal-poll-free-slots-hint span {
  flex: 1;
}

/* Mobile: Chips umbrechen, Touch-Targets ≥ 36px (bereits gesetzt) */
@media (max-width: 600px) {
  .cal-poll-free-slots-chips {
    flex-direction: column;
    align-items: stretch;
  }
  .cal-poll-suggest-chip {
    justify-content: flex-start;
  }
}

/* ── Poll: Location-Type-Segmented-Control ─────────────────────────────── */

.cal-poll-loc-type-bar {
  display: inline-flex;
  gap: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: .125rem;
}

.cal-poll-loc-type-bar .tab-filter-btn {
  flex: 1;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .375rem .75rem;
  font-size: .8125rem;
  font-weight: 500;
  border: none;
  border-radius: 0;
  background: var(--bg-primary);
  color: var(--text-secondary);
  cursor: pointer;
  white-space: nowrap;
  min-height: 34px;
  transition: background var(--transition), color var(--transition);
}

.cal-poll-loc-type-bar .tab-filter-btn + .tab-filter-btn {
  border-left: 1px solid var(--border);
}

.cal-poll-loc-type-bar .tab-filter-btn:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}

.cal-poll-loc-type-bar .tab-filter-btn.active {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
}

/* Mobile: full-width, taller touch targets */
@media (max-width: 600px) {
  .cal-poll-loc-type-bar {
    width: 100%;
  }
  .cal-poll-loc-type-bar .tab-filter-btn {
    min-height: 44px;
    justify-content: center;
  }
}

/* Tablet (600–900px): Touch-Target auch ohne full-width */
@media (max-width: 900px) {
  .cal-poll-loc-type-bar .tab-filter-btn {
    min-height: 44px;
  }
}

/* ── ds-cal-week-view — read-only Week-View Component ──────────
   Spec: stratum_timetracking_ux_and_mobile_badge.md Teil 7.2
   Session D 2026-06-09.
   Die Component nutzt .ds-cal-week-view als äußersten Wrapper +
   die bestehenden .cal-*-Strukturklassen darunter — damit werden
   alle vorhandenen Time-Grid-Regeln automatisch geerbt.
   Neue Regeln hier: Component-spezifische Overrides + Scoping,
   dcw-* Hilfsklassen, Read-only-Cursor, Selected-Day-Highlight.
   Dark-Mode: automatisch via CSS-Variablen aus base.css.
   ────────────────────────────────────────────────────────────── */

/* Wrapper: füllt verfügbaren Raum, eigener Scroll-Kontext */
.ds-cal-week-view {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
}

/* Kein Sidebar-Toggle-Platz im Gutter-Head — Component hat keine Sidebar */
.ds-cal-week-view .cal-time-gutter-head {
  width: var(--cal-hour-label-width);
}

/* Read-only: kein Pointer auf Tages-Spalten */
.ds-cal-week-view .cal-day-col.dcw-readonly {
  cursor: default;
}
/* Read-only: Hover nur dezent (kein Edit-Feedback) */
.ds-cal-week-view .cal-day-col.dcw-readonly:hover {
  background: inherit;
}
.ds-cal-week-view .cal-day-col-today.dcw-readonly:hover {
  background: var(--cal-today-bg);
}

/* Event-Blöcke in der Component: kein Resize-Handle, kein Drag-Cursor */
.ds-cal-week-view .dcw-event-block {
  cursor: default;
  pointer-events: none;
}

/* Ausgewählter Tag (selectedDate, sofern nicht heute) */
.ds-cal-week-view .dcw-selected-day .cal-week-hd-dow {
  color: var(--teal);
}
.ds-cal-week-view .dcw-selected-day .cal-week-hd-num {
  background: var(--teal-light);
  border-radius: 50%;
  color: var(--teal);
  font-weight: 700;
}
.ds-cal-week-view .cal-day-col.dcw-day-col-selected {
  background: color-mix(in srgb, var(--teal-light) 60%, var(--bg-primary));
}

/* Empty-State */
.ds-cal-week-view.dcw-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 120px;
  color: var(--text-tertiary);
  font-size: 0.875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

/* "+N weitere"-Hinweis in All-Day-Zeile: read-only, kein Button-Stil */
.ds-cal-week-view .dcw-more-hint {
  cursor: default;
  pointer-events: none;
}

/* Time-Scroll: Höhe für Split-Screen-Kontext (nimmt verfügbaren Rest) */
.ds-cal-week-view .cal-time-scroll {
  flex: 1;
  min-height: 0;
}

/* Cal-header: kein Klick-Feedback in read-only Component */
.ds-cal-week-view .cal-week-hd {
  cursor: default;
}

/* Animation: sanftes Einblenden beim Mount */
.ds-cal-week-view {
  animation: dcwFadeIn 180ms ease both;
}
@keyframes dcwFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Mobile (≤600px): kompakter Header */
@media (max-width: 600px) {
  .ds-cal-week-view .cal-week-hd-dow {
    font-size: 0.62rem;
  }
  .ds-cal-week-view .cal-week-hd-num {
    width: 22px;
    height: 22px;
    font-size: 0.8rem;
  }
  .ds-cal-week-view .cal-event-block-time,
  .ds-cal-week-view .cal-event-contact,
  .ds-cal-week-view .cal-event-block-loc {
    display: none;
  }
}

/* ── Serientermin-Scope-Dialog (.cal-recur-scope-*) ─────────────────────────── */
/* Imperativer Overlay für "Serientermin ändern/löschen" – 3-Wege-Auswahl.      */
/* Phase 1 (Spec 20260612_recurring_event_edit_scope). z-index:2200 (über        */
/* Panel 401, Finalize-Overlay 2100).                                            */

.cal-recur-scope-backdrop {
  position: fixed;
  inset: 0;
  z-index: 2200;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  animation: calRecurScopeFadeIn 150ms ease;
}

@keyframes calRecurScopeFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.cal-recur-scope-panel {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 400px;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  animation: calRecurScopeSlideUp 200ms ease;
}

@keyframes calRecurScopeSlideUp {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

.cal-recur-scope-title {
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--text-primary);
  margin: 0 0 0.125rem;
}

.cal-recur-scope-sub {
  font-size: 0.875rem;
  color: var(--text-secondary);
  margin: 0 0 0.75rem;
}

.cal-recur-scope-buttons {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
}

.cal-recur-scope-btn {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: 0.9375rem;
  text-align: left;
  cursor: pointer;
  min-height: 52px;
  transition: background var(--transition), border-color var(--transition);
}

.cal-recur-scope-btn:hover {
  background: var(--accent-light);
  border-color: var(--accent);
  color: var(--accent);
}

.cal-recur-scope-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.cal-recur-scope-btn--disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

.cal-recur-scope-btn-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  margin-top: 0.125rem;
  color: var(--text-tertiary);
}

.cal-recur-scope-btn:hover .cal-recur-scope-btn-icon {
  color: var(--accent);
}

.cal-recur-scope-btn-text {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.cal-recur-scope-btn-label {
  font-weight: 600;
  line-height: 1.3;
}

.cal-recur-scope-btn-hint {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  font-weight: 400;
}

.cal-recur-scope-cancel {
  display: block;
  width: 100%;
  padding: 0.625rem 1rem;
  margin-top: 0.25rem;
  border: none;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.875rem;
  cursor: pointer;
  border-radius: var(--radius-md);
  transition: background var(--transition), color var(--transition);
  min-height: 44px;
}

.cal-recur-scope-cancel:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}

.cal-recur-scope-cancel:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Mobile (≤600px): Touch-Targets */
@media (max-width: 600px) {
  .cal-recur-scope-panel {
    max-width: 100%;
    padding: 1.25rem 1rem;
  }

  .cal-recur-scope-btn {
    min-height: 56px;
    padding: 0.875rem 1rem;
  }

  .cal-recur-scope-cancel {
    min-height: 48px;
  }
}

/* ── Drag/Resize Bestätigungs-Overlay (.cal-move-confirm-*) ───────────────── */
/* Erscheint nach JEDEM Drag-Move und Resize (Nicht-Serien-Termine).          */
/* Zeigt alt → neu Zeitangabe und Verschieben/Abbrechen-Buttons.              */
/* z-index: 2200 (identisch cal-recur-scope-backdrop — sie kommen nie gleich- */
/* zeitig vor: Serien zeigen Scope-Dialog, Einzel zeigen diesen Dialog).      */

.cal-move-confirm-backdrop {
  position: fixed;
  inset: 0;
  z-index: 2200;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  animation: calMoveConfirmFadeIn 150ms ease;
}

@keyframes calMoveConfirmFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.cal-move-confirm-panel {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 360px;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  animation: calMoveConfirmSlideUp 200ms ease;
}

@keyframes calMoveConfirmSlideUp {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

.cal-move-confirm-title {
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--text-primary);
  margin: 0;
}

.cal-move-confirm-times {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.75rem 1rem;
}

.cal-move-confirm-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
}

.cal-move-confirm-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  min-width: 3.5rem;
  flex-shrink: 0;
}

.cal-move-confirm-old {
  color: var(--text-secondary);
  text-decoration: line-through;
  text-decoration-color: var(--coral);
}

.cal-move-confirm-new {
  color: var(--text-primary);
  font-weight: 500;
}

.cal-move-confirm-arrow {
  color: var(--accent);
  flex-shrink: 0;
  font-size: 1rem;
  line-height: 1;
}

.cal-move-confirm-buttons {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.25rem;
}

.cal-move-confirm-ok {
  flex: 1;
  min-height: 44px;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: var(--radius-md);
  font-size: 0.9375rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition);
}
.cal-move-confirm-ok:hover {
  background: var(--accent-dark);
}
.cal-move-confirm-ok:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.cal-move-confirm-cancel {
  flex: 1;
  min-height: 44px;
  background: transparent;
  color: var(--text-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-size: 0.9375rem;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
}
.cal-move-confirm-cancel:hover {
  background: var(--bg-secondary);
  border-color: var(--text-secondary);
}
.cal-move-confirm-cancel:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Mobile (≤600px) */
@media (max-width: 600px) {
  .cal-move-confirm-panel {
    max-width: 100%;
    padding: 1.25rem 1rem;
  }
  .cal-move-confirm-ok,
  .cal-move-confirm-cancel {
    min-height: 52px;
  }
}

/* Wiedervorlage: eigenes Datum waehlen (Ticket 3.377.4) -- Mini-Kalender
   (ds-mini-calendar) als Dropdown-Popover-Inhalt, analog dem bestehenden
   Kategorie-/Beschaeftigt-/Kalender-Picker-Content (_openGrid*Dropdown). */
.cal-followup-snooze-picker {
  padding: 0.5rem;
  width: 240px;
}
/* ── Fahrtenbuch ──────────────────────────────────────────────
   Toolbar (Vehicle-Dropdown + Monats-Nav), Suggestion-Bar mit
   Kalender-Termin-Vorschlaegen, Tabelle mit Lueckenzeilen
   (amber-highlight) und Quick-Resolve-Buttons. Form-Panel nutzt
   ds-cal-panel — keine eigenen Panel-Styles noetig. */
.fb-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: center;
  margin-bottom: 1rem;
  padding: .75rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.fb-toolbar-group {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.fb-month-label {
  font-weight: 600;
  min-width: 9rem;
  text-align: center;
}
.fb-suggestions {
  margin-bottom: 1rem;
  padding: .75rem 1rem;
  background: var(--accent-light);
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
}
.fb-suggestions-title {
  display: flex;
  align-items: center;
  gap: .5rem;
  color: var(--accent);
  font-weight: 600;
  font-size: .85rem;
  margin-bottom: .5rem;
}
.fb-suggestions-list { display: flex; flex-direction: column; gap: .375rem; }
.fb-suggestion {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .85rem;
  flex-wrap: wrap;
}
.fb-suggestion-time { font-weight: 600; min-width: 3rem; }
.fb-suggestion-title { color: var(--text-primary); }
.fb-suggestion-loc { color: var(--text-secondary); }

.fb-table .fb-row:hover { background: var(--bg-secondary); }
.fb-cell-route {
  display: inline-block;
  max-width: 28rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fb-row-chev { color: var(--text-tertiary); font-size: 1.2rem; }

/* Lueckenzeile — amber-Highlight per GoBD-Konvention */
.fb-gap-row {
  background: var(--amber-light);
}
.fb-gap-row td { padding-top: .5rem; padding-bottom: .5rem; }
.fb-gap-label {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  color: var(--amber);
  font-weight: 600;
  font-size: .85rem;
}

/* Form-Warnung im Trip-Panel (finalized) */
.fb-form-warning {
  margin-bottom: .75rem;
  padding: .5rem .75rem;
  background: var(--coral-light);
  border-left: 3px solid var(--coral);
  border-radius: var(--radius-sm);
  font-size: .85rem;
  color: var(--text-primary);
}

/* Kontakt-Autocomplete-Liste */
.fb-contact-suggest {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 5;
  max-height: 220px;
  overflow-y: auto;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
}
.fb-contact-suggest-item {
  padding: .5rem .75rem;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: .15rem;
  font-size: .85rem;
}
.fb-contact-suggest-item:hover { background: var(--bg-secondary); }
.fb-contact-primary  { color: var(--text-primary); }
.fb-contact-secondary { color: var(--text-tertiary); font-size: .78rem; }
/* Compat: altes fb-contact-mail bleibt */
.fb-contact-mail { color: var(--text-tertiary); font-size: .78rem; }
/* X-Button zum Entfernen des verknuepften Kontakts */
.fb-contact-clear {
  position: absolute;
  right: .4rem;
  top: 50%;
  transform: translateY(-50%);
  padding: .2rem;
  line-height: 1;
}

/* ── Driver-Log Trips-Listen-Controls (Search + Tab-Filter) ── */
.dl-list-controls {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}
.dl-list-controls .search-bar {
  margin-bottom: 0;
}

/* P8 — fb-toolbar Mobile: „Filter"-Trigger + Collapse */
.fb-toolbar-toggle  { display: none; }       /* Compat-Alias — nicht mehr in Verwendung */
.fb-toolbar-trigger { display: none; }       /* Desktop: Trigger unsichtbar */
.fb-toolbar-overflow { display: contents; }  /* Desktop: Items fliessen normal */
/* G — Maps-Import: nur auf Mobile sichtbar */
.fb-toolbar-mobile-only { display: none; }

@media (max-width: 900px) {
  .fb-toolbar {
    flex-wrap: nowrap;
    gap: .5rem;
    align-items: center;
  }
  /* P8 — Trigger-Button: immer sichtbar auf Mobile */
  .fb-toolbar-trigger {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    padding: .5rem .75rem;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    font-size: .875rem;
    font-weight: 500;
    cursor: pointer;
    flex-shrink: 0;
    white-space: nowrap;
    transition: background var(--transition);
  }
  .fb-toolbar-trigger:hover { background: var(--bg-secondary); }
  /* Chevron-Rotation im expanded-State */
  .fb-toolbar:not(.is-collapsed) .fb-toolbar-trigger svg {
    transform: rotate(180deg);
  }
  /* Collapse: Overflow ausblenden */
  .fb-toolbar.is-collapsed .fb-toolbar-overflow {
    display: none;
  }
  /* Expanded: Overflow mehrzeilig */
  .fb-toolbar:not(.is-collapsed) {
    flex-wrap: wrap;
    align-items: flex-start;
    row-gap: .5rem;
  }
  .fb-toolbar-overflow {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    width: 100%;
  }
  .fb-cell-route { max-width: 14rem; }
  .dl-list-controls { flex-direction: column; align-items: stretch; }
  .dl-list-controls .tab-filter { overflow-x: auto; }
  /* G — Maps-Import: sichtbar auf Mobile */
  .fb-toolbar-mobile-only { display: inline-flex; }
}

/* ── Driver-Log Import-Assistent ──────────────────────────── */
/* Upload-Card: .card gibt --bg-primary (weiss/dunkel), max-width begrenzt auf lesbares Format */
.dl-import-upload-card { max-width: 42rem; }
.dl-import-card-title  { margin: 0 0 .75rem; font-size: 1rem; font-weight: 600; }
/* Beschreibungs-Text im Upload-Schritt */
.dl-import-desc {
  font-size: .875rem;
  line-height: 1.5;
  color: var(--text-secondary);
  margin: 0 0 1.25rem;
}
/* Action-Wrapper fuer Schritt 1 und Done-Schritt — Flex-Reihe mit Gap */
.dl-import-actions {
  display: flex;
  gap: .5rem;
  margin-top: 1rem;
}
.dl-import-actions__primary { flex: 1; }
/* Zentrierte Variante fuer Done-Schritt (empty-state) */
.dl-import-actions--centered { justify-content: center; }
.dl-import-table .dl-import-row.is-unchecked { opacity: .5; }
.dl-import-mobile-row.is-unchecked           { opacity: .5; }
.dl-import-route {
  display: inline-block;
  max-width: 24rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .85rem;
}
/* Zeitanzeige unter Datum (Desktop + Mobile) */
.dl-import-time { font-size: .78rem; color: var(--text-tertiary); }
/* Match-Badge in der Mobile-Spalte — Block damit Badges untereinander stehen */
.dl-import-match-badge { display: block; margin-top: .25rem; }
/* Fehler-Details im Done-Schritt */
.dl-import-errors {
  text-align: left;
  max-width: 32rem;
  margin: 1rem auto;
}
.dl-import-errors-pre {
  white-space: pre-wrap;
  font-size: .78rem;
  margin: .5rem 0 0;
}
.dl-import-footer {
  display: flex;
  justify-content: space-between;
  gap: .5rem;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}

.select.select-sm {
  padding: .25rem 1.5rem .25rem .5rem;
  font-size: .85rem;
  height: auto;
  background-position: right 0.4rem center;
  background-size: 10px;
}

/* ── Driver-Log OBD2-UI ───────────────────────────────────── */

/* Status-Badge in Toolbar */
.dl-obd2-badge {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .25rem .5rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: .78rem;
  color: var(--text-secondary);
}

/* Badge-Slot-Sichtbarkeit: Desktop zeigt Badge im Overflow (neben Vehicle-Select),
   Mobile zeigt Badge ausserhalb des Overflow (immer sichtbar, auch bei collapsed Toolbar).
   Begruendung: Overflow wird auf Mobile bei is-collapsed ausgeblendet (display:none) →
   Badge muss ausserhalb liegen damit Android-Nutzer den OBD2-Status immer sehen. */
.dl-obd2-badge-mobile-slot  { display: none; }   /* Mobile: sichtbar (override unten) */
.dl-obd2-badge-desktop-slot { display: contents; } /* Desktop: normal im Flow */

@media (max-width: 900px) {
  /* Mobile: Badge ausserhalb des Overflow → immer sichtbar, kein Expand noetig */
  .dl-obd2-badge-mobile-slot  { display: inline-flex; align-items: center; }
  /* Mobile: Badge innerhalb des Overflow ausblenden (doppelt wuerde vorkommen) */
  .dl-obd2-badge-desktop-slot { display: none; }
}
.dl-obd2-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-tertiary);
  flex-shrink: 0;
}
.dl-obd2-dot-paired       { background: var(--accent); }
.dl-obd2-dot-active       { background: var(--teal); box-shadow: 0 0 0 2px rgba(42,187,138,.2); }
.dl-obd2-dot-connecting   { background: var(--amber); animation: dl-obd2-pulse 1s infinite; }
.dl-obd2-dot-disconnected { background: var(--text-tertiary); }
.dl-obd2-dot-error        { background: var(--danger); }
.dl-obd2-dot-idle         { background: var(--text-tertiary); }
@keyframes dl-obd2-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: .3; }
}

/* Active-Trip-Banner */
.dl-active-trip {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-bottom: 1rem;
  padding: .75rem 1rem;
  background: var(--teal-light);
  border: 1px solid var(--teal);
  border-radius: var(--radius-md);
  font-size: .9rem;
}
.dl-active-trip-text   { flex: 1; color: var(--text-primary); font-weight: 600; }
.dl-active-trip-meta   { color: var(--text-secondary); font-weight: 400; }

/* OBD2-Section im Vehicle-Form */
.dl-obd2-section {
  margin-top: 1rem;
  padding: .75rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.dl-obd2-section.dl-obd2-disabled {
  background: var(--bg-tertiary);
  opacity: .8;
}
.dl-obd2-section-title {
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: .5rem;
}
.dl-obd2-status {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: .5rem;
  font-size: .9rem;
}
.dl-obd2-meta {
  font-size: .8rem;
  color: var(--text-secondary);
  margin-bottom: .5rem;
}
.dl-obd2-hint {
  font-size: .75rem;
  color: var(--text-tertiary);
  margin-top: .5rem;
}
.dl-obd2-disabled-hint {
  font-size: .85rem;
  color: var(--text-secondary);
  font-style: italic;
}

/* OBD2-CTA im Trip-Form (unter den Speichern-Buttons) */
.dl-obd2-cta {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-top: 1rem;
  padding: .75rem;
  background: var(--accent-light);
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
  flex-wrap: wrap;
}
.dl-obd2-cta-text {
  flex: 1;
  min-width: 12rem;
  font-size: .85rem;
  color: var(--text-primary);
}

/* Source-Badge in Trip-Liste */
.dl-source-badge {
  margin-left: .375rem;
  font-size: .65rem;
  padding: 1px 5px;
  vertical-align: middle;
}

/* ── GoBD Banner (5/7-Tage-Frist) ─────────────────────────── */
.dl-gobd-banner {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: 1rem;
  padding: .625rem 1rem;
  border-radius: var(--radius-md);
  background: var(--amber-light);
  color: var(--amber);
  border-left: 3px solid var(--amber);
  font-size: .875rem;
}
.dl-gobd-banner-urgent {
  background: var(--coral-light);
  color: var(--coral);
  border-left-color: var(--coral);
  font-weight: 600;
}
.dl-gobd-banner-text { flex: 1; }

/* ── Period-Close-Dialog ──────────────────────────────────── */
.dl-period-close-meta {
  margin-bottom: 1rem;
  font-size: .9rem;
  color: var(--text-secondary);
}
.dl-period-close-meta strong { color: var(--text-primary); display: inline-block; min-width: 6rem; }
.dl-period-summary {
  margin: .5rem 0;
  padding-left: 1.25rem;
  font-size: .9rem;
}
.dl-period-summary li { margin: .25rem 0; }
.dl-period-warning {
  margin: .75rem 0;
  padding: .5rem .75rem;
  background: var(--amber-light);
  border-left: 3px solid var(--amber);
  border-radius: var(--radius-sm);
  font-size: .85rem;
  color: var(--text-primary);
}
/* Ticket 3.336.1 — Wiedereroeffnen-Aktion direkt unter dem Sperrhinweis */
.dl-period-reopen-actions {
  margin: -.25rem 0 .75rem;
}

/* ── Korrektur-Sub-Panel + Audit-Trail ───────────────────── */
.dl-audit {
  margin-top: 1rem;
  padding: .75rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-md);
}
.dl-audit-title {
  font-size: .78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-secondary);
  margin-bottom: .5rem;
}
.dl-audit ul { padding-left: 1.25rem; margin: 0; font-size: .85rem; }
.dl-audit li { margin: .25rem 0; }
.dl-audit-when {
  font-weight: 600;
  color: var(--text-primary);
  margin-right: .375rem;
}
.dl-audit-field {
  font-style: italic;
  color: var(--accent);
}
.dl-audit-reason {
  color: var(--text-tertiary);
  font-size: .78rem;
  margin-top: .125rem;
}
.dl-correction-form {
  margin-top: .75rem;
  padding: .75rem;
  background: var(--accent-light);
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
}
.dl-correction-title {
  font-size: .85rem;
  font-weight: 600;
  color: var(--accent);
  margin-bottom: .5rem;
}

/* ── PDF-Dropdown ────────────────────────────────────────── */
.dl-pdf-dropdown {
  position: relative;
  display: inline-block;
}
.dl-pdf-menu {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: .25rem;
  z-index: 10;
  min-width: 12rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.dl-pdf-menu-item {
  display: block;
  width: 100%;
  padding: .5rem .75rem;
  text-align: left;
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: .85rem;
  color: var(--text-primary);
}
.dl-pdf-menu-item:hover { background: var(--bg-secondary); }

/* HTML-Read-Mode: Inline-Formatierung darstellen */
.cal-event-form-desc-html p { margin: 0 0 .5rem; }
.cal-event-form-desc-html p:last-child { margin-bottom: 0; }
.cal-event-form-desc-html ul,
.cal-event-form-desc-html ol { margin: 0 0 .5rem; padding-left: 1.25rem; }
.cal-event-form-desc-html li { margin: .15rem 0; }
.cal-event-form-desc-html a {
  color: var(--accent);
  text-decoration: underline;
  word-break: break-word;
}
.cal-event-form-desc-html a:hover { color: var(--accent-dark); }
.cal-event-form-desc-html strong, .cal-event-form-desc-html b { font-weight: 600; }
.cal-event-form-desc-html em, .cal-event-form-desc-html i { font-style: italic; }
.cal-event-form-desc-html code {
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  padding: 1px 4px;
  font-size: .85em;
}
.cal-event-form-desc-html blockquote {
  margin: 0 0 .5rem;
  padding-left: .75rem;
  border-left: 3px solid var(--border);
  color: var(--text-secondary);
}

/* Edit-Mode: ds-rich-editor + Quill-Container die volle Wrap-Hoehe nutzen */
.cal-event-form-desc-wrap.is-edit { display: flex; flex-direction: column; }
.cal-event-form-desc-wrap.is-edit ds-rich-editor {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.cal-event-form-desc-wrap.is-edit .ds-rich-editor {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.cal-event-form-desc-wrap.is-edit .ds-rich-editor-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.cal-event-form-desc-wrap.is-edit .ql-container.ql-snow {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.cal-event-form-desc-wrap.is-edit .ql-container .ql-editor {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* ── Mobile-Lücken-Zeilen (native-row--gap, seit 2026-06-27) ─────────── */
/* Visuelle Abgrenzung: amber-Hintergrund analog Desktop .fb-gap-row,
   aber als native-row Card-Variante mit Action-Buttons unterhalb. */
.native-row--gap {
  background: var(--amber-light);
  border-left: 3px solid var(--amber);
  flex-wrap: wrap;
  gap: .5rem;
  align-items: flex-start;
  cursor: default; /* Lücken-Row ist kein Drill-Down */
}

.native-row--gap:hover {
  background: var(--amber-light); /* kein Standard-hover-override */
}

.dl-mobile-gap-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--amber);
  flex-shrink: 0;
  padding-top: .125rem;
}

.dl-mobile-gap-label {
  color: var(--amber);
  font-weight: 600;
}

/* Action-Buttons Zeile — volle Breite unterhalb der Info-Reihe */
.dl-mobile-gap-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
  width: 100%;
  padding-left: 0;
}

/* Schmalere Buttons auf Mobile damit alle 3 in eine Zeile passen */
.dl-mobile-gap-btn {
  font-size: .8rem;
  padding: .3125rem .625rem;
  min-height: 36px;
  border-color: var(--amber);
  color: var(--amber);
}

.dl-mobile-gap-btn:hover {
  background: var(--amber-light);
  border-color: var(--amber);
}

/* ── Invoice / Quote Module (Spec 3300-A) ──────────────────────────────── */

/* Bug 6: Summary-Bar kompakt im Page-Header (page-header-summary) */
.page-header-summary {
  display: flex;
  gap: .5rem;
  flex: 1;
  flex-wrap: wrap;
  min-width: 0;
}

/* Legacy standalone .invoice-summary-bar (wird nicht mehr gerendert, CSS bleibt fuer Fallback) */
.invoice-summary-bar {
  display: flex;
  gap: 1rem;
  padding: .75rem 0;
  margin-bottom: 1rem;
  overflow-x: auto;
}

.invoice-summary-item {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-md);
  padding: .35rem .75rem;
  min-width: 90px;
  flex-shrink: 0;
  transition: background var(--transition);
}
/* Issue 6: klickbare Summary-Items erhalten Hover-Feedback */
.invoice-summary-item:hover {
  background: var(--accent-light);
}

/* Kompaktere Items wenn im page-header */
.page-header-summary .invoice-summary-item {
  padding: .3rem .625rem;
  min-width: 80px;
}

.invoice-summary-label {
  font-size: .7rem;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
}

.invoice-summary-value {
  font-size: .9rem;
  font-weight: 600;
  color: var(--text-primary);
}

/* ── Mobile Summary-Strip (offers.js + invoices.js) ──────────────
   Ersetzt den Inline-Style-Wust aus _renderMobileSummaryStrip():
   3 Stat-Badges fuellen gleichmaessig die volle Breite (= Suchfeld-
   Breite), kein horizontales Scrollen mehr. Farbvarianten sind nach
   FARBE benannt (nicht nach Label), weil offers.js (Entwuerfe/Offen/
   Angenommen) und invoices.js (Offen/Ueberfaellig/Bezahlt) dieselben
   Klassen mit unterschiedlicher Label-Semantik teilen (P-5).
*/
.invoicing-summary-strip {
  display: flex;
  width: 100%;
  gap: .5rem;
  padding: .375rem 0 .5rem;
}
.invoicing-summary-strip-item {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: .375rem .5rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  text-align: center;
  transition: filter var(--transition);
}
.invoicing-summary-strip-item:hover,
.invoicing-summary-strip-item:active {
  filter: brightness(0.96);
}
.invoicing-summary-strip-label,
.invoicing-summary-strip-value {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.invoicing-summary-strip-label {
  font-size: .6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
}
.invoicing-summary-strip-value {
  font-size: .9375rem;
  font-weight: 700;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.invoicing-summary-strip-item--amber {
  background: var(--amber-light);
  border-color: var(--amber);
}
.invoicing-summary-strip-item--amber .invoicing-summary-strip-label,
.invoicing-summary-strip-item--amber .invoicing-summary-strip-value {
  color: var(--amber);
}
.invoicing-summary-strip-item--coral {
  background: var(--coral-light);
  border-color: var(--coral);
}
.invoicing-summary-strip-item--coral .invoicing-summary-strip-label,
.invoicing-summary-strip-item--coral .invoicing-summary-strip-value {
  color: var(--coral);
}
.invoicing-summary-strip-item--teal {
  background: var(--teal-light);
  border-color: var(--teal);
}
.invoicing-summary-strip-item--teal .invoicing-summary-strip-label,
.invoicing-summary-strip-item--teal .invoicing-summary-strip-value {
  color: var(--teal);
}

/* Positionen-Sektion im Editor-Panel */
.invoice-items-section {
  margin-top: .75rem;
  /* Issue 4: border-top + padding-top entfernt — Fieldset-Wrapper liefert Trennung */
}

.invoice-items-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .75rem;
  font-weight: 600;
  font-size: .9rem;
}

.invoice-items-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

.invoice-item {
  display: flex;
  flex-direction: column;  /* Bug 2: action-links unter der Row (nicht daneben) */
  padding: .5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
}

/* Bug 2: Drag-Handle + Grid-Row horizontal nebeneinander */
.invoice-item-main {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
}

.invoice-item.section {
  background: var(--bg-secondary);
  border-style: dashed;
  /* Bug 4: Drag-Handle | Title-Textarea | X.
     B29: align-items:center bleibt — .invoice-item-delete ist ein .btn-icon
     (min 44px) und bleibt bis 2 Textzeilen (~41px) das hoechste Element der
     Reihe, das die Zeilenhoehe bestimmt; center haelt den Titel-Text (egal ob
     1 oder mehrere Zeilen) optisch mittig zum Button/Drag-Handle. Mit
     align-items:start wuerde der 44px-Button bei einzeiligen Titeln (Regelfall)
     ueber der Textmitte "schweben" — das waere die schlechtere Option. */
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: .5rem;
  padding: .375rem .5rem;
}

.invoice-item.is-dragging,
.invoice-item.is-dragging .drag-handle {
  opacity: .4;
  cursor: grabbing;
}

/* Ticket 3.70: optionale Angebotsposition — dezente Kennzeichnung der Zeile
   (analog PDF ItemsTableRenderer::renderOptionalBadge — dort grau/kursiv statt
   Akzentfarbe, die bleibt .invoice-item.section vorbehalten). */
.invoice-item.is-optional {
  border-left: 2px dashed var(--border);
}
.invoice-item.is-optional .invoice-item-desc {
  font-style: italic;
}

/* Checkbox-Toggle „Optional" im Positions-Editor — nur Angebote (s.
   _document-items.js allowOptionalItems). Kein .ds-theme-toggle: das Muster ist
   fuer app-weite Ein/Aus-Einstellungen reserviert, hier ist es eine Zeilen-
   Auswahl analog .ds-merge-row-check (Anhaenge-Zusammenfuehren-Panel).
   🔒 Ticket 187: steht seit dieser Session unter der "Produkt/Preis speichern"-
   Zeile (.invoice-item-actions) statt in der Beschreibungs-Spalte — padding-left
   2.5rem uebernimmt exakt den Einzug von .invoice-item-actions (Drag-Handle +
   Beschreibung), damit beide Zeilen buendig untereinander stehen. */
.invoice-item-optional-toggle {
  display: flex;
  align-items: center;
  gap: .3rem;
  font-size: .75rem;
  color: var(--text-tertiary);
  margin-top: .25rem;
  padding-left: 2.5rem;
  cursor: pointer;
  user-select: none;
}
.invoice-item-optional-toggle input[type="checkbox"] {
  width: 14px;
  height: 14px;
  accent-color: var(--accent);
  cursor: pointer;
}

/* Desktop: Grid-Layout — 7 sichtbare Spalten via display:contents auf Wrapper-Divs */
.invoice-item-row {
  display: grid;
  /* desc(flex), qty(60), unit-select(96), price(92), tax(76), total(96), X(32), 3-Punkte(30) */
  grid-template-columns: minmax(0, 1.8fr) 60px 96px 92px 76px 96px 32px 30px;
  gap: .4rem;
  align-items: flex-start;
  flex: 1; /* nimmt restliche Breite im .invoice-item-main Flex-Row */
}

.invoice-item-desc  { grid-column: 1; }

/* Auf Desktop: Wrapper-Divs transparent fuer das Grid */
.invoice-item-meta,
.invoice-item-tax-total {
  display: contents;
}

.invoice-item-qty   { text-align: right; }
.invoice-item-price { text-align: right; }
/* Issue 8b: MwSt-Select breiter damit Prozentzeichen sichtbar */
.invoice-item-tax   { width: 76px; min-width: 76px; }
/* Issue 8c: Einheit-Select native + Custom-Input-Fallback */
.invoice-item-unit-wrap {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  min-width: 0;
}
.invoice-item-unit-custom {
  font-size: .85rem;
}

.invoice-item-total {
  text-align: right;
  font-weight: 500;
  font-size: .9rem;
  white-space: nowrap;
  color: var(--text-primary);
  /* Issue 8a: feste Breite + read-only-Stil verhindert Layout-Shift */
  width: 96px;
  min-width: 96px;
  background: var(--bg-secondary);
  font-variant-numeric: tabular-nums;
  cursor: default;
}
.invoice-item-section-title {
  flex: 1;
  font-weight: 600;
  background: transparent;
  border: none;
  font-size: .95rem;
  /* B29: <textarea rows="1"> statt <input> — waechst mit dem Inhalt statt
     ihn abzuschneiden (Hoehe wird per _autoGrowSectionTitle() gesetzt). */
  width: 100%;
  resize: none;
  overflow: hidden;
  line-height: 1.35;
  min-height: 0;
  padding: 0;
}
/* B29: order-confirmations.js nutzt eine eigene Klasse fuer dasselbe Feld
   (kein gemeinsamer .invoice-item.section-Wrapper dort, s. design-system.md
   „invoicing" — die OC-Zeile hat kein eigenes Bold/Transparent-Styling, nur
   das fuer den Zeilenumbruch noetige Verhalten wird ergaenzt). min-height
   bewusst NICHT auf 0 gesetzt — die geerbte .input-Mindesthoehe (44px) bleibt
   fuer 1-2 Zeilen die bisherige Boxhoehe, JS-Hoehe wächst erst darueber hinaus. */
.invoice-item-section-input {
  width: 100%;
  resize: none;
  overflow: hidden;
  line-height: 1.35;
}
.invoice-item-text {
  flex: 1;
  min-height: 60px;
}

/* Spec 20260722 §3.1 — Zwischensumme: neutral/fett + duenne Trennlinie oben,
   bewusst NICHT accent-blau wie .invoice-item.section (Abschnitt = Start,
   Zwischensumme = Ende — visuell soll nur der Abschnitt „auffallen"). Analog
   der PDF-Zeile in ItemsTableRenderer::renderSubtotalRow (border-top + bold). */
.invoice-item.subtotal {
  background: var(--bg-primary);
  border-top: 2px solid var(--border);
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: .5rem;
  padding: .5rem .5rem .375rem;
}
.invoice-item-subtotal-label {
  font-weight: 600;
  background: transparent;
  border: none;
  font-size: .95rem;
  min-width: 0;
}
.invoice-item-subtotal-label::placeholder {
  font-weight: 400;
  color: var(--text-tertiary);
}
.invoice-item-subtotal-amount {
  font-weight: 700;
  font-size: .9rem;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  padding-right: .25rem;
}

/* Spec 20260722 §5 — Seitenumbruch: rein kosmetisches PDF-Signal, kein Inhalt
   (kein Eingabefeld, kein Betrag). Bewusst die schlankste aller Positions-
   Zeilen: transparent, ohne Border/BG — nur eine gestrichelte Trennlinie mit
   zentrierter Beschriftung. Klar unterscheidbar von .invoice-item.section
   (Akzent-Blau, Start eines Abschnitts) und .invoice-item.subtotal
   (neutral/fett, Ende eines Bereichs). */
.invoice-item.pagebreak {
  background: transparent;
  border: none;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: .5rem;
  padding: .25rem .5rem;
}
.invoice-item-pagebreak-line {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .375rem;
  min-width: 0;
  color: var(--text-tertiary);
}
.invoice-item-pagebreak-line::before,
.invoice-item-pagebreak-line::after {
  content: '';
  flex: 1;
  border-top: 1px dashed var(--border);
}
.invoice-item-pagebreak-label {
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .01em;
  white-space: nowrap;
}

/* Toggle „Abschnittsweise nummerieren" — ganz oben im Positions-Block, dezent als Teil
   der Block-Konfiguration (nicht als eigene Box) — Spec 20260722 §3.2, Feinschliff 2026-07-22 */
.invoice-section-numbering-toggle {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding-bottom: .625rem;
}
.invoice-section-numbering-toggle-text {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  min-width: 0;
}
.invoice-section-numbering-toggle-label {
  font-size: .8125rem;
  font-weight: 500;
  color: var(--text-secondary);
}
.invoice-section-numbering-toggle-hint {
  font-size: .72rem;
  color: var(--text-tertiary);
}

.invoice-items-add-bar {
  display: flex;
  gap: .5rem;
  margin-top: .5rem;
  flex-wrap: wrap;
  padding: .5rem .75rem;
  background: var(--bg-secondary);
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
}

/* Summen-Anzeige */
.invoice-totals {
  margin-top: 1rem;
  border-top: 1px solid var(--border);
  padding-top: .75rem;
  display: flex;
  flex-direction: column;
  gap: .3rem;
  align-items: flex-end;
}

.invoice-totals-row {
  display: flex;
  gap: 2rem;
  font-size: .9rem;
  color: var(--text-secondary);
}

.invoice-totals-gross {
  font-weight: 700;
  font-size: 1rem;
  color: var(--text-primary);
  border-top: 1px solid var(--border);
  padding-top: .3rem;
  margin-top: .2rem;
}

/* Ticket 3.70: „Optionen (nicht enthalten)" — dezent, analog PDF
   ItemsTableRenderer::renderOptionalTotalRow (kursiv/grau, keine Akzentfarbe). */
.invoice-totals-optional-row {
  font-size: .8rem;
  font-style: italic;
  color: var(--text-tertiary);
}

/* ── Globaler Rabatt / Aufschlag — Anzeige unter Positionen (Session 4) ── */

/* Add-Button: subtiler Link-Stil, rechtsbündig unter der Positions-Liste */
.invoicing-global-discount-add {
  display: flex;
  justify-content: flex-end;
  margin-top: .375rem;
}

.invoicing-global-discount-add-btn {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  background: none;
  border: none;
  color: var(--text-tertiary);
  cursor: pointer;
  font-size: .8125rem;
  padding: .25rem .375rem;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
}

.invoicing-global-discount-add-btn:hover {
  color: var(--accent);
  background: var(--accent-light);
}

.invoicing-global-discount-add-btn svg {
  flex-shrink: 0;
}

/* Anzeige-Zeile wenn Rabatt / Aufschlag gesetzt */
.invoicing-global-discount-display {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-top: .5rem;
  padding: .4rem .625rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
}

.invoicing-global-discount-label {
  flex: 1;
  color: var(--text-secondary);
  min-width: 0;
}

.invoicing-global-discount-action {
  background: none;
  border: none;
  color: var(--accent);
  cursor: pointer;
  font-size: .8rem;
  padding: .125rem .25rem;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  transition: background var(--transition);
}

.invoicing-global-discount-action:hover {
  background: var(--accent-light);
}

.invoicing-global-discount-action--remove {
  color: var(--coral);
}

.invoicing-global-discount-action--remove:hover {
  background: var(--coral-light);
}

/* Totals-Zeile für Rabatt / Aufschlag — leicht hervorgehoben */
.invoicing-global-discount-totals-row {
  color: var(--text-secondary);
  font-style: italic;
}

.invoicing-global-discount-totals-row span:last-child {
  font-variant-numeric: tabular-nums;
}

/* Überfällig-Highlight in Tabelle */
.row-overdue {
  background: rgba(216, 90, 48, .04);
}

/* P3 — Mobile: H1 ausblenden wenn L3-Tab Modul-Name schon zeigt */
@media (max-width: 900px) {
  page-invoices             .page-header,
  page-offers               .page-header,
  /* F9 (Spec 20260728_document_type_parity, Session S9): AB hat ebenfalls einen
     L3-Tab-Balken (nav-config tabs) — Header-Duplikat auf Mobile daher analog
     Rechnung/Angebot ausgeblendet, FAB + Mobile-Summary-Strip uebernehmen. */
  page-order-confirmations  .page-header,
  page-driver-log           .page-header,
  page-notes                .page-header {
    display: none;
  }
}

/* Mobile: Summary-Bar in page-header nimmt eigene Zeile */
@media (max-width: 900px) {
  .invoice-summary-bar { overflow-x: auto; }
  .page-header-summary {
    order: 3;          /* nach h1 + page-header-actions */
    flex-basis: 100%;  /* bricht auf neue Zeile */
    overflow-x: auto;
  }
}

/* P6 — Mobile: Card-pro-Position Layout (< 600px) */
@media (max-width: 600px) {
  .invoice-item {
    flex-direction: column;
    padding: .75rem;
    gap: .5rem;
    position: relative;
  }
  /* Bug 2: .invoice-item-main nimmt volle Breite auf Mobile */
  .invoice-item-main {
    width: 100%;
  }
  .invoice-item .drag-handle {
    position: absolute;
    top: .375rem;
    left: .375rem;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .invoice-item-row {
    display: grid;
    grid-template-columns: 1fr;
    gap: .5rem;
    padding-left: 2.5rem;  /* Drag-Handle-Platz */
    padding-right: 2.5rem; /* Action-Button-Platz */
  }
  .invoice-item-desc {
    grid-row: 1;
    font-size: 1rem;
  }
  /* Wrapper für Autocomplete-Dropdown (PA-3) — erbt grid-row:1 durch Auto-Flow */
  .invoice-item-desc-wrap {
    grid-row: 1;
    grid-column: 1;
  }
  .invoice-item-meta {
    grid-row: 2;
    display: grid;
    grid-template-columns: 80px 1fr 110px;
    gap: .5rem;
  }
  .invoice-item-tax-total {
    grid-row: 3;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-top: .5rem;
    border-top: 1px dashed var(--border);
    font-size: .875rem;
  }
  /* Inline-X-Button ausblenden — wird durch Action-Menue ersetzt */
  .invoice-item .invoice-item-delete { display: none; }
  /* 3-Punkte-Button auf Mobile absolut positioniert (oben rechts) */
  .invoice-item-action-btn {
    position: absolute;
    top: .375rem;
    right: .375rem;
    display: flex;
  }
  /* Grid-Spalte fuer 3-Punkte-Button entfaellt auf Mobile (absolut positioniert) */
  .invoice-item-row {
    padding-right: 2.5rem;
  }
}

/* Action-Button (3 Punkte) rechts oben im Mobile-Item */
.invoice-item-action-btn {
  /* Session 3: Sichtbar auf Desktop + Mobile — 3-Punkte-Menue neben Trash-Icon */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  background: transparent;
  border: 0;
  color: var(--text-tertiary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  padding: 0;
  flex-shrink: 0;
}
.invoice-item-action-btn:hover { background: var(--bg-secondary); }

/* Bug 7: sticky entfernt — Totals erscheinen nur am Dokumentende */
.invoice-totals--sticky-mobile {
  margin-top: 1rem;
}

/* Issue 6+7: Dezente Aktions-Links unter einem Produkt-Item (Produkt/Kundenpreis speichern) */
.invoice-item-actions {
  display: flex;
  gap: .75rem;
  justify-content: flex-start;  /* Issue 7: links unten unter Beschreibung-Toggle */
  margin-top: .25rem;
  padding: 0 0 .25rem 2.5rem;   /* Issue 7: links unter Drag-Handle + Desc eingerückt */
}
.invoice-item-link {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  font-size: .75rem;
  cursor: pointer;
  text-decoration: underline;
  line-height: 1.4;
}
.invoice-item-link:hover { color: var(--accent-dark); }

/* Session 3 — Rabatt-Pille pro Position (Aufgabe D) */
.invoice-item-discount-badge {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  margin-top: .3rem;
  padding: .125rem .45rem .125rem .5rem;
  border-radius: 999px;
  background: var(--coral-light);
  color: var(--coral);
  font-size: .72rem;
  font-weight: 500;
  line-height: 1.4;
  user-select: none;
}
.invoice-item-discount-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--coral);
  cursor: pointer;
  border-radius: 50%;
  flex-shrink: 0;
  opacity: .7;
  transition: opacity var(--transition);
}
.invoice-item-discount-clear:hover { opacity: 1; background: rgba(0,0,0,.08); }
:root[data-theme="dark"] .invoice-item-discount-clear:hover,
:root:not([data-theme="light"]) .invoice-item-discount-clear:hover { background: rgba(255,255,255,.12); }

/* Session 3 — Context-Menu Section-Header (EINFÜGEN / EIGENSCHAFTEN) */
.ds-context-menu-header {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  padding: .6rem .7rem .2rem;
  cursor: default;
  user-select: none;
}
.ds-context-menu-header:first-child { padding-top: .25rem; }

/* Bug 1+2: Empfänger-Grid — 2 separate Cards (je .ds-fieldset mit align-self:stretch) */
.invoicing-recipient-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-bottom: .5rem;  /* Abstand vor Titel-Zeile */
}
.invoicing-recipient-grid > .ds-fieldset {
  align-self: stretch;   /* beide Cards gleiche Höhe */
  margin-bottom: 0;      /* kein Extra-Margin aus Standard-Fieldset */
}
@media (max-width: 900px) {
  .invoicing-recipient-grid {
    grid-template-columns: 1fr;
  }
}

/* Issue 2: Datum-Grid — 2-spaltig (Datum links, Leistungszeitraum rechts) */
.invoicing-dates-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-bottom: .5rem;
}
.invoicing-dates-grid > .ds-fieldset {
  align-self: stretch;
  margin-bottom: 0;
}
@media (max-width: 900px) {
  .invoicing-dates-grid {
    grid-template-columns: 1fr;
  }
}

/* Bug 2: Sub-Block für Adress-/E-Mail-Typ + Override visuell gruppiert */
.invoicing-recipient-subblock {
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  padding: .5rem .625rem;
  display: flex;
  flex-direction: column;
  gap: .375rem;
  margin-top: .25rem;
}

/* Bug 4: Readonly-Anzeige für computed Adresse/E-Mail (nicht-manual Modus) */
.invoicing-recipient-readonly {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .5rem .625rem;
  font-size: .875rem;
  color: var(--text-secondary);
  white-space: pre-line;
  min-height: 3rem;
  line-height: 1.5;
}

/* ── Invoicing: Position-Langbeschreibung + Custom-Einheit-Picker (Editor-Improvements B.10/B.12) ── */

.invoice-item-longdesc {
  width: 100%;
  min-height: 3.5rem;
  resize: vertical;
  font-size: .875rem;
  padding: .375rem .5rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  line-height: 1.5;
  box-sizing: border-box;
  font-family: inherit;
}
.invoice-item-longdesc:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--bg-primary);
}

.invoice-item-longdesc-toggle {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .75rem;
  color: var(--text-tertiary);
  background: none;
  border: none;
  padding: .1rem .25rem;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: color var(--transition);
  margin-top: .125rem;
}
.invoice-item-longdesc-toggle:hover {
  color: var(--accent);
  background: var(--accent-light);
}

.invoice-item-longdesc-readonly {
  font-size: .8125rem;
  color: var(--text-secondary);
  white-space: pre-wrap;
  line-height: 1.45;
  padding: .25rem 0;
}

/* P2 — Inline-Rabatt-Anzeige in Preis-Spalte (ersetzt Pille in Beschreibungs-Spalte) */
.invoice-item-price-wrap {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  min-width: 0;
}

.invoice-item-price-discount {
  display: flex;
  align-items: center;
  gap: .15rem;
  margin-top: .1rem;
}

.invoice-item-discount-pct,
.invoice-item-discount-amt {
  width: 4.5rem;
  min-width: 0;
  font-size: .78rem;
  padding: .2rem .3rem;
  height: 1.6rem;
  color: var(--coral);
  border-color: var(--coral-light);
  background: var(--coral-light);
  text-align: right;
}
.invoice-item-discount-pct:focus,
.invoice-item-discount-amt:focus {
  border-color: var(--coral);
  outline: none;
  box-shadow: 0 0 0 2px rgba(216,90,48,.15);
}

.invoice-item-discount-unit {
  font-size: .75rem;
  color: var(--coral);
  cursor: pointer;
  padding: 0 .15rem;
  user-select: none;
  transition: opacity var(--transition);
}
.invoice-item-discount-unit:hover { opacity: .7; }

/* × Clear-Button im Preis-Discount-Strip — braucht mehr Platz als der SVG-Variant in der Badge */
.invoice-item-price-discount .invoice-item-discount-clear {
  width: 18px;
  height: 18px;
  font-size: .75rem;
  line-height: 1;
}

/* P2 — Total-Spalte mit Rabatt-Hinweis darunter */
.invoice-item-total-wrap {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  min-width: 0;
}

.invoice-item-total-discount-hint {
  font-size: .72rem;
  color: var(--coral);
  text-align: right;
  white-space: nowrap;
  padding-right: .25rem;
}

/* Custom Unit Picker Dropdown (B.12 — replaces <datalist>) */
.unit-picker-wrap {
  position: relative;
}

.unit-picker-dropdown {
  position: absolute;
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  z-index: 50;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  max-height: 200px;
  overflow-y: auto;
}

.unit-picker-item {
  padding: .375rem .75rem;
  cursor: pointer;
  font-size: .875rem;
  color: var(--text-primary);
  white-space: nowrap;
  transition: background var(--transition);
}
.unit-picker-item:hover,
.unit-picker-item.is-active {
  background: var(--accent-light);
  color: var(--accent);
}

/* ── Settings: Invoicing ──────────────────────────────────── */

/* Profile-List */
.invoicing-profile-list {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  margin-top: .5rem;
}

/* Profile-Card */
.invoicing-profile-card { cursor: pointer; }
.invoicing-profile-card__body {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .875rem 1rem;
}
.invoicing-profile-card__avatar {
  flex-shrink: 0;
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 700;
}
.invoicing-profile-card__logo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}
.invoicing-profile-card__info {
  flex: 1;
  min-width: 0;
}
.invoicing-profile-card__title-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}
.invoicing-profile-card__name {
  font-weight: 600;
  font-size: .9375rem;
}
.invoicing-profile-card__sub {
  font-size: .8125rem;
  color: var(--text-secondary);
  margin-top: .125rem;
}
.invoicing-profile-card__actions {
  display: flex;
  align-items: center;
  gap: .25rem;
  flex-shrink: 0;
}

/* Manuelle Fußzeile — 3-Spalten direkt unter footer_style-Tabs */
.invoicing-manual-footer-cols {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: .5rem;
  margin-top: .5rem;
}
@media (max-width: 600px) {
  .invoicing-manual-footer-cols { grid-template-columns: 1fr; }
}

/* Ghost-Danger variant for icon buttons (e.g. Delete in profile card) */
.btn-danger-ghost { color: var(--danger); }
.btn-danger-ghost:hover { background: var(--danger-light); }

/* Skeleton loading state */
.invoicing-skeleton-card { margin: 1rem 0; }
.invoicing-skeleton-bar--wide {
  width: 60%;
  height: 1.25rem;
  margin-bottom: .5rem;
}
.invoicing-skeleton-bar--narrow { width: 40%; }

/* Empty state */
.invoicing-empty-state { margin-top: 2rem; }

/* Panel: tab-bar bottom spacing */
.invoicing-panel-tabs { margin-bottom: 1.25rem; }

/* Form: required asterisk */
.form-label-required { color: var(--coral); }

/* Form: Toggle row (label beside toggle) */
.invoicing-toggle-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-top: .25rem;
}
.invoicing-toggle-label {
  font-size: .875rem;
  color: var(--text-secondary);
}

/* Form: PLZ + Stadt side-by-side */
.invoicing-zip-city-row {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: .5rem;
}

/* Form: Color-Picker row */
.invoicing-color-picker {
  display: flex;
  gap: .5rem;
  align-items: center;
}
.invoicing-color-picker input[type="color"] {
  width: 40px;
  height: 36px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  padding: 0;
  cursor: pointer;
}
.invoicing-color-hex { width: 7rem; }

/* Form: Logo preview */
.invoicing-logo-preview {
  display: block;
  max-height: 60px;
  max-width: 200px;
  margin-bottom: .5rem;
  border-radius: var(--radius-sm);
}

/* Ticket 3.171: Vorschau der deckenden Logo-Variante ("So erscheint das Logo
   in der E-Rechnung") -- fixes Weiss statt Theme-Variable, analog
   .pub-doc-iframe{background:#ffffff} (public-doc.css): die PDF/A-3b-Datei
   ist immer auf Papier/weiss kalibriert, unabhaengig vom App-Theme. Das Bild
   selbst traegt bereits einen gebackenen weissen Hintergrund (GD-Komposition,
   s. BusinessProfileController::buildOpaqueLogoVariant()) -- der Rahmen macht
   nur die Kante sichtbar, v.a. im Dark-Mode. */
.invoicing-logo-opaque-preview {
  margin-top: .5rem;
  padding: .5rem;
  background: #ffffff;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  display: inline-block;
}
.invoicing-logo-opaque-preview .invoicing-hint-text {
  color: #666666;
  margin: 0 0 .375rem 0;
}
.invoicing-logo-preview--opaque { margin-bottom: 0; }

/* Form: file input padding */
.invoicing-file-input { padding: .375rem; }

/* Form: Hint text below inputs */
.invoicing-hint-text {
  font-size: .78rem;
  color: var(--text-tertiary);
  margin: .25rem 0 0;
}

/* Inline-Speicher-Link nach Adress-/E-Mail-Blur (Bug 1 fix 2026-05-15) */
.invoicing-pending-save-link {
  display: inline-block;
  margin-top: .25rem;
  font-size: .8125rem;
  color: var(--accent);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.invoicing-pending-save-link:hover {
  color: var(--accent-dark);
}

/* 2-Spalten-Grid für zusammengehörige Farbfelder (Vorlage-Tab) */
.invoicing-form-grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
@media (max-width: 600px) {
  .invoicing-form-grid-2 { grid-template-columns: 1fr; }
}

/* Form: Save/Cancel action row */
.invoicing-form-actions {
  display: flex;
  gap: .5rem;
  margin-top: 1.5rem;
}
.invoicing-form-actions__save { flex: 1; }

/* Generic info-box — reusable (GoBD notices, format help, etc.) */
.ds-info-box {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .6rem .85rem;
  font-size: .85rem;
  color: var(--text-secondary);
  margin: .5rem 0;
  line-height: 1.5;
}
.ds-info-box--amber {
  background: var(--amber-light);
  border-color: transparent;
  color: var(--amber);
}
/* Teal-Variante: positive Bestaetigung (z.B. "Synchronisiert mit ...") —
   Pendant zu --amber, seit 2026-07-17 (Kalender Sync-Zustands-Indikator). */
.ds-info-box--teal {
  background: var(--teal-light);
  border-color: transparent;
  color: var(--teal);
}
/* Coral-Variante: deutliche Warnung (z.B. „Schutz wird aufgehoben") – Pendant zu
   --amber/--teal, seit Ticket 3.422 (Steuerberater-Freigabe-Link ueberlebt
   Passwortaenderung – Warnhinweis beim Aufheben des Link-Passwortschutzes). */
.ds-info-box--coral {
  background: var(--coral-light);
  border-color: transparent;
  color: var(--coral);
}
.ds-info-box--with-action {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
}
.ds-info-box--with-action > :first-child {
  flex: 1;
  min-width: 0;
}

/* Mobile adjustments */
@media (max-width: 900px) {
  .invoicing-zip-city-row {
    grid-template-columns: 100px 1fr;
  }
  .invoicing-color-picker { flex-wrap: wrap; }
}

/* ── PDF-Vorschau iframe ─────────────────────────────────────────
   Ersetzt style="width:100%;height:70vh;border:none;border-radius:var(--radius-md)"
   in offers.js + invoices.js _showPdf().
   Scope: Invoice/Offer panel PDF view.
*/
.invoice-pdf-iframe {
  width: 100%;
  height: 70vh;
  border: none;
  border-radius: var(--radius-md);
  display: block;
}

/* ── PDF-Vorschau: Fallback-Hinweis bei Frame-Blockierung ────────
   Zeigt dezenten Hinweis + Link oberhalb des iframe, falls der
   Browser das iframe aufgrund von X-Frame-Options blockiert (PROD).
   target="_blank" + rel="noopener" ist Pflicht (Tabnabbing-Schutz).
*/
.pdf-preview-fallback-hint {
  font-size: .85rem;
  color: var(--text-secondary);
  margin-bottom: .5rem;
  padding: .5rem .75rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
}
.pdf-preview-fallback-hint a {
  color: var(--accent);
  font-weight: 500;
}

/* ── Skeleton-Liste (vertikale Aneinanderreihung) ────────────────
   Ersetzt style="display:flex;flex-direction:column;gap:.75rem;margin-top:.5rem"
   in _renderSkeleton() beider Pages.
*/
.invoice-skeleton-list {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  margin-top: .5rem;
}

/* ── Skeleton-Bar Variante: Tabellen-Zeilenhöhe ─────────────────
   Ersetzt style="height:42px;border-radius:var(--radius-md)" auf
   .skeleton-bar-Elementen innerhalb .invoice-skeleton-list.
*/
.invoice-skeleton-list .skeleton-bar {
  height: 42px;
  border-radius: var(--radius-md);
}

/* ── Empty State für Listen-Pages (offers + invoices) ───────────
   Ersetzt style="text-align:center;padding:3rem 1rem;color:var(--text-tertiary)"
   auf dem leeren-Zustand-Wrapper. Erweitert .empty-state.
*/
.invoice-list-empty {
  text-align: center;
  padding: 3rem 1rem;
  color: var(--text-tertiary);
}
/* Nur die direkte Illustration blassen/zentrieren — NICHT das Plus-Icon im
   "Erstes X erstellen"-Button (das ist in .btn verschachtelt, kein Kind von
   .invoice-list-empty selbst). Descendant-Selektor traf vorher beide. */
.invoice-list-empty > svg { opacity: .35; margin-bottom: 1rem; display: block; margin-inline: auto; }
.invoice-list-empty p   { margin: .5rem 0; }
.invoice-list-empty .btn { margin-top: .75rem; }

/* ── Invoicing: Anhänge (Session E) ─────────────────────────────
   Anhänge-Liste + Upload-Trigger im Angebots-/Rechnungs-Editor.
   Verwendet im ds-fieldset-Block unter den Positionen.
*/
.invoicing-attachments-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .375rem;
}
.invoicing-attachment-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem .5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  min-width: 0;
}
.invoicing-attachment-icon {
  color: var(--text-tertiary);
  flex-shrink: 0;
  display: flex;
  align-items: center;
}
.invoicing-attachment-name {
  flex: 1;
  min-width: 0;
  color: var(--accent);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .875rem;
}
.invoicing-attachment-name:hover { text-decoration: underline; }
.invoicing-attachment-size {
  color: var(--text-tertiary);
  font-size: .8rem;
  flex-shrink: 0;
}
.invoicing-attachment-upload {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .5rem .75rem;
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--text-secondary);
  font-size: .875rem;
  margin-top: .5rem;
  transition: background var(--transition);
}
.invoicing-attachment-upload:hover {
  background: var(--bg-secondary);
}
@media (max-width: 600px) {
  .invoicing-attachment-row {
    flex-wrap: wrap;
    gap: .375rem;
  }
  .invoicing-attachment-name {
    flex-basis: 100%;
    max-width: 100%;
  }
}

/* ── PLZ-Eingabefeld Breite ──────────────────────────────────────
   Ersetzt style="max-width:6rem" auf dem PLZ-Input in settings-invoicing.js.
*/
.input--zip { max-width: 6rem; }

/* ── Avatar-Initialen für Angebote/Rechnungen ───────────────────
   Ersetzt style="background:...;color:...;font-weight:700;font-size:.75rem"
   auf .avatar.avatar-sm in den Mobile-Listen. .avatar.avatar-sm deckt
   bereits background, color, font-size ab (components.css L418+430).
   Nur font-weight:700 (vs 600) ist ein Deltas — wird hier normalisiert.
*/
.avatar--initials { font-weight: 700; }

/* ── Panel-Dialog: Send + MarkPaid Aktionszeile ─────────────────
   .invoicing-form-actions + .invoicing-form-actions__save existieren bereits
   (L11024). Keine neuen Klassen nötig — nur Dokumentation hier.
*/

/* ── Invoicing: Template Picker (Spec 3400, Schritt 6) ─────────────────────── */
/* 3-Karten-Grid für Theme-Auswahl in settings-invoicing.js */
.ds-template-picker {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: .75rem;
  margin-top: .25rem;
}
@media (max-width: 900px) {
  .ds-template-picker {
    grid-template-columns: 1fr;
  }
}

.ds-template-card {
  position: relative;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-md);
  padding: .75rem;
  cursor: pointer;
  background: var(--bg-primary);
  transition: border-color var(--transition), box-shadow var(--transition), background var(--transition);
  user-select: none;
  display: flex;
  flex-direction: column;
  gap: .4rem;
}
.ds-template-card:hover {
  border-color: var(--accent);
  background: var(--accent-light);
}
.ds-template-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.ds-template-card.is-active {
  border-color: var(--accent);
  background: var(--accent-light);
  box-shadow: 0 0 0 2px var(--accent-light);
}

/* Häkchen oben rechts bei aktiver Karte */
.ds-template-card-check {
  position: absolute;
  top: .5rem;
  right: .5rem;
  width: 1.25rem;
  height: 1.25rem;
  background: var(--accent);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* SVG-Vorschau-Grafik */
.ds-template-card-preview {
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  color: var(--text-primary);
}
.ds-template-card-svg {
  width: 100%;
  height: 100%;
}

/* Theme-Name */
.ds-template-card-name {
  font-weight: 600;
  font-size: .9rem;
  color: var(--text-primary);
}

/* Kurz-Beschreibung: Meta-Tags (Standardwerte) */
.ds-template-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem;
  font-size: .72rem;
  color: var(--text-tertiary);
}
.ds-template-card-meta span {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .1rem .35rem;
}
.ds-template-card.is-active .ds-template-card-meta span {
  background: var(--bg-primary);
}

/* ── Invoicing: Editor als Vollseite (Session D, Spec 20260514) ─────────────── */
.invoicing-editor-page {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 0;
}
.invoicing-editor-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.invoicing-editor-actions {
  display: flex;
  gap: .5rem;
  align-items: center;
  flex-wrap: wrap;
}
/* Mobile: Toolbar-Wrap + Sticky-Footer-Save */
@media (max-width: 900px) {
  .invoicing-editor-page .ds-panel-toolbar {
    flex-wrap: wrap;
    row-gap: .375rem;
  }
  /* Docking-Fix (User-Feedback: Leiste schwebt mit Spalt ueber der Bottom-Nav
     + nicht volle Breite). Root-Cause verifiziert: ds-bottom-nav ist KEIN
     position:fixed — sie ist ein normaler Flex-Sibling von .ds-content-body
     im Fluss (nav.css „Kein extra padding-bottom nötig – ds-bottom-nav sitzt
     im normalen Flow"). Der Spalt kommt stattdessen vom eigenen Padding des
     naechsten Scroll-Containers (.ds-content-body: 1rem ≤900px / .75rem
     ≤600px, nav.css) — sticky respektiert dieses Padding als Stuck-Grenze,
     auch durch die padding-lose Zwischen-Div .invoicing-editor-page hindurch.
     `bottom` negativ hebt genau dieses Container-Padding auf; padding-bottom
     haelt den sichtbaren Innenabstand + Safe-Area. .ds-content-body hat
     overflow-y:auto (haerter Clip) → dieser Ausgleich kann die Leiste nie
     ueber den wahren Rand hinaus schieben, nur bis dorthin. */
  .invoicing-editor-page .form-footer {
    position: sticky;
    bottom: -1rem;
    background: var(--bg-primary);
    border-top: 1px solid var(--border);
    padding: .75rem 1rem;
    z-index: 5;
    /* Full-Bleed: .ds-content-body hat horizontales Padding (1rem/.75rem) —
       ausbrechen fuer volle Breite, ueber vw statt fester Prozent-Rechnung
       (Container-Werte hier unbekannt). .ds-content-body ist auf Mobile
       (Rail ausgeblendet) selbst 100vw breit — ihr overflow-x:hidden clippt
       hier nichts, da kein Ueberstand ueber den Container hinaus entsteht. */
    width: 100vw;
    margin-left: 50%;
    transform: translateX(-50%);
    /* Mobile-Geräte: Safe-Area für iPhone-Notch berücksichtigen */
    padding-bottom: calc(.75rem + env(safe-area-inset-bottom, 0px));
  }
}

/* .ds-content-body verengt sein Padding auf .75rem ab ≤600px (nav.css) —
   Docking-Ausgleich nachziehen (s. Begruendung oben). */
@media (max-width: 600px) {
  .invoicing-editor-page .form-footer { bottom: -0.75rem; }
}

/* Desktop (>900px): Footer klebt am unteren Rand des Scroll-Containers, aber
   NUR sobald der Editor-Kopf (.invoicing-edit-header) den sichtbaren Bereich
   verlassen hat — Gate ueber die Klasse .is-footer-stuck auf .invoicing-editor-
   page, gesetzt von einem IntersectionObserver auf .invoicing-edit-header
   (Wurzel .ds-content-body), s. _syncFooterStickyObserver() in invoices.js /
   offers.js / order-confirmations.js. Solange der Kopf sichtbar ist, bleibt
   die Leiste im normalen Fluss am Kartenende. Docking-Mechanik unveraendert
   zum Mobile-Sticky-Block oben (position:sticky respektiert das Padding von
   .ds-content-body als Stuck-Grenze; negativer bottom-Offset gleicht genau
   dieses Desktop-Padding aus: 1.5rem, nav.css `.ds-content-body { padding:
   1.5rem }`). User-Wunsch 2026-07-23, Nachbesserung zu v2026.07.23.08.
   Full-Bleed innerhalb des Inhaltsbereichs (NICHT ueber die volle Bildschirm-
   breite wie im Mobile-Block — das liefe unter der Sidebar durch): margin
   hebt exakt das horizontale Padding von .ds-content-body auf (1.5rem, im
   Browser gemessen 2026-07-23: .ds-content-body padding-left/right=24px,
   .invoicing-editor-page/.form-footer reichten vorher nur bis an die Padding-
   Kante — die Leiste wird jetzt bis an die tatsaechliche Container-Kante
   ausgebrochen). Innen-Padding der Leiste (padding:1rem 1.5rem, _core.css)
   bleibt, damit die Buttons nicht am Rand kleben. */
@media (min-width: 901px) {
  .invoicing-editor-page.is-footer-stuck .form-footer {
    position: sticky;
    bottom: -1.5rem;
    background: var(--bg-primary);
    border-top: 1px solid var(--border);
    z-index: 5;
    margin-left: -1.5rem;
    margin-right: -1.5rem;
  }
}

/* Issue 2+6: Footer-Flex-Layout — alle Buttons rechtsbuendig, gleiche Hoehe */
.invoicing-form-footer {
  display: flex;
  justify-content: flex-end;
  align-items: stretch;
  gap: .5rem;
}
.invoicing-form-footer .btn,
.invoicing-form-footer .invoicing-split-btn {
  min-height: 38px;
}

/* P3: Split-Button (Speichern + Chevron-Dropdown) */
.invoicing-split-btn {
  display: inline-flex;
  align-items: stretch;
}
.invoicing-split-btn-main {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
}
.invoicing-split-btn.has-menu .invoicing-split-btn-main {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-right: 1px solid rgba(255, 255, 255, .25);
}
.invoicing-split-btn-chevron {
  padding: 0 .5rem;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
/* Chevron-Button bleibt aktiviert auch im read-only-Modus (Menü immer verfügbar) */
.invoicing-split-btn-chevron:disabled {
  opacity: 1;
  pointer-events: auto;
  cursor: pointer;
}

/* P3: Edit-Page-Header (Breadcrumb links, Split-Button rechts) */
.invoicing-edit-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: .75rem;
  flex-wrap: wrap;
}
.invoicing-edit-header-actions {
  flex-shrink: 0;
  display: flex;
  align-items: stretch;
  gap: .5rem;
}
/* Alle Buttons im Header-Actions haben gleiche Hoehe */
.invoicing-edit-header-actions .btn,
.invoicing-edit-header-actions .invoicing-split-btn {
  min-height: 38px;
}

/* ── Read-Only-Dokument-Layout (Post-Finalize, PDF-aehnliche Ansicht) ───────── */
/* Doc-View ist ein transparenter Wrapper — das Iframe-HTML rendert die A4-Seite
   weiss + zentriert (via injectScreenPreviewCss im Controller). */
.invoicing-doc-view {
  background: transparent;
  border: none;
  border-radius: 0;
  margin: 0 0 1.5rem;
  position: relative;
  width: 100%;
  align-self: stretch;
}
.invoicing-doc-iframe {
  width: 100%;
  min-width: 100%;
  height: 1400px;
  min-height: 1200px;
  border: none;
  display: block;
  background: #fff;
}
@media (max-width: 900px) {
  /* PDF-Vorschau + Status-Banner auf Mobile ausblenden — Iframe unbrauchbar,
     Status steht ohnehin in der Sidebar. Dokument bleibt über „Dokumente" abrufbar. */
  .invoicing-doc-iframe,
  .invoicing-doc-preview-wrap,
  .invoicing-doc-status-banner { display: none; }
  /* Linke Spalte komplett ausblenden — enthält nur Iframe + Banner (beide hidden).
     Damit entfällt der grid-gap-Abstand zwischen Breadcrumb und den Sidebar-Cards. */
  .invoicing-doc-layout-main { display: none; }
}

/* Migrierte/importierte Dokumente: generierte Inline-Vorschau ist nur Platzhalter
   (echtes Dokument liegt als PDF unter „Dokumente"). Daher blurren + Hinweis-Label. */
.invoicing-doc-preview-wrap { position: relative; }
.invoicing-doc-iframe.is-blurred {
  filter: blur(5px);
  pointer-events: none;
  user-select: none;
}
.invoicing-doc-preview-blur-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 4rem 1rem;
  pointer-events: none;
}
.invoicing-doc-preview-blur-label {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 0.875rem 1.25rem;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--text-secondary);
  text-align: center;
  max-width: 90%;
}
/* Inline-Toolbar zwischen Versionsbanner und Doc-View — Projekte + Anhaenge gebuendelt */
.invoicing-doc-meta-toolbar {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .625rem .875rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-bottom: 1rem;
}
.invoicing-doc-meta-toolbar-section {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}
.invoicing-doc-meta-toolbar-label {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  font-weight: 600;
}
@media (max-width: 768px) {
  .invoicing-doc-view { padding: 1.5rem 1.25rem; }
}
/* Status-Banner overlay auf der weissen A4-Card — die Card sitzt horizontal
   centered (max-width:24cm), daher Banner via calc auf die linke Card-Kante. */
.invoicing-doc-status-banner {
  position: absolute;
  top: 1.75rem;
  left: max(0px, calc(50% - 12cm));
  background: var(--accent);
  color: #fff;
  padding: .625rem 1.25rem;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  box-shadow: 0 2px 6px rgba(0,0,0,.15);
  z-index: 2;
}
.invoicing-doc-status-banner-title {
  font-size: 1rem;
  font-weight: 600;
  display: block;
}
.invoicing-doc-status-banner-sub {
  font-size: .75rem;
  opacity: .9;
  display: block;
  margin-top: .125rem;
}
.invoicing-doc-status-banner--success { background: var(--teal); }
.invoicing-doc-status-banner--warning { background: var(--amber); }
.invoicing-doc-status-banner--danger  { background: var(--coral); }

.invoicing-doc-header {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2rem;
  align-items: flex-start;
  margin-bottom: 2rem;
  padding-top: 3.5rem;
}
.invoicing-doc-anschrift-label,
.invoicing-doc-meta-label {
  font-size: .75rem;
  color: var(--text-tertiary);
  margin-bottom: .25rem;
}
.invoicing-doc-anschrift-company {
  font-size: 1rem;
  font-weight: 600;
  color: var(--accent);
}
.invoicing-doc-anschrift-line {
  font-size: .9rem;
  line-height: 1.5;
}
.invoicing-doc-title {
  font-size: 2.25rem;
  font-weight: 400;
  color: var(--text-primary);
  text-align: right;
  margin: 0;
}

.invoicing-doc-metabar {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr auto;
  gap: 1.5rem;
  padding: 1rem 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  margin-bottom: 1.5rem;
}
.invoicing-doc-meta-value {
  font-size: .95rem;
  font-weight: 600;
}
.invoicing-doc-meta-value--accent { color: var(--accent); }
.invoicing-doc-metabar > div:last-child { text-align: right; }

.invoicing-doc-intro {
  margin-bottom: 1.5rem;
  font-size: .95rem;
  line-height: 1.6;
}

.invoicing-doc-items {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 1.5rem;
}
.invoicing-doc-items thead th {
  background: var(--bg-secondary);
  color: var(--text-tertiary);
  font-weight: 500;
  font-size: .8125rem;
  padding: .75rem .5rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
}
.invoicing-doc-items thead th.right { text-align: right; }
.invoicing-doc-items tbody td {
  padding: 1rem .5rem;
  vertical-align: top;
  border-bottom: 1px solid var(--border);
  font-size: .9rem;
}
.invoicing-doc-items tbody td.right    { text-align: right; tab-numeric: tabular-nums; font-variant-numeric: tabular-nums; }
.invoicing-doc-items tbody td.num      { text-align: right; width: 2.5rem; color: var(--text-tertiary); }
.invoicing-doc-items-title {
  font-weight: 600;
  margin-bottom: .25rem;
}
.invoicing-doc-items-desc {
  font-size: .8125rem;
  color: var(--text-secondary);
  white-space: pre-wrap;
}
.invoicing-doc-items tbody tr.is-section td {
  background: var(--bg-secondary);
  font-weight: 600;
  padding: .625rem .5rem;
}

.invoicing-doc-totals {
  margin-left: auto;
  width: clamp(280px, 50%, 380px);
  margin-bottom: 1.5rem;
}
.invoicing-doc-totals-row {
  display: flex;
  justify-content: space-between;
  padding: .4rem 0;
  font-size: .9rem;
}
.invoicing-doc-totals-row--gross {
  border-top: 2px solid var(--text-primary);
  margin-top: .25rem;
  padding-top: .6rem;
  font-size: 1rem;
  font-weight: 700;
}

.invoicing-doc-footer {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
  font-size: .875rem;
  line-height: 1.55;
  color: var(--text-secondary);
  white-space: pre-wrap;
}
/* Mobile (≤900px): Top-Header-Actions ausblenden — Sticky-Footer übernimmt */
@media (max-width: 900px) {
  page-offers .invoicing-edit-header-actions,
  page-invoices .invoicing-edit-header-actions {
    display: none;
  }
}
/* Issue 8: Texte 50/50 Grid (Einleitung + Fußzeile nebeneinander) */
.invoicing-texts-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
@media (max-width: 900px) {
  .invoicing-texts-grid {
    grid-template-columns: 1fr;
  }
}

/* Breadcrumb Mobile: Ellipsis bei langen Pfaden */
@media (max-width: 600px) {
  .breadcrumb {
    flex-wrap: nowrap;
    overflow: hidden;
  }
  .breadcrumb-item,
  .breadcrumb-current {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 40vw;
  }
  .breadcrumb-item:first-child {
    flex-shrink: 0;
  }
}

/* ── Invoicing: Version-History-Banner (Edit-Storno, GoBD-Audit-Trail) ── */
/* Erscheint über dem Kopfdaten-Formular wenn das Dokument Teil einer Version-Chain ist */
.invoicing-version-banner {
  background: var(--accent-light);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: .75rem 1rem;
  margin-bottom: 1rem;
  font-size: .875rem;
  color: var(--text-primary);
}
.invoicing-version-banner-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  line-height: 1.4;
}
.invoicing-version-banner-row + .invoicing-version-banner-row {
  margin-top: .5rem;
}
.invoicing-version-banner-row--warning {
  color: var(--amber);
}
/* Storno-Variante: coral-Tonung (Credit-Note-Banner) */
.invoicing-version-banner-row--storno {
  color: var(--coral);
}
/* Link-Button im Banner: kein eigenes Button-Styling, nur Text + Underline */
.invoicing-version-banner .link-button {
  background: none;
  border: none;
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline;
  font-size: inherit;
  padding: 0;
  line-height: inherit;
}
.invoicing-version-banner-row--warning .link-button {
  color: var(--amber);
}
.invoicing-version-banner-row--storno .link-button {
  color: var(--coral);
}
.invoicing-version-banner .link-button:hover {
  opacity: .8;
}

/* ── Bug 2: Download-Icons in Listen-Tabelle (invoices + offers) ── */
/* Neue Klasse: .invoice-list-files — td mit Download-Aktionen rechts */
/* Neue Klasse: .invoice-list-files-th — header der files-Spalte (schmal, kein Padding) */
/* Neue Klasse: .invoice-list-pdf-mobile — PDF-Icon in Mobile native-row */
.invoice-list-files {
  display: flex;
  align-items: center;
  gap: .125rem;
  white-space: nowrap;
  padding-inline: .375rem;
}
.invoice-list-files-th {
  width: 2.5rem;
  padding-inline: .375rem;
}
.invoice-list-files .btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: .25rem;
  color: var(--text-tertiary);
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
}
.invoice-list-files .btn-icon:hover {
  color: var(--accent);
  background: var(--accent-light);
}
/* P6: SVG innerhalb List-PDF-Buttons immer block + fixe Größe */
.invoice-list-files .btn-icon svg,
.invoice-list-pdf-mobile svg {
  display: block;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}
/* Mobile-Icon in native-row-right — marginTop so Abstand zum Badge stimmt */
.invoice-list-pdf-mobile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: .25rem;
  color: var(--text-tertiary);
  margin-top: .125rem;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
}
.invoice-list-pdf-mobile:hover {
  color: var(--accent);
  background: var(--accent-light);
}

/* ── Bug 3: Versions-Chain im Version-Banner (invoices + offers) ── */
/* Neue Klasse: .invoicing-version-chain — Horizontale Liste aller Versionen */
/* Neue Klasse: .invoicing-version-chain-item — Einzelner Versions-Eintrag */
/* Neue Klasse: .badge-tiny — Kleines Badge (z.B. Status neben Version-Link) */
.invoicing-version-chain {
  list-style: none;
  padding: 0;
  margin: .375rem 0 0;
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  align-items: center;
}
.invoicing-version-chain-item {
  display: flex;
  align-items: center;
  gap: .25rem;
  font-size: .8125rem;
}
.invoicing-version-chain-item.is-current .link-button {
  font-weight: 700;
  color: var(--text-primary);
  cursor: default;
  text-decoration: none;
}
.invoicing-version-chain-item.is-current .link-button:hover {
  opacity: 1;
}
/* Separator zwischen Versions-Items */
.invoicing-version-chain-item + .invoicing-version-chain-item::before {
  content: '›';
  color: var(--text-tertiary);
  font-size: .75rem;
  margin-right: .25rem;
  pointer-events: none;
}
.badge-tiny {
  font-size: .625rem;
  padding: 0 .3rem;
  line-height: 1.4;
  border-radius: 999px;
}

/* ── ds-toolbar-item--success (Angenommen-Button, teal — analog --danger) ── */
.ds-toolbar-item--success {
  color: var(--teal);
  border-color: var(--teal-light);
}
.ds-toolbar-item--success:hover {
  background: var(--teal-light);
  color: var(--teal);
}

/* ── Invoicing: Payments-Section ─────────────────────────────── */
.invoicing-payments-list {
  list-style: none;
  padding: 0;
  margin: 0 0 .75rem;
}
.invoicing-payments-row {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  gap: .5rem;
  align-items: center;
  padding: .5rem .25rem;
  border-bottom: 1px solid var(--border);
  font-size: .875rem;
  min-width: 0;
}
.invoicing-payments-row:last-child {
  border-bottom: none;
}
.invoicing-payments-amount {
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--text-primary);
}
.invoicing-payments-method {
  font-size: .8125rem;
  color: var(--text-secondary);
  text-align: center;
}
.invoicing-payments-notes {
  font-size: .8125rem;
  color: var(--text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.invoicing-payments-summary {
  margin-top: .75rem;
  padding-top: .75rem;
  border-top: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  gap: .5rem .75rem;
  align-items: center;
  font-size: .875rem;
}
.invoicing-payments-empty {
  color: var(--text-tertiary);
  font-size: .875rem;
  margin: .25rem 0 .75rem;
}
/* Ticket 3.341.2: bank-erzeugte Zahlung -- Herkunfts-Icon statt Papierkorb
   (weggelassen statt ausgegraut, s. modules/invoicing.md „Zahlungsweg (Rechnung)"-
   Nachbarabschnitt fuer dasselbe Prinzip bei der Kategorien-Verwaltung: das
   Symbol widerspricht nie dem Text) + volle Herkunfts-Zeile unter der Reihe. */
.invoicing-payments-source {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  color: var(--text-tertiary);
}
.invoicing-payments-origin {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: .5rem;
  row-gap: .125rem;
  margin-top: -.125rem;
  padding-left: 3.25rem;
  font-size: .75rem;
  line-height: 1.4;
}
.invoicing-payments-origin-label {
  color: var(--text-tertiary);
}
.invoicing-payments-origin-link {
  padding: 0;
  border: none;
  background: none;
  color: var(--accent);
  font-size: .75rem;
  text-decoration: underline;
  cursor: pointer;
}
.invoicing-payments-origin-link:hover {
  color: var(--accent-dark);
}
@media (max-width: 600px) {
  .invoicing-payments-origin {
    padding-left: 0;
  }

  .invoicing-payments-row {
    grid-template-columns: 1fr auto auto;
    row-gap: .125rem;
  }
  .invoicing-payments-method {
    text-align: left;
    font-size: .75rem;
  }
  .invoicing-payments-amount {
    text-align: right;
  }
}

/* ── Invoicing: Payments 3-Block Layout ───────────────────── */
.invoicing-payments-total {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: .5rem .25rem .5rem;
  font-weight: 600;
  font-size: .9375rem;
  border-bottom: 2px solid var(--border);
  margin-bottom: .25rem;
}
.invoicing-payments-balance {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .625rem .25rem .25rem;
  border-top: 2px solid var(--border);
  margin-top: .25rem;
}
.invoicing-payments-balance--paid {
  color: var(--teal);
}
.invoicing-payments-balance--open {
  color: var(--amber);
}
/* Block-3 Footer via invoicing-payments-total: border-top statt border-bottom, Farb-Modifier */
.invoicing-payments-total.invoicing-payments-balance--paid {
  border-bottom: none;
  border-top: 2px solid var(--border);
  margin-top: .25rem;
  margin-bottom: 0;
  color: var(--teal);
}
.invoicing-payments-total.invoicing-payments-balance--open {
  border-bottom: none;
  border-top: 2px solid var(--border);
  margin-top: .25rem;
  margin-bottom: 0;
  color: var(--amber);
}
.invoicing-payments-balance-amount {
  flex: 1;
  font-size: .875rem;
}
.invoicing-payments-balance-add {
  margin-left: auto;
  flex-shrink: 0;
}
.invoicing-payments-fieldset {
  margin-top: 1.25rem;
}

/* ── Invoicing: QR-Code Position-Picker ───────────────────── */

.qr-position-grid {
  display: grid;
  grid-template-columns: repeat(2, 72px);
  gap: .375rem;
  margin-top: .375rem;
}

.qr-position-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .25rem;
  width: 72px;
  padding: .375rem .25rem .3rem;
  background: var(--bg-primary);
  border: 2px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-tertiary);
  cursor: pointer;
  transition: border-color var(--transition), color var(--transition), background var(--transition);
}

.qr-position-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--bg-secondary);
}

.qr-position-btn.is-active {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-light);
}

.qr-position-label {
  font-size: .6875rem;
  line-height: 1.2;
  text-align: center;
  color: inherit;
  pointer-events: none;
}

/* ── Finalize-Validation-Modal ────────────────────────────── */
.finalize-validation-modal {
  padding: .5rem 0;
}
.finalize-validation-header {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-bottom: 1rem;
  color: var(--amber);
}
.finalize-validation-header h3 {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text-primary);
}
.finalize-validation-intro {
  color: var(--text-secondary);
  margin: 0 0 .75rem;
  font-size: .9rem;
}
.finalize-validation-list {
  margin: 0 0 1rem;
  padding-left: 1.25rem;
  list-style: disc;
  font-size: .875rem;
  line-height: 1.6;
  color: var(--text-primary);
}
.finalize-validation-list li {
  margin-bottom: .25rem;
}
.finalize-validation-list strong {
  color: var(--text-primary);
}
.finalize-validation-hint {
  margin: 0;
  padding: .625rem .75rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  font-size: .8rem;
  color: var(--text-tertiary);
  border-left: 3px solid var(--amber);
}


/* ── Invoicing: Projekt-Zuordnung (P5) ──────────────────────── */
.invoicing-project-picker {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
  align-items: center;
}
.invoicing-project-chip {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .25rem .5rem;
  border: 1.5px solid var(--border);
  border-radius: 999px;
  background: var(--bg-secondary);
  font-size: .8rem;
  color: var(--text-primary);
}
.invoicing-project-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.invoicing-project-chip-remove {
  border: none;
  background: transparent;
  cursor: pointer;
  font-size: .9rem;
  line-height: 1;
  padding: 0 .15rem;
  color: var(--text-tertiary);
}
.invoicing-project-chip-remove:hover {
  color: var(--coral);
}
.invoicing-project-add {
  font-size: .8rem;
  min-width: 12rem;
}

/* ── Invoicing: Kommentare-Sektion (B7, 2026-05-17) ──────────────────────── */
.invoicing-comments-list {
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.invoicing-comment-card {
  padding: .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
}
.invoicing-comment-header {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: .375rem;
  font-size: .875rem;
}
.invoicing-comment-time {
  color: var(--text-tertiary);
  font-size: .75rem;
  flex: 1;
}
.invoicing-comment-body {
  font-size: .875rem;
  color: var(--text-primary);
  line-height: 1.5;
  white-space: pre-wrap;
}

/* ── Mail-Compose-Panel (Invoicing Send-Dialog) ──────────────────────────── */
.ds-mail-compose { display: flex; flex-direction: column; gap: 1rem; }
.ds-mail-compose-sender {
  padding: .5rem .75rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: .875rem;
  color: var(--text-secondary);
  user-select: text;
}
.ds-mail-compose-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .5rem;
  margin-top: 1rem;
  padding-top: .75rem;
  border-top: 1px solid var(--border);
}
.ds-mail-compose-editor { display: block; min-height: 240px; }
.ds-mail-compose-editor .ql-editor { min-height: 220px; }
.ds-mail-compose-attachments {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .375rem;
}
.ds-mail-compose-attachment {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  font-size: .875rem;
}
.ds-mail-compose-attachment label {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  cursor: pointer;
  flex: 1;
  min-width: 0;
}
.ds-mail-compose-attachment-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-mail-compose-attachment input[type="checkbox"] {
  accent-color: var(--accent);
  flex-shrink: 0;
}

/* ── Move-Profile-Panel (B59, Spec 20260802_invoicing_profile_move_and_inline_timetracking.md)
   Vertikaler Form-Stack — Werte identisch zu .ds-mail-compose (kein neuer Wert,
   nur ein semantisch treffender Name statt des Mail-Compose-Kontexts). ──────── */
.ds-move-profile-panel { display: flex; flex-direction: column; gap: 1rem; }

/* ── Empfaenger-Zeilen + Cc/Bcc-Aufklapp-Links (geteiltes Sende-Panel,
   Backlog B41, Spec 20260728_document_send_recipients.md, Runde R3) ──────── */
.doc-send-recipient-row .form-label { margin-bottom: .25rem; }
.doc-send-cc-bcc-toggles {
  display: flex;
  gap: .75rem;
  margin: -.25rem 0 .75rem 0;
}
.doc-send-toggle-link {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  font-size: .8125rem;
  cursor: pointer;
  text-decoration: underline;
}
.doc-send-toggle-link:hover { color: var(--accent-dark); }

/* ── Wiedervorlage-Vorschlag im Sende-Panel (Ticket 3.360.2) ─────────────────
   `.builder-toggle-row` ist die generische Toggle-Zeile aus _core.css — hier nur
   der Bottom-Margin auf 0 gesetzt, weil der umgebende Flex (.ds-mail-compose)
   den Row-Rhythmus bereits per gap:1rem herstellt; ein zusaetzlicher 1.5rem-
   Abstand darunter waere doppelt so gross wie jeder andere Panel-Abschnitt. ── */
.doc-send-followup-block { display: flex; flex-direction: column; gap: .625rem; }
.doc-send-followup-block .builder-toggle-row { margin-bottom: 0; }
.doc-send-followup-date-row .form-label { margin-bottom: .25rem; }

/* ── Variable-Chips (Klick fuegt Platzhalter im Editor ein) ──────────────── */
.ds-var-chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
  margin-top: .5rem;
}
.ds-var-chip {
  display: inline-flex;
  align-items: center;
  padding: .25rem .5rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--accent);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  cursor: pointer;
  transition: var(--transition);
  white-space: nowrap;
}
.ds-var-chip:hover {
  background: var(--accent-light);
  border-color: var(--accent);
}
.ds-var-chip:active {
  transform: scale(0.97);
}

/* ── Invoicing/Offers 2-Spalten-Layout (Post-Finalize Mini-Dashboard) ─────── */
.invoicing-doc-layout {
  display: grid;
  grid-template-columns: 1fr 360px;
  gap: 1.25rem;
  align-items: start;
}
.invoicing-doc-layout-main {
  min-width: 0; /* verhindert iframe overflow in grid */
}
.invoicing-doc-layout-sidebar {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  position: sticky;
  top: 1rem;
  min-width: 0;
}
.invoicing-doc-layout-sidebar .ds-fieldset {
  margin: 0;
}
@media (max-width: 1100px) {
  .invoicing-doc-layout { grid-template-columns: 1fr; }
  .invoicing-doc-layout-sidebar { position: static; }
}

.invoicing-sidebar-meta-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: .5rem;
  font-size: .875rem;
}
.invoicing-sidebar-meta-grid > div {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .5rem;
  min-width: 0; /* erlaubt Ellipsis auf flex-Kindern */
}

/* Ellipsis-Hilfskasse für lange Werte (z.B. Firmenname) in Sidebar-Meta-Grid */
.invoicing-sidebar-ellipsis {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.invoicing-sidebar-meta-label {
  color: var(--text-tertiary);
  font-size: .8125rem;
}
/* B61: Bestellnummer-Wert in der Status-Sidebar — Referenz-Werte koennen lang sein
   (keine natuerlichen Umbruchstellen wie bei Namen), daher word-break statt Ellipsis. */
.invoicing-sidebar-meta-value--ref {
  word-break: break-all;
  font-size: .8125rem;
}
.invoicing-sidebar-attachments {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
.invoicing-sidebar-attachment {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem .5rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
}
.invoicing-sidebar-attachment-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Quick-Actions in Editor-Header (z.B. „Zahlung erfassen" prominent) */
.invoicing-quick-actions {
  display: inline-flex;
  gap: .5rem;
}

/* ── Invoicing Sidebar Polish (Session 1, 2026-05-19) ──────────────────── */

/* Fieldset mit optionalem Icon links neben der Legend */
.invoicing-sidebar-fieldset {
  margin-bottom: .875rem;
  min-width: 0;
}
.invoicing-sidebar-fieldset .ds-fieldset-legend {
  display: flex;
  align-items: center;
  gap: .375rem;
}
.invoicing-sidebar-fieldset-icon {
  display: inline-flex;
  flex-shrink: 0;
  color: var(--text-tertiary);
}

/* Dokumente-Liste (Fieldset 3) */
.invoicing-doc-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
.invoicing-doc-list-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem .5rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
  text-decoration: none;
  color: var(--text-primary);
  transition: background var(--transition);
}
.invoicing-doc-list-item:hover {
  background: var(--accent-light);
}
.invoicing-doc-list-item-icon {
  display: inline-flex;
  flex-shrink: 0;
  color: var(--text-tertiary);
}
.invoicing-doc-list-item-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.invoicing-doc-list-item-size {
  flex-shrink: 0;
  color: var(--text-tertiary);
  font-size: .75rem;
  margin-left: .25rem;
}
.invoicing-doc-list-sep {
  height: 1px;
  background: var(--border);
  margin: .25rem 0;
}
.invoicing-doc-list-zip {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem .5rem;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
  color: var(--text-secondary);
  cursor: pointer;
  width: 100%;
  text-align: left;
  transition: background var(--transition), color var(--transition);
}
.invoicing-doc-list-zip:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}

/* Dokument-Liste: volle Zeile als klickbarer Button (BUG 4, 2026-05-19) */
.invoicing-doc-list-button {
  display: flex;
  align-items: center;
  gap: .375rem;
  width: 100%;
  padding: .375rem .375rem;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-align: left;
  font-size: .8125rem;
  color: var(--text-primary);
  transition: background var(--transition), color var(--transition);
  min-height: 32px;
  min-width: 0;
}
.invoicing-doc-list-button:hover {
  background: var(--bg-secondary);
}
.invoicing-doc-list-button-icon {
  flex-shrink: 0;
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
}
.invoicing-doc-list-button-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .8125rem;
}
.invoicing-doc-list-button-size {
  flex-shrink: 0;
  font-size: .75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}
.invoicing-doc-list-button--zip {
  color: var(--accent);
  font-weight: 600;
  margin-top: .125rem;
}
.invoicing-doc-list-button--zip:hover {
  background: var(--accent-light);
}
/* Anhänge zusammenführen (Spec 20260722, Session 3) — Sidebar-Zeile analog --zip:
   beides sind "wirk auf das gesamte Dokument"-Aktionen statt Einzel-Datei-Downloads. */
/* Aktions-Zeile der Dokumente-Karte (wirkt auf das GESAMTE Dokument, im Gegensatz
   zu den Einzel-Datei-Downloads darueber) — gleiche Optik wie --zip. */
.invoicing-doc-list-button--merge {
  color: var(--accent);
  font-weight: 600;
  margin-top: .125rem;
}
.invoicing-doc-list-button--merge:hover {
  background: var(--accent-light);
}

/* „Anhang hochladen" steht ganz unten und ist bewusst NICHT akzentfarben:
   es ist eine Eingabe-Aktion, keine Ausgabe-/Download-Aktion wie die Zeilen
   darueber. Neutraler grauer Button mit Rahmen, damit er sich klar absetzt. */
.invoicing-doc-list-button--upload {
  justify-content: center;
  margin-top: .5rem;
  padding: .4375rem .375rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  font-weight: 500;
}
.invoicing-doc-list-button--upload:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}

/* Dokument-Zeile mit Ansehen-Button (DocPreview-Integration) */
.invoicing-doc-list-row {
  display: flex;
  align-items: stretch;
  gap: 0;
}
/* Download-Button in einer Row: flex:1, kein right-radius */
.invoicing-doc-list-row .invoicing-doc-list-button {
  flex: 1;
  min-width: 0;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
}
/* Ansehen-Icon-Button rechts */
.invoicing-doc-list-view-btn {
  flex-shrink: 0;
  width: 28px;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  border-left: 1px solid var(--border);
  transition: color var(--transition), background var(--transition);
  padding: 0;
}
.invoicing-doc-list-view-btn:hover {
  color: var(--accent);
  background: var(--accent-light);
}
.invoicing-doc-list-view-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* Öffentlicher Link (Fieldset 4) */
.invoicing-public-url-row {
  display: flex;
  gap: .375rem;
  align-items: center;
}
.invoicing-public-url-input {
  flex: 1;
  min-width: 0;
  font-size: .8125rem;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .375rem .5rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: default;
  user-select: all;
}

/* Annahme-Audit (Fieldset 4, nur Angebote) */
.invoicing-accept-audit {
  display: flex;
  flex-direction: column;
  gap: .375rem;
  margin-top: .5rem;
  padding: .5rem .625rem;
  background: var(--teal-light);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
}
.invoicing-accept-audit-row {
  display: flex;
  align-items: flex-start;
  gap: .375rem;
  line-height: 1.4;
}
.invoicing-accept-audit-label {
  color: var(--text-tertiary);
  flex-shrink: 0;
  min-width: 5rem;
}

/* D2: Abstand zwischen Suchleiste und Tabellen-Card in Rechnungs-/Angebots-Listen */
.invoicing-list-gap {
  margin-top: 1rem;
}

:root[data-theme="dark"] .invoicing-accept-audit {
  background: rgba(42, 187, 138, .1);
}

/* ── Variablen-Hilfe (Einleitung + Fußzeile, nur Draft-Modus) ── */
.invoicing-vars-help {
  margin-top: .5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
}
.invoicing-vars-help > summary {
  cursor: pointer;
  padding: .375rem .75rem;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--text-secondary);
  list-style: none;
  display: flex;
  align-items: center;
  gap: .375rem;
  user-select: none;
}
.invoicing-vars-help > summary::-webkit-details-marker { display: none; }
.invoicing-vars-help > summary::before {
  content: '';
  display: inline-block;
  width: .5rem;
  height: .5rem;
  border-right: 1.5px solid var(--text-tertiary);
  border-bottom: 1.5px solid var(--text-tertiary);
  transform: rotate(-45deg);
  flex-shrink: 0;
  transition: transform var(--transition);
}
.invoicing-vars-help[open] > summary::before {
  transform: rotate(45deg);
}
.invoicing-vars-list {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
  padding: .5rem .75rem .75rem;
  border-top: 1px solid var(--border);
}
.invoicing-vars-chip {
  display: inline-flex;
  align-items: center;
  gap: .3125rem;
  padding: .25rem .625rem;
  min-height: 36px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  cursor: pointer;
  font-size: .8125rem;
  transition: border-color var(--transition), background var(--transition);
  white-space: nowrap;
}
.invoicing-vars-chip:hover {
  border-color: var(--accent);
  background: var(--accent-light);
}
.invoicing-vars-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.invoicing-vars-chip-key {
  font-family: ui-monospace, 'SFMono-Regular', Menlo, monospace;
  font-size: .75rem;
  font-weight: 600;
  color: var(--accent);
}
.invoicing-vars-chip-sep {
  color: var(--text-tertiary);
  font-size: .75rem;
}
.invoicing-vars-chip-val {
  color: var(--text-secondary);
  font-size: .75rem;
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.invoicing-vars-chip-empty {
  color: var(--text-tertiary);
  font-style: italic;
  font-size: .75rem;
}
.invoicing-vars-help-count {
  margin-left: auto;
  font-size: .6875rem;
  font-weight: 700;
  color: var(--text-tertiary);
  background: var(--bg-tertiary, var(--bg-primary));
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 .375rem;
  min-width: 1.25rem;
  text-align: center;
}

/* Mobile: Chips nehmen volle Breite wenn sehr klein */
@media (max-width: 480px) {
  .invoicing-vars-list {
    flex-direction: column;
  }
  .invoicing-vars-chip {
    width: 100%;
    min-height: 44px;
    justify-content: flex-start;
  }
}

/* ── Angebots-Import-Panel ──────────────────────────────────────────────── */

.offers-import-panel {
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.offers-import-hint {
  font-size: .875rem;
  color: var(--text-secondary);
  margin: 0;
  line-height: 1.5;
}

.offers-import-hint strong {
  color: var(--text-primary);
}

/* Datei-Upload-Feld */
.offers-import-file-label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  border: 2px dashed var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
  font-size: .875rem;
  color: var(--text-secondary);
  transition: border-color .15s, background .15s;
}

.offers-import-file-label:hover {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
}

.offers-import-filenames {
  font-size: .8125rem;
  color: var(--text-secondary);
  margin: var(--space-2) 0 0;
  line-height: 1.8;
}

/* Vorschau-Zusammenfassung */
.offers-import-summary {
  font-size: .875rem;
  margin: 0 0 var(--space-1);
}

/* Loading-Skeletons */
.offers-import-loading {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* Ergebnis-Block */
.offers-import-result {
  background: var(--teal-light);
  border: 1px solid var(--teal);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  font-size: .875rem;
}

.offers-import-errors {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-4);
  font-size: .8125rem;
  color: var(--coral);
  list-style: disc;
}

/* Dark-Mode: Ergebnis-Block (nur expliziter data-theme="dark"-Toggle) */
:root[data-theme="dark"] .offers-import-result {
  background: color-mix(in srgb, var(--teal) 12%, transparent);
  border-color: var(--teal);
}

/* ── Timesheet-Section Mobile Card-Liste (≤900px) ───────────────────────── */
/* [HIGH] .tt-ts-table ist eine 7-Spalten-Tabelle — auf Mobile als Card-Liste
   per isMobile()-Branch in _renderTimesheetSection (invoices.js) gerendert.
   Diese Klassen decken das Card-Layout ab. */

/* Wrapper für eine Zeile als Card */
.tt-ts-mobile-card {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .625rem .75rem;
  display: flex;
  flex-direction: column;
  gap: .375rem;
}
.tt-ts-mobile-card--alt {
  background: var(--bg-secondary);
}
.tt-ts-mobile-card--readonly {
  opacity: .75;
}

/* Erste Zeile: Datum + Dauer */
.tt-ts-mobile-card-toprow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
}
.tt-ts-mobile-card-date {
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-primary);
}
.tt-ts-mobile-card-dur {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--accent);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Zweite Zeile: Firma/Projekt */
.tt-ts-mobile-card-context {
  font-size: .8125rem;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Dritte Zeile: Zeit-Inputs (Start/Ende) + Aktion */
.tt-ts-mobile-card-timerow {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.tt-ts-mobile-card-timerow .input {
  height: 36px;
  min-height: 36px;
  flex: 1;
  min-width: 0;
  font-size: .8125rem;
}

/* Vierte Zeile: Beschreibung */
.tt-ts-mobile-card-desc .input {
  width: 100%;
  height: 36px;
  min-height: 36px;
  font-size: .8125rem;
}

/* Badge + Aktion-Button-Zeile */
.tt-ts-mobile-card-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .375rem;
  margin-top: .125rem;
}

/* ── Wochen-Zwischensummen-Zeile (Zeitnachweis-Sektion, 2026-07-01) ─────────
   Desktop-<tr> + Mobile-Pendant nach dem letzten Eintrag jeder ISO-Kalenderwoche
   (Montag–Sonntag). Optisch abgesetzt von normalen Zeilen (bg-tertiary + bold),
   aber deutlich schwächer als die finale ".tt-ts-tfoot-*"-Gesamtzeile. */
.tt-ts-week-summary-row td {
  background: var(--bg-tertiary);
  font-weight: 600;
  font-size: .8125rem;
  color: var(--text-secondary);
  padding-top: .375rem;
  padding-bottom: .375rem;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.tt-ts-week-summary-label {
  white-space: nowrap;
}
.tt-ts-week-summary-total {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
  white-space: nowrap;
}

/* Mobile-Pendant: Trenner-Card zwischen Wochen-Blöcken */
.tt-ts-week-summary-mobile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .375rem .75rem;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--text-secondary);
}
.tt-ts-week-summary-mobile-label {
  white-space: nowrap;
}
.tt-ts-week-summary-mobile-total {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
  white-space: nowrap;
}

/* ── Mobile-Card-Listen: Betrag-Spalte nie clippend (P6 Feinschliff) ──────
   Kanonisches native-row-Pattern nutzt .native-row-main als Mitte-Spalte
   (design-system.md A.2), aber _core.css definiert bisher nur die Alias-
   Klassen .native-row-mid/.native-row-center mit flex:1;min-width:0 — die
   tatsaechlich verwendete .native-row-main fehlte dort komplett. Ohne
   min-width:0 kann der Flex-Item nicht unter seine Inhalts-Breite schrumpfen
   (nowrap-Titel/-Sub zaehlen als eigene Min-Breite) → der rechte Betrag wird
   aus dem sichtbaren .native-row (overflow:hidden) herausgedrueckt und
   abgeschnitten. Fix hier statt in _core.css (ausserhalb des Sessions-Scope),
   gilt global ueber components.css (Belege nutzen dieselbe Klasse mit).
   .native-row-amount = eigene, nie schrumpfende Betrags-Spalte. */
.native-row-main {
  flex: 1;
  min-width: 0;
}
.native-row-amount {
  flex-shrink: 0;
  white-space: nowrap;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}

/* ── Anhänge zusammenführen (Gesamt-PDF, Spec 20260722) — Sekundär-Panel ───
   Neue Klassen-Familie statt Reuse von .tt-attach-entry-*: strukturell
   verwandt (Checkbox-Zeile mit Name/Meta), aber fachlich anderes Modul
   (Invoicing-Anhänge statt Time-Tracking-Einträge) + eigene Reorder-Buttons,
   die es im Time-Tracking-Pendant nicht gibt. Genutzt in offers.js +
   invoices.js (_renderMergePanel). */
.ds-merge-list {
  display: flex;
  flex-direction: column;
  gap: .375rem;
  max-height: 50vh;
  overflow-y: auto;
  margin-bottom: .5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .25rem;
}
.ds-merge-row {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .5rem .625rem;
  border-radius: var(--radius-sm);
  transition: background var(--transition);
}
.ds-merge-row:hover {
  background: var(--bg-secondary);
}
.ds-merge-row.is-disabled {
  opacity: .55;
}
.ds-merge-row-check {
  flex-shrink: 0;
  accent-color: var(--accent);
  width: 15px;
  height: 15px;
  cursor: pointer;
}
.ds-merge-row-check:disabled {
  cursor: not-allowed;
}
.ds-merge-row-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.ds-merge-row-name {
  font-size: .8125rem;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-merge-row-meta {
  font-size: .75rem;
  color: var(--text-tertiary);
}
.ds-merge-row-order {
  display: flex;
  flex-direction: column;
  gap: .125rem;
  flex-shrink: 0;
}
.ds-merge-row-order-btn {
  width: 24px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.ds-merge-row-order-btn:hover:not(:disabled) {
  background: var(--accent-light);
  color: var(--accent);
  border-color: var(--accent);
}
.ds-merge-row-order-btn:disabled {
  opacity: .35;
  cursor: not-allowed;
}
@media (max-width: 600px) {
  .ds-merge-row-check,
  .ds-merge-row-order-btn {
    width: 22px;
    height: 22px;
  }
}

/* ── <ds-item-rich-text>: Mini-Rich-Text-Editor fuer Textbloecke + Positions-
   Langbeschreibung (Spec 20260723_invoice_item_rich_text) ─────────────────
   Ersetzt die reinen <textarea class="invoice-item-text|invoice-item-longdesc">
   in invoices.js/offers.js/order-confirmations.js. Wrapper + Toolbar sind
   theme-aware (--bg-secondary/--border wie jede andere Chrome), die eigentliche
   Editier-Flaeche (.ds-item-rich-body) ist bewusst FEST WEISS unabhaengig vom
   App-Theme — gleiches Prinzip wie .pub-doc-iframe (s. "Public-Doc-View" weiter
   oben in dieser Datei/design-system.md): der Inhalt geht 1:1 ins PDF, die feste
   Farbpalette (#222222 etc.) ist auf Papier kalibriert und waere auf dunklem
   App-Hintergrund kaum lesbar. Toolbar-Buttons rendern in currentColor. */
.ds-item-rich {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--bg-primary);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.ds-item-rich:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}
.ds-item-rich-toolbar {
  display: flex;
  align-items: center;
  gap: .125rem;
  padding: .25rem .3125rem;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
}
.ds-item-rich-sep {
  width: 1px;
  align-self: stretch;
  margin: .1875rem .1875rem;
  background: var(--border);
}
.ds-item-rich-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.ds-item-rich-btn:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}
.ds-item-rich-btn.is-active {
  background: var(--accent-light);
  color: var(--accent);
}
.ds-item-rich-color-wrap {
  position: relative;
  display: flex;
}
.ds-item-rich-color-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 50;
  min-width: 8.5rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: .25rem;
  display: flex;
  flex-direction: column;
  gap: .0625rem;
}
.ds-item-rich-color-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem .5rem;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: .8125rem;
  text-align: left;
  cursor: pointer;
  transition: background var(--transition);
}
.ds-item-rich-color-item:hover {
  background: var(--bg-secondary);
}
.ds-item-rich-color-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px solid var(--border);
}
/* Feste weisse Editier-Flaeche — Begruendung s. Sektions-Kommentar oben. */
.ds-item-rich-body {
  min-height: 44px;
  padding: .5rem .625rem;
  font-size: .875rem;
  line-height: 1.5;
  background: #ffffff;
  color: #222222;
  outline: none;
  overflow-wrap: anywhere;
}
.ds-item-rich-body:empty::before {
  content: attr(data-placeholder);
  color: #999999;
  pointer-events: none;
}
.ds-item-rich.is-readonly {
  border-style: dashed;
}
.ds-item-rich.is-readonly .ds-item-rich-body {
  cursor: default;
}

/* Host-Modifier: ersetzen die Groessen-Rollen der frueheren <textarea>-Klassen. */
ds-item-rich-text { display: block; }
.invoice-item-text-rich {
  flex: 1;
  min-width: 0;
}
.invoice-item-text-rich .ds-item-rich-body { min-height: 44px; }
.invoice-item-longdesc-rich {
  width: 100%;
}
.invoice-item-longdesc-rich .ds-item-rich-body { min-height: 3.5rem; }

/* ── "Weitere Bankkonten" je Unternehmensprofil (Spec 20260801_bookkeeping_accounts_upload_receipt_edit.md, Session 2) ── */
/* Neue Klassen-Familie: das nächste Verwandte (.invoicing-doc-list-item) hat keine
   Aktions-Buttons rechts und keinen Add/Edit-Formular-Zustand — daher eigene, kleine
   Familie statt Reuse (Begründung analog ".ds-merge-*" oben). */
.invoicing-bank-account-list {
  list-style: none;
  padding: 0;
  margin: 0 0 .5rem;
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
.invoicing-bank-account-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .625rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
}
.invoicing-bank-account-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .0625rem;
}
.invoicing-bank-account-label {
  font-size: .875rem;
  font-weight: 600;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.invoicing-bank-account-meta {
  font-size: .75rem;
  color: var(--text-tertiary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.invoicing-bank-account-actions {
  display: flex;
  align-items: center;
  gap: .25rem;
  flex-shrink: 0;
}
.invoicing-bank-account-form {
  padding: .625rem .625rem .25rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  margin-bottom: .25rem;
}
.invoicing-bank-account-form-actions {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: .5rem 0 .625rem;
}
/* ── Products: Such-Bar + Profil-Filter-Toolbar ────────────────── */
.products-toolbar {
  display: grid;
  grid-template-columns: 1fr 240px;
  gap: .5rem;
  margin-bottom: 1rem;
}
.products-toolbar .search-bar {
  margin-bottom: 0;
}
@media (max-width: 600px) {
  .products-toolbar {
    /* Suche 2/3 + Profil-Select 1/3 in einer Zeile statt gestapelt */
    grid-template-columns: 2fr 1fr;
  }
}

/* ── Products: Listen-Spalten ──────────────────────────────────── */
.products-list-name {
  font-weight: 600;
}
.products-list-desc {
  color: var(--text-secondary);
  font-size: .875rem;
  max-width: 24rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: inline-block;
  vertical-align: bottom;
}
.products-list-price {
  font-weight: 500;
  text-align: right;
  display: block;
}
.products-list-archived-badge {
  background: var(--bg-secondary);
  color: var(--text-tertiary);
  font-size: .75rem;
  font-weight: 400;
  padding: .15rem .5rem;
  border-radius: 999px;
  margin-left: .375rem;
  vertical-align: middle;
}

/* ── Products: Customer-Prices-Tab ────────────────────────────── */
.products-cp-list {
  display: flex;
  flex-direction: column;
  gap: .375rem;
}
.products-cp-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  flex-wrap: wrap;
}
.products-cp-contact {
  flex: 1;
  min-width: 0;
}
.products-cp-contact-name {
  font-weight: 500;
  font-size: .875rem;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.products-cp-contact-profile {
  font-size: .75rem;
  color: var(--text-tertiary);
}
.products-cp-price {
  width: 8rem;
  flex-shrink: 0;
}
.products-cp-tax {
  width: 5rem;
  flex-shrink: 0;
}
.products-cp-remove {
  color: var(--coral);
  flex-shrink: 0;
}
.products-cp-add-row {
  display: flex;
  gap: .5rem;
  align-items: flex-start;
  padding: .625rem .75rem;
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
  flex-wrap: wrap;
  margin-top: .5rem;
}

/* Products: Mobile-Page-Header H1 ausblenden wenn L3-Tab sichtbar */
@media (max-width: 900px) {
  page-products .page-header-h1 {
    display: none;
  }
  page-products .page-header-actions {
    display: none;
  }
}

/* Products: Edit-Page Mobile Sticky-Footer */
/* Desktop: Footer ausblenden (Toolbar-Speichern-Button reicht) */
page-products .form-footer {
  display: none;
}
@media (max-width: 900px) {
  page-products .form-footer {
    display: flex;
    position: sticky;
    bottom: 0;
    background: var(--bg-primary);
    border-top: 1px solid var(--border);
    padding: .75rem;
    padding-bottom: calc(.75rem + env(safe-area-inset-bottom, 0px));
    z-index: 5;
  }
  page-products .products-footer-save {
    flex: 1;
    justify-content: center;
    min-height: 48px;
  }
}

/* ── Products: Autocomplete im Position-Editor (PA-3) ─────────── */
.product-suggest-dropdown {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  max-height: 320px;
  overflow-y: auto;
  z-index: 100;
  margin-top: 2px;
}
.product-suggest-item {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .5rem .75rem;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
  min-height: 44px;
}
.product-suggest-item:last-child { border-bottom: none; }
.product-suggest-item:hover { background: var(--bg-secondary); }
.product-suggest-icon {
  color: var(--text-tertiary);
  flex-shrink: 0;
}
.product-suggest-main {
  flex: 1;
  min-width: 0;
}
.product-suggest-name {
  font-weight: 500;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.product-suggest-desc {
  font-size: .8rem;
  color: var(--text-tertiary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.product-suggest-price {
  font-size: .875rem;
  color: var(--text-secondary);
  text-align: right;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .15rem;
}
.product-suggest-override-badge {
  background: var(--teal-light);
  color: var(--teal);
  font-size: .65rem;
  padding: .1rem .35rem;
  border-radius: 999px;
}
.product-suggest-empty {
  padding: .75rem;
  color: var(--text-tertiary);
  font-size: .875rem;
  text-align: center;
}
.product-suggest-create {
  border-top: 1px solid var(--border);
  color: var(--accent);
  font-weight: 500;
}
.product-suggest-create:hover {
  background: var(--accent-light);
}
/* Anchor für das Dropdown — position:relative auf dem Desc-Feld-Wrapper */
/* Ersetzt den direkten .invoice-item-desc als Grid-Spalte-1-Kind */
.invoice-item-desc-wrap {
  position: relative;
  grid-column: 1;
  min-width: 0;
}
/* Input im Wrapper nimmt volle Breite */
.invoice-item-desc-wrap .invoice-item-desc {
  width: 100%;
  /* grid-column-Direktive auf .invoice-item-desc entfaellt — liegt jetzt im Wrapper */
}

/* Products: Customer-Price add-row Mobile */
@media (max-width: 600px) {
  .products-cp-row {
    flex-wrap: wrap;
  }
  .products-cp-price,
  .products-cp-tax {
    width: auto;
    flex: 1 1 auto;
    min-width: 5rem;
  }
  .products-cp-add-row {
    flex-direction: column;
  }
  .products-cp-add-row > * {
    width: 100%;
  }
}

/* ── Notes: Editor (ds-note-editor, Spec 3600) ─────────────── */

/* Outer-Wrapper – setzt Kontext für Quill-Override + Mention-Dropdown */
.ds-note-editor-wrap {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  overflow: visible; /* war: hidden – bricht das Mention-Dropdown (absolutely-positioned child außerhalb Wrap-Bottom) */
}

/* Quill-Toolbar im Editor-Wrap. Ticket 3.310: display:flex mit genau ZWEI Kindern
   (`.ql-toolbar-zone-left`/`-right`, s. „Notes: Toolbar-Zonen" weiter unten) – die linke
   Zone bricht bei wenig Platz intern mehrzeilig um, die rechte bleibt dank `align-items:
   flex-start` immer in Zeile 1 stehen, unabhängig davon wie hoch die linke Zone wächst. */
.ds-note-editor-toolbar,
.ds-note-editor-wrap .ql-toolbar.ql-snow {
  border: none;
  border-bottom: 1px solid var(--border);
  border-top-left-radius: var(--radius-md);
  border-top-right-radius: var(--radius-md);
  background: var(--bg-secondary);
  padding: .35rem .5rem;
  flex-shrink: 0;
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: .5rem;
}

/* Quill-Container (scrollbarer Editor-Bereich) */
.ds-note-editor-body,
.ds-note-editor-wrap .ql-container.ql-snow {
  flex: 1;
  border: none;
  border-bottom-left-radius: var(--radius-md);
  border-bottom-right-radius: var(--radius-md);
  font-size: 1rem;
  font-family: inherit;
  overflow-y: auto;
  overflow-x: hidden; /* Quill-Editor-Content in den unteren Ecken clippen */
}

/* Quill-Editor-Inhalt */
.ds-note-editor-wrap .ql-editor {
  min-height: 200px;
  color: var(--text-primary);
  padding: .75rem 1rem;
  line-height: 1.6;
}

/* Placeholder */
.ds-note-editor-wrap .ql-editor.ql-blank::before {
  color: var(--text-tertiary);
  font-style: normal;
}

/* Platzhalter "Notiz schreiben…" NIE im Lesemodus (Ticket 3.196.2, zweite,
   von der ql-blank-Synchronisation in ds-note-editor.js::_loadValueIntoQuill()
   unabhängige Absicherung) – eine Notiz zum Lesen fordert nicht zum
   Schreiben auf. Höhere Spezifität (4 statt 2 Klassen) gewinnt unabhängig
   von der Ladereihenfolge gegen quill.snow.min.css. Gilt in BEIDEN Formaten
   (Web- und A4/A5-Lesemodus) – kein :not(.ds-note-page-mode)-Guard nötig. */
.ds-note-editor-wrap.ds-note-editor--read .ql-editor.ql-blank::before {
  display: none;
}

/* Drag-over-Feedback – visueller Rahmen wenn Datei über dem Editor schwebt */
.ds-note-editor-wrap .ql-editor.drag-over {
  outline: 2px dashed var(--accent);
  outline-offset: -4px;
  background: var(--accent-light);
}

/* Bild-Auswahl (Desktop) – sichtbarer Rahmen nach Klick, Entf/Backspace löscht (N1) */
.ds-note-editor-wrap .ql-editor img {
  cursor: pointer;
}
.ds-note-editor-wrap .ql-editor img.ds-note-img-selected {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Mention-Blot – inline Chip im Editor-Text */
.ql-mention {
  display: inline-block;
  background: var(--accent-light);
  color: var(--accent);
  border-radius: var(--radius-sm);
  padding: .1rem .35rem;
  font-weight: 500;
  font-size: .9em;
  cursor: default;
  user-select: none; /* Pflicht: kein versehentliches Partial-Select */
  white-space: nowrap;
  transition: background var(--transition);
}

/* Mention-Suggestion-Dropdown – Position wird von _note-editor-mentions.js
   dynamisch über die Custom-Properties --mention-top/--mention-left/
   --mention-bottom gesetzt (Ticket 3.225: aus Quill getBounds() direkt unter
   dem Cursor berechnet). Fallback (kein Wert gesetzt) bleibt die alte
   statische Position knapp unter der Toolbar – besser als gar keine
   Positionierung, greift praktisch nie, weil updateMentionPosition() bei
   jedem Trigger-Check läuft.
   🔒 Ticket 3.417.4 (Re-Fix): `position:fixed` statt `absolute` – ein
   `absolute`-Kind von `.ds-note-editor-wrap` wurde vom Vorfahren
   `.notes-editor-page-body` (`overflow:hidden`, s.u. „Editor-Seiten-
   Scroll-Container") abgeschnitten, sobald der Cursor nah am unteren Rand
   der sichtbaren Editor-Fläche stand – diese Liste hatte zusätzlich (anders
   als die Schnellanlage darunter) GAR KEINE Flip-Logik. `position:fixed` +
   Viewport-Koordinaten (s. computeFixedPopupPosition() in
   _note-editor-mentions.js) escaped JEDEN `overflow:hidden`-Vorfahren –
   kein Ahne trägt `transform`/`filter`/`perspective`/`contain` (geprüft),
   dasselbe Prinzip wie core/ds-context-menu.js. `--mention-bottom` klappt
   die Liste bei Bedarf nach OBEN um (Umklappen), analog
   .ds-note-editor-mention-create. */
.ds-note-editor-mention-list {
  position: fixed;
  top: var(--mention-top, calc(100% + 4px));
  bottom: var(--mention-bottom, auto);
  left: var(--mention-left, 0);
  min-width: 220px;
  max-height: 240px;
  overflow-y: auto;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  z-index: 420;
  list-style: none;
  margin: 0;
  padding: .25rem 0;
}

/* Einzelner Mention-Suggestion-Eintrag */
.ds-note-editor-mention-item {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding: .45rem .75rem;
  cursor: pointer;
  transition: background var(--transition);
  border-radius: 0;
}
.ds-note-editor-mention-item:hover,
.ds-note-editor-mention-item.is-active {
  background: var(--accent-light);
  color: var(--accent);
}

/* Type-Badge (Kontakt / Projekt) innerhalb des Mention-Items */
.ds-note-editor-mention-item-type {
  display: inline-block;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .03em;
  padding: .05rem .3rem;
  border-radius: var(--radius-sm);
  background: var(--accent-light);
  color: var(--accent);
}

/* Mention-Item-Textblock (Name + Sub-Zeile) – ersetzt ein früheres
   Inline-Style (min-width:0;flex:1, frontend.md "CSS: Klassen statt
   Inline-Styles"), Ticket 3.408.2. */
.ds-note-editor-mention-item-body { min-width: 0; flex: 1; }

/* Slash-Befehlsliste ("/" im leeren Absatz, Ticket 3.408.5) – dieselbe
   Bauform wie die Mention-Vorschlagsliste oben (attendee-suggest-*-Klassen +
   .ds-note-editor-mention-item-body für Label/Beschreibung), eigene
   Positions-Variablen (--slash-top/--slash-left/--slash-bottom, s.
   updateSlashPosition() in _note-editor-slash-commands.js) statt
   --mention-top/-left/-bottom – beide Listen sind unabhängiger State und
   könnten (auch wenn praktisch nie) parallel existieren.
   🔒 Ticket 3.417.4: `position:fixed` + Flip nach oben – identische
   Begründung wie .ds-note-editor-mention-list oben (Re-Fix,
   `.notes-editor-page-body` schnitt diese Liste zuvor ab, keine
   Flip-Logik vorhanden). */
.ds-note-editor-slash-list {
  position: fixed;
  top: var(--slash-top, calc(100% + 4px));
  bottom: var(--slash-bottom, auto);
  left: var(--slash-left, 0);
  min-width: 260px;
  max-height: 280px;
  overflow-y: auto;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  z-index: 420;
}
/* Befehls-Icon – quadratisch statt der kreisrunden Avatar-Optik (geerbt von
   .attendee-suggest-avatar), Farbe wechselt mit Hover/aktivem Eintrag wie
   der Text daneben. */
.ds-note-editor-slash-icon { border-radius: var(--radius-sm); background: var(--bg-secondary); color: var(--text-secondary); }
.ds-note-editor-slash-list .attendee-suggest-item:hover .ds-note-editor-slash-icon,
.ds-note-editor-slash-list .attendee-suggest-item.is-active .ds-note-editor-slash-icon {
  background: var(--accent-light);
  color: var(--accent);
}

/* "…" als Kontakt anlegen"-Eintrag am Ende der @-Mention-Liste (Ticket
   3.408.2, s. openMentionCreateContact() in _note-editor-mentions.js) –
   Accent statt Grundtext, damit er sich von den echten Treffern abhebt. */
.ds-note-editor-mention-create-item { color: var(--accent); }
.ds-note-editor-mention-create-item .ds-note-editor-mention-create-icon {
  background: var(--accent-light);
  color: var(--accent);
}

/* Kontakt-Schnellanlage-Popover (Ticket 3.408.2) – teilt sich den Anker
   (--mention-top/--mention-left/--mention-bottom) mit .ds-note-editor-
   mention-list oben, beide schließen sich gegenseitig aus (s.
   renderMentionDropdown()). 🔒 Ticket 3.417.4: `position:fixed` (wie die
   Liste oben) statt `absolute` relativ zu `.ds-note-editor-wrap` – escaped
   denselben `overflow:hidden`-Vorfahren (`.notes-editor-page-body`). */
.ds-note-editor-mention-create {
  position: fixed;
  top: var(--mention-top, calc(100% + 4px));
  /* Ticket 3.417.2/.4: --mention-bottom (statt top) klappt das Formular NACH
     OBEN um, wenn unterhalb des Cursors nicht genug Platz ist – s.
     updateMentionCreatePosition() in _note-editor-mentions.js. Default
     "auto" wirkt nur, wenn --mention-top gleichzeitig auf "auto" gesetzt
     ist (nicht-umgeklappter Fall lässt bottom unbenutzt). */
  bottom: var(--mention-bottom, auto);
  left: var(--mention-left, 0);
  width: 300px;
  max-width: calc(100% - .75rem);
  z-index: 440;
  display: flex;
  flex-direction: column;
  padding: .75rem .85rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}
.ds-note-editor-mention-create-title {
  font-size: .8rem;
  font-weight: 700;
  color: var(--text-secondary);
  margin-bottom: .25rem;
}
.ds-note-editor-mention-create-pair {
  display: flex;
  gap: .5rem;
}
.ds-note-editor-mention-create-pair > div { flex: 1; min-width: 0; }
.ds-note-editor-mention-create-hint {
  font-size: .75rem;
  color: var(--text-tertiary);
  margin: .25rem 0 0;
}
.ds-note-editor-mention-create-toolbar { margin-top: .5rem; }

/* ── Tabellen-Styling: bereits vorhanden (Ticket 3.196.3, Zeile ~2000
   weiter unten in dieser Datei) – `.ds-note-editor-wrap .ql-editor table` +
   `td`/`th` waren schon vollstaendig gestylt (Overflow-Scroll bei
   Überbreite, Kopfzeile simuliert via tr:first-child, Light/Dark über
   CSS-Variablen), aus einer Zeit als Tabellen nur per Zwischenablage-Paste
   ins Dokument kamen. Ticket 3.200 (Toolbar-Button + natives Quill-
   'table'-Modul) erzeugt IDENTISCHES DOM (`<table><tbody><tr><td>`, keine
   `ql-`-Klassen, per Puppeteer-Probe verifiziert) – die bestehende Regel
   traf also bereits zu, ein zweiter Block hier wäre Duplikat/Spiegel (P-5)
   und ist NICHT ergänzt worden. Gleiches gilt für `_splitTableAcrossPages()`
   (A4/A5-Seiten-Pagination) – arbeitet generisch auf jedem `<table>` im
   Dokument, unabhängig davon ob per Paste oder per Toolbar-Button
   entstanden, kein Sonderfall nötig. */

/* ── "Tabelle einfügen"-Raster-Popover (Ticket 3.200) ──────────────────────
   Position via --tp-top/--tp-left (Custom Properties) – relativ zu
   .ds-note-editor-wrap (position:relative-Anker), berechnet aus
   getBoundingClientRect() des Toolbar-Buttons, s. _openTableGridPicker() in
   ds-note-editor.js. 🔒 Bewusst weiterhin `position:absolute`, NICHT `fixed`
   wie die drei Overlays oben (Ticket 3.417.4) – der Toolbar-Button liegt
   immer im oberen, nie geclippten Teil von `.ds-note-editor-wrap`, daher
   kein Bezug zur `.notes-editor-page-body`-overflow:hidden-Problematik. */
.ds-note-table-picker {
  position: absolute;
  /* Normalfall: unterhalb des Buttons (--tp-bottom bleibt auto). Reicht der
     Platz nicht (Mobile-Sticky-Footer-Toolbar), setzt _openTableGridPicker()
     stattdessen --tp-bottom + --tp-top:auto – der Popover wächst dann nach
     oben. Siehe _renderTableGridPicker()/_openTableGridPicker() Docblock. */
  top: var(--tp-top, calc(100% + 6px));
  bottom: var(--tp-bottom, auto);
  left: var(--tp-left, 0);
  z-index: 430; /* über der Mention-Liste (420) – beide können nie gleichzeitig offen sein, Reihenfolge nur für den Fall paralleler Overlays robust */
  min-width: 268px; /* muss PICKER_MIN_WIDTH in ds-note-editor.js entsprechen (Zeilen-/Spalten-Felder + "Einfügen" ohne Umbruch) */
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .65rem .75rem .75rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}
.ds-note-table-picker-label {
  text-align: center;
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-secondary);
}
.ds-note-table-picker-grid {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-self: center;
}
.ds-note-table-picker-row { display: flex; gap: 3px; }
.ds-note-table-picker-cell {
  width: 20px;
  height: 20px;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: var(--bg-secondary);
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
}
.ds-note-table-picker-cell.is-active {
  background: var(--accent);
  border-color: var(--accent);
}
.ds-note-table-picker-custom {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .4rem;
  padding-top: .55rem;
  border-top: 1px solid var(--border);
}
.ds-note-table-picker-custom-label {
  width: 100%;
  font-size: .72rem;
  color: var(--text-tertiary);
}
.ds-note-table-picker-input {
  width: 4.4rem; /* muss "Zeilen"/"Spalten" als Placeholder ungekürzt zeigen */
  padding: .3rem .4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: .82rem;
  text-align: center;
  font-family: inherit;
}
.ds-note-table-picker-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}
.ds-note-table-picker-custom-x { color: var(--text-tertiary); font-size: .8rem; }
.ds-note-table-picker-confirm { margin-left: auto; }

/* Dark-Mode: Quill-Toolbar-Icons (nur expliziter data-theme="dark"-Toggle) */
:root[data-theme="dark"] .ds-note-editor-wrap .ql-snow .ql-stroke { stroke: var(--text-secondary); }
:root[data-theme="dark"] .ds-note-editor-wrap .ql-snow .ql-fill   { fill:   var(--text-secondary); }
:root[data-theme="dark"] .ds-note-editor-wrap .ql-snow .ql-picker  { color:  var(--text-secondary); }
:root[data-theme="dark"] .ds-note-editor-wrap .ql-snow .ql-active .ql-stroke,
:root[data-theme="dark"] .ds-note-editor-wrap .ql-snow button:hover .ql-stroke { stroke: var(--accent); }
:root[data-theme="dark"] .ds-note-editor-wrap .ql-snow .ql-active .ql-fill,
:root[data-theme="dark"] .ds-note-editor-wrap .ql-snow button:hover .ql-fill   { fill:   var(--accent); }

/* Mobile (P4): größere Touch-Targets fürs Editor-Feld (≤ 900 px). Toolbar-Umbruch +
   Button-Größe selbst leben seit Ticket 3.310 im „Notes: Toolbar-Zonen"-Block weiter
   unten (Zeilenumbruch passiert INNERHALB der linken Zone, die Toolbar selbst bleibt
   `flex-wrap:nowrap` – s. Basis-Regel oben). */
@media (max-width: 900px) {
  .ds-note-editor-wrap .ql-toolbar.ql-snow {
    padding: .5rem;
  }
  .ds-note-editor-wrap .ql-editor {
    min-height: 160px;
    padding: .65rem .75rem;
    font-size: 1rem; /* kein kleineres Font auf Mobile */
  }
}

/* Kamera-Button in der Quill-Toolbar (manuell injiziert via _injectCameraButton) */
.ds-note-editor-wrap .ql-toolbar .ql-camera {
  width: 28px;
  height: 24px;
  padding: 3px 5px;
  cursor: pointer;
  background: none;
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
}
.ds-note-editor-wrap .ql-toolbar .ql-camera svg {
  width: 18px;
  height: 18px;
  color: var(--text-secondary);
  stroke: currentColor;
  fill: none;
  display: block;
}
.ds-note-editor-wrap .ql-toolbar .ql-camera:hover svg {
  color: var(--accent);
}

/* ── Notes: A4/A5-Seitenansicht – echte Block-Pagination (Spec 20260718 §5,
   Nachtrag "Option B" statt duenner Fuehrungslinien) ──────────────────────
   Web (Default) = unverändert (unendlich scrollen). ds-note-page-mode
   (JS-gesetzt, ds-note-editor.js _applyPageMode()) rendert den Inhalt auf
   getrennten weissen DIN-Seiten-"Sheets" auf grauem "Schreibtisch"-Canvas,
   mit grauen Gaps dazwischen – kein Block sitzt je im Gap (JS schiebt
   Bloecke per marginTop auf die nächste Seite, s. _recalcPageBreaks()).
   --note-page-w/-h/-pad sind JS-berechnete Custom Properties (physische
   Papiergrößen-Umrechnung 96dpi, keine Design-Spacing-Entscheidung –
   deshalb bewusst keine hartcodierten px-Werte hier, s. ds-note-editor.js
   _pageDims()). Die weissen Sheets kommen NICHT von .ql-editor selbst
   (das ist jetzt transparent + reiner Text-Traeger), sondern von einem
   JS-verwalteten Overlay-Sibling (.ds-note-page-sheets, _renderPageSheets()),
   das per z-index HINTER dem Text liegt. */
.ds-note-editor-wrap.ds-note-page-mode .ds-note-editor-body {
  position: relative;
  background: var(--bg-secondary);
  padding: 2rem 1rem;
}

.ds-note-editor-wrap.ds-note-page-mode .ql-editor {
  width: var(--note-page-w);
  min-height: var(--note-page-h);
  max-width: 100%;
  margin: 0 auto;
  box-sizing: border-box;
  padding: var(--note-page-pad);
  background: transparent; /* Sheets (s.u.) liefern das Weiss */
  position: relative; /* nötig damit z-index gegen den Sheets-Sibling greift */
  z-index: 1;
}

/* Ticket 3.269 (Folgemeldung 24.08.2026): Quills Link-/Überschrift-Popup
   (.ql-tooltip) ist im Seitenmodus ein Geschwister von .ql-editor (beide
   Kinder von .ds-note-editor-body) – quill.snow.min.css setzt darauf nur
   `position:absolute`, KEIN z-index (Stack-Level 0). Sobald .ql-editor
   (s.o.) `z-index:1` trägt, gewinnt dessen eigener Stacking-Context gegen
   das unpositionierte Tooltip-Level-0 – das Popup landet HINTER der Seite
   und ist weder sichtbar noch klickbar (mit elementFromPoint() nachweisbar:
   der Treffer an der Popup-Position ist .ql-editor, nicht der Tooltip).
   Fix: EINE Stufe über .ql-editor, in derselben kleinen Familie wie die
   Sheets (0/1/2) – keine willkuerlich hohe Zahl, die an anderer Stelle im
   Seitenmodus wieder überlagert. Bewusst NUR im Seitenmodus gescopt
   (.ds-note-page-mode) – .ql-tooltip kommt app-weit vor (Termine, Aufgaben,
   Angebote, Formulare via ds-rich-editor.js, s. dort), dort existiert kein
   z-index-Konflikt und eine ungescopte Regel duerfte diese Stapelreihenfolge
   nicht anfassen. Schema-Dokumentation: .claude/rules/modules/notes.md
   „Bildschirm-Rendering" (Sheets z-index:0, .ql-editor z-index:1). */
.ds-note-editor-wrap.ds-note-page-mode .ql-tooltip {
  z-index: 2;
}

/* Sheets-Overlay – Sibling von .ql-editor innerhalb des Scroll-Containers,
   scrollt automatisch mit (kein manuelles Sync). `top`/`height` sowie die
   einzelnen `.ds-note-page-sheet`-Kinder werden vollstaendig von
   _renderPageSheets() (JS) positioniert – die Werte hier sind nur
   Fallback/Defaults vor dem ersten Recompute. */
.ds-note-page-sheets {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  width: var(--note-page-w);
  max-width: 100%;
  margin: 0 auto;
  pointer-events: none;
  z-index: 0; /* HINTER .ql-editor (z-index:1) */
}
.ds-note-page-sheet {
  position: absolute;
  left: 0;
  right: 0;
  background: var(--bg-primary);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
}
.ds-note-page-sheet-label {
  position: absolute;
  right: .75rem;
  bottom: .5rem;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}

/* Mobile: fit-to-width – .ql-editor UND .ds-note-page-sheets werden per
   JS-Transform gemeinsam/identisch verkleinert (_recalcMobilePageScale(),
   Notability-Stil: ganze Seite sichtbar, vertikal scrollen, kein
   horizontales Scrollen – .ql-container hat bereits overflow-x:hidden).
   Nur weniger Schreibtisch-Rand auf Mobile. */
@media (max-width: 900px) {
  .ds-note-editor-wrap.ds-note-page-mode .ds-note-editor-body {
    padding: 1rem .5rem;
  }

  /* Fit-to-width via JS-transform braucht die ECHTE DIN-Breite (--note-page-w),
     nicht auf Container geklemmt – sonst doppelte Verkleinerung + falsches
     Seitenverhältnis. Zentrierung/Fit macht _recalcMobilePageScale() (top left). */
  .ds-note-editor-wrap.ds-note-page-mode .ql-editor,
  .ds-note-editor-wrap.ds-note-page-mode .ds-note-page-sheets {
    max-width: none;
    margin-left: 0;
    margin-right: 0;
  }
}

/* ── Notes: Format-Picker (Web/A4/A5 + Ausrichtung, Spec 20260718 §5) ───── */
.ds-note-format-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  padding: .5rem 1rem;
  border-bottom: 1px solid var(--border);
}
.ds-note-format-segment {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  flex-shrink: 0;
}
.ds-note-format-btn {
  padding: 0 .75rem;
  height: 30px;
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-size: .78rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  border: none;
  border-right: 1px solid var(--border);
  transition: background var(--transition), color var(--transition);
}
.ds-note-format-btn:last-child { border-right: none; }
.ds-note-format-btn:hover      { background: var(--bg-tertiary); color: var(--text-primary); }
.ds-note-format-btn.is-active  { background: var(--accent-light); color: var(--accent-dark); font-weight: 600; }

.ds-note-orient-toggle-wrap {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
}
.ds-note-orient-label {
  font-size: .78rem;
  color: var(--text-secondary);
}

@media (max-width: 900px) {
  .ds-note-format-row { padding: .5rem .75rem; }
  .ds-note-format-btn  { flex: 1; text-align: center; }
}

/* ── Notes: "Neue Seite" – Werkzeugleisten-Knopf (Ticket 254/T-00002, seit
   Ticket 3.310 gemeinsam mit dem Seiten-Toggle in der rechten, nicht
   umbrechenden Toolbar-Zone `.ql-toolbar-zone-right`, s. _core.css „Notes:
   Toolbar-Zonen" weiter unten und ds-note-editor.js `_reorganizeToolbar()`).
   Fuegt einen manuellen Seitenumbruch AN DER SCHREIBMARKE ein (Cursor-Insert,
   ds-note-editor.js _insertPageBreakAtCursor()) – anders als der Navigator-/
   Bottom-Sheet-Button "Seite hinzufügen" (_addPageAtEnd(), haengt IMMER ans
   Dokumentende an). Auf JEDER Breite sichtbar (kein Mobile-Hide wie beim
   Nav-Toggle) – Mobile hätte sonst keinen Weg, einen Umbruch an einer
   beliebigen Cursor-Position statt nur am Dokumentende einzufuegen. Gleiches
   Größen-/Optik-Muster wie .ql-camera/.ql-pagetoggle. ──── */
.ds-note-editor-wrap .ql-toolbar .ql-insert-pagebreak {
  width: 28px;
  height: 24px;
  padding: 3px 5px;
  cursor: pointer;
  background: none;
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  border-radius: var(--radius-sm);
  transition: background var(--transition), color var(--transition);
}
.ds-note-editor-wrap .ql-toolbar .ql-insert-pagebreak svg {
  width: 18px;
  height: 18px;
  color: var(--text-secondary);
  stroke: currentColor;
  fill: none;
  display: block;
}
.ds-note-editor-wrap .ql-toolbar .ql-insert-pagebreak:hover svg { color: var(--accent); }

/* ── Notes: "Trennlinie einfügen" – Werkzeugleisten-Knopf (Ticket 3.117
   Teil A). Fuegt eine horizontale Trennlinie (DividerBlot, ds-note-editor.js
   _registerDividerBlot()) AN DER SCHREIBMARKE ein – eigene .ql-formats-Gruppe
   direkt NACH "Neue Seite", gleiches Größen-/Optik-Muster wie
   .ql-insert-pagebreak/.ql-camera/.ql-pagetoggle. ──── */
.ds-note-editor-wrap .ql-toolbar .ql-insert-divider {
  width: 28px;
  height: 24px;
  padding: 3px 5px;
  cursor: pointer;
  background: none;
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  border-radius: var(--radius-sm);
  transition: background var(--transition), color var(--transition);
}
.ds-note-editor-wrap .ql-toolbar .ql-insert-divider svg {
  width: 18px;
  height: 18px;
  color: var(--text-secondary);
  stroke: currentColor;
  fill: none;
  display: block;
}
.ds-note-editor-wrap .ql-toolbar .ql-insert-divider:hover svg { color: var(--accent); }

/* Die eingefügte Trennlinie selbst (echtes <hr>, DividerBlot) – dezente
   Linie in beiden Modi (Web-Endlos-Scroll UND A4/A5-Seitenansicht), Edit-
   UND Read-Mode identisch (keine Bedienelemente, anders als der
   Seitenumbruch-Blot oben). */
.ds-note-editor-wrap .ql-editor hr.ds-note-divider-blot {
  border: none;
  border-top: 1px solid var(--border);
  margin: 1.5rem 0;
}

/* ── Notes: Seiten-Ansicht-Umschalter – Toolbar-Button (Nutzer-Feedback #3,
   Folge-Session). Seit Ticket 3.310 zusammen mit "Neue Seite" in der rechten,
   nicht umbrechenden Toolbar-Zone (`.ql-toolbar-zone-right`, s.o.) – bleibt
   dadurch IMMER in Zeile 1, egal wie oft die linke Zone umbricht. Schaltet
   NUR die Sichtbarkeit der Seiten-Bar/des Navigators. Das Einfuegen an der
   Schreibmarke läuft seit Ticket 254 über den eigenen Knopf davor
   (.ql-insert-pagebreak, s.o.). Immer sichtbar – unabhängig vom Format –,
   schaltet die Seiten-Bar (.ds-note-nav) ein/aus. Nur Desktop: Mobile hat
   die eigene Kompaktleiste/Bottom-Sheet (Button-Hide s.u.). ──── */
.ds-note-editor-wrap .ql-toolbar .ql-pagetoggle {
  width: 28px;
  height: 24px;
  padding: 3px 5px;
  cursor: pointer;
  background: none;
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  border-radius: var(--radius-sm);
  transition: background var(--transition), color var(--transition);
}
.ds-note-editor-wrap .ql-toolbar .ql-pagetoggle svg {
  width: 18px;
  height: 18px;
  color: var(--text-secondary);
  stroke: currentColor;
  fill: none;
  display: block;
}
.ds-note-editor-wrap .ql-toolbar .ql-pagetoggle:hover svg { color: var(--accent); }
.ds-note-editor-wrap .ql-toolbar .ql-pagetoggle.is-active {
  background: var(--accent-light);
}
.ds-note-editor-wrap .ql-toolbar .ql-pagetoggle.is-active svg { color: var(--accent-dark); }
@media (max-width: 900px) {
  /* Mobile hat die eigene Kompaktleiste/das Bottom-Sheet (_renderMobileNavBar()) für
     Format/Seiten – der Toolbar-Knopf selbst wäre redundant. Button-Hide statt (wie vor
     Ticket 3.310) Gruppen-Hide, da die Gruppe seit der Zonen-Umstellung "Neue Seite" +
     Seiten-Toggle GEMEINSAM trägt und "Neue Seite" auf Mobile weiterhin sichtbar bleiben
     muss (s. Docblock bei .ql-insert-pagebreak oben). */
  .ds-note-editor-wrap .ql-toolbar .ql-pagetoggle { display: none; }
}

/* ── Notes: manueller Seitenumbruch-Blot (Quill Custom-Embed, Spec 20260718
   §5, Phase 3b) – contenteditable=false, eigene Zeile im Delta. Dashed
   Trennlinie mit zentriertem Label + Hoch/Quer-Toggle ("sticky" Ausrichtung,
   s. ds-note-editor.js _lastActiveOrientation()). Markiert nur die
   Einfuegestelle im Text – der eigentliche Seiten-Sprung (weisses Sheet +
   grauer Gap) wird seit der Block-Pagination (s.o., .ds-note-page-sheets)
   NACH diesem Blot gerendert; der Blot selbst zählt nicht zur Seiten-
   Fuellung (s. ds-note-editor.js _recalcPageBreaks(), "isBreak"-Zweig). ──── */
.ds-note-break-blot {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .75rem;
  margin: 1.5rem 0;
  padding: .35rem 0;
  user-select: none;
}
.ds-note-break-blot::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  border-top: 1px dashed var(--border);
}
.ds-note-break-blot-label {
  position: relative;
  z-index: 1;
  background: var(--bg-primary);
  padding: 0 .6rem;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.ds-note-break-blot-orient {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: .35rem;
  background: var(--bg-primary);
  padding: 0 .6rem;
}
.ds-note-break-blot-orient-text {
  font-size: .68rem;
  color: var(--text-secondary);
}

/* Löschen-Button am manuellen Umbruch (Aufgabe #3) – entfernt genau diesen
   Umbruch, Inhalt fliesst wieder zusammen (s. ds-note-editor.js
   _deletePageBreak()). Dezent bis Hover, dann Danger-Farbe. */
.ds-note-break-blot-delete {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-tertiary);
  cursor: pointer;
  flex-shrink: 0;
  transition: background var(--transition), color var(--transition);
}
.ds-note-break-blot-delete svg { display: block; }
.ds-note-break-blot-delete:hover {
  background: var(--danger-light);
  color: var(--danger);
}

/* ── Notes: Seiten-Bar (Nutzer-Feedback #3, Folge-Session zu Spec 20260718
   §5, Phase 3b) ──────────────────────────────────────────────────────────
   Der früher immer sichtbare Format-Icon-Rail (Dock) ist entfallen – der
   Umschalter sitzt jetzt in der Quill-Toolbar (.ql-pagetoggle, s.o.). Die
   Bar selbst (.ds-note-nav: Format oben, Seiten darunter) ist eine
   alleinstehende, eigen umrandete Spalte, die NUR gerendert wird wenn offen
   (JS-Gate in ds-note-editor.js _renderDesktopNav()). Sichtbarkeit Desktop/
   Mobile ist zusätzlich per Media-Query gehaertet (Reload/Resize-sicher). */
.ds-note-editor-row {
  display: flex;
  flex-direction: row;
  flex: 1;
  min-height: 0;
  gap: .75rem;
}
.ds-note-editor-row .ds-note-editor-wrap {
  flex: 1;
  min-width: 0;
}

.ds-note-nav {
  /* 196px statt vormals 168px (Ticket 3.67, Aufgabe #2 – Navigator-
     Thumbnails): die Mini-Vorschauen brauchen etwas mehr Breite um
     erkennbar zu sein, s. .ds-note-nav-thumb unten. */
  width: 196px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  min-height: 0;
  overflow: hidden;
}
/* Format-Umschalter als Kopf-Abschnitt der Bar (oben Formate, darunter
   Seiten) – schmale 168px-Spalte braucht ein gestapeltes statt nebenein-
   ander-Layout (anders als die geraeumige Mobile-Sheet-Variante, die den
   Standard-Zeilen-Flow von .ds-note-format-row unverändert nutzt). */
.ds-note-nav .ds-note-format-row {
  flex-direction: column;
  align-items: stretch;
  gap: .5rem;
  padding: .6rem .75rem;
}
.ds-note-nav .ds-note-format-segment { width: 100%; }
.ds-note-nav .ds-note-format-btn { flex: 1; text-align: center; }
.ds-note-nav .ds-note-orient-toggle-wrap { justify-content: space-between; }

.ds-note-nav-web-hint {
  padding: 1rem .75rem;
  font-size: .78rem;
  line-height: 1.4;
  color: var(--text-tertiary);
  text-align: center;
}

.ds-note-nav-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: .5rem;
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
/* Desktop-Navigator-Eintrag ist seit Ticket 3.67 (Aufgabe #2) eine
   gestapelte "Karte": Mini-Vorschau oben (.ds-note-nav-thumb, optional),
   Metadaten-Zeile (Nummer/Label/Löschen-Icon, .ds-note-nav-item-meta)
   darunter. Die Mobile-Bottom-Sheet-Liste hat KEINE Thumbnails (Platzgrund,
   s. ds-note-editor.js _updateNavThumbnails()-Kommentar) und überschreibt
   flex-direction daher gezielt zurück auf eine kompakte Zeile
   (.ds-note-nav-sheet-list .ds-note-nav-item weiter unten). */
.ds-note-nav-item {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: .35rem;
  padding: .4rem .5rem;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-size: .78rem;
  cursor: pointer;
  text-align: left;
  transition: background var(--transition), color var(--transition);
}
.ds-note-nav-item:hover { background: var(--accent-light); color: var(--accent-dark); }
.ds-note-nav-item-meta {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
}
.ds-note-nav-item-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: .68rem;
  font-weight: 700;
  transition: background var(--transition), color var(--transition);
}
.ds-note-nav-item:hover .ds-note-nav-item-num { background: var(--accent); color: #fff; }
.ds-note-nav-item-text { display: flex; flex-direction: column; line-height: 1.25; }
.ds-note-nav-item-orient {
  font-size: .65rem;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .03em;
}

/* Löschen-Icon im Navigator-Eintrag (Aufgabe #3, "optional"-Teil) – nur
   gerendert wenn die Seite durch einen manuellen Umbruch entstand
   (p.breakEl gesetzt, s. ds-note-editor.js _recalcPageBreaks()). Bewusst ein
   <span> statt <button> (Verschachtelung von <button> in <button> ist laut
   HTML-Spec ungültig – .ds-note-nav-item ist selbst ein <button>); Klick
   stoppt die Propagation, damit nicht zusätzlich zum Item navigiert wird. */
.ds-note-nav-item-delete {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-left: auto;
  border-radius: var(--radius-sm);
  color: var(--text-tertiary);
  flex-shrink: 0;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.ds-note-nav-item-delete svg { display: block; width: 12px; height: 12px; }
.ds-note-nav-item-delete:hover {
  background: var(--danger-light);
  color: var(--danger);
}

/* Mini-Vorschau je Seite (Ticket 3.67, Aufgabe #2) – zeigt einen skalierten,
   nicht-interaktiven Ausschnitt des ECHTEN Editor-Inhalts (verkleinerter DOM-
   Klon per JS-Transform, kein Canvas/Screenshot-Paket, s. ds-note-editor.js
   _updateNavThumbnails()). Größe/Position der inneren Seite kommt
   vollstaendig aus JS (dims.w/h sind physische DIN-Massen, kein CSS-Token) –
   hier nur der Rahmen/Clip. Bei Notizen mit sehr vielen Seiten (Schwellwert
   s. JS-Konstante MAX_THUMB_PAGES) bleibt die Box leer + gedimmt (Fallback
   auf reine Nummernliste, kein Rebuild-Kosten für eine unrealistische
   Seitenzahl). */
.ds-note-nav-thumb {
  position: relative;
  overflow: hidden;
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  pointer-events: none;
}
.ds-note-nav-thumb-page {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: top left;
}
/* Fallback oberhalb der Seiten-Obergrenze (MAX_THUMB_PAGES) – Box bleibt im
   Layout (kein Sprung), zeigt aber keinen Inhalt. */
.ds-note-nav-list.ds-note-nav-thumb-disabled .ds-note-nav-thumb { display: none; }

.ds-note-nav-add {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .35rem;
  margin: .5rem;
  padding: .4rem .6rem;
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-secondary);
  font-size: .75rem;
  font-weight: 500;
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.ds-note-nav-add:hover { background: var(--accent-light); color: var(--accent-dark); border-color: var(--accent); }
.ds-note-nav-add svg { width: 14px; height: 14px; flex-shrink: 0; }

@media (max-width: 900px) {
  .ds-note-nav { display: none; }
}

/* ── Notes: Mobile-Kompaktleiste + Bottom-Sheet für Format &amp; Seiten
   (Spec 20260718 §5, Phase 3b; Nutzer-Feedback #3 Folge-Session: der Button
   ist jetzt IMMER sichtbar – auch im Web-Format – als Format-Icon statt nur
   "Seite X/N") – Notability-Stil-Pendant zum Desktop-Dock; Platzgrund: kein
   fester Navigator auf Mobile (Schreibfläche hat Prioritaet). Backdrop/
   Sheet-Muster analog .ds-more-sheet (nav.css). ── */
.ds-note-nav-mobile-btn {
  display: none;
  align-items: center;
  justify-content: center;
  gap: .35rem;
  width: 100%;
  padding: .4rem;
  margin-top: .35rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: .78rem;
  font-weight: 600;
  cursor: pointer;
}
.ds-note-nav-mobile-btn svg { width: 14px; height: 14px; flex-shrink: 0; }
.ds-note-nav-mobile-label { flex-shrink: 0; }
.ds-note-nav-mobile-pagecount {
  padding: .1rem .4rem;
  border-radius: var(--radius-sm);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: .7rem;
  font-weight: 600;
  flex-shrink: 0;
}

@media (max-width: 900px) {
  .ds-note-nav-mobile-btn { display: flex; }
}

.ds-note-nav-backdrop {
  position: fixed;
  inset: 0;
  z-index: 500;
  background: rgba(0, 0, 0, 0);
  transition: background var(--transition-slow);
  pointer-events: none;
}
.ds-note-nav-backdrop.visible { background: rgba(0, 0, 0, .45); pointer-events: all; }

.ds-note-nav-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 501;
  background: var(--bg-primary);
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  box-shadow: 0 -4px 32px rgba(0, 0, 0, .12);
  transform: translateY(100%);
  transition: transform 280ms cubic-bezier(.25, .46, .45, .94);
  pointer-events: none;
  max-height: 70dvh;
  display: flex;
  flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom);
}
.ds-note-nav-sheet.open { transform: translateY(0); pointer-events: all; }

.ds-note-nav-sheet-handle-row { display: flex; justify-content: center; padding: .6rem 0 .35rem; cursor: pointer; }
.ds-note-nav-sheet-handle { width: 36px; height: 4px; border-radius: 2px; background: var(--border); }
.ds-note-nav-sheet-title {
  padding: 0 1rem .5rem;
  font-size: .8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
}
.ds-note-nav-sheet-list {
  overflow-y: auto;
  padding: 0 .75rem;
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
/* Mobile Bottom-Sheet-Liste bleibt bewusst OHNE Thumbnails (Ticket 3.67,
   Aufgabe #2 – Platzgrund + Performance, s. ds-note-editor.js
   _updateNavThumbnails()-Kommentar) – die Karten-Spaltung des Desktop-
   Navigators (.ds-note-nav-item s.o.) wird hier gezielt zurückgesetzt auf
   die urspruengliche kompakte Zeile (kein .ds-note-nav-thumb im Mobile-
   Template, .ds-note-nav-item-meta bleibt einziges Kind -> flex-direction
   ist hier ohnehin nur für den hypothetischen Fall relevant). */
.ds-note-nav-sheet-list .ds-note-nav-item {
  flex-direction: row;
  align-items: center;
  gap: .5rem;
  font-size: .85rem;
  padding: .6rem .5rem;
}
.ds-note-nav-sheet-add { margin: .75rem 1rem; }
.ds-note-nav-sheet-safe-area { height: .5rem; }

@media (min-width: 901px) {
  .ds-note-nav-backdrop, .ds-note-nav-sheet { display: none !important; }
}

/* ── Notes: Mobile Sticky-Footer Toolbar (≤ 900 px) ─────────────── */
/* Breakpoint 2026-07-18 (Spec 20260718 §7-Nachtrag): von 600px auf den
   App-Standard-Mobile-Breakpoint 900px (isMobile()) harmonisiert – der
   Editor-eigene Speichern-Button muss konsistent auf allen Mobile-Breiten
   erscheinen (z.B. iPad Portrait 768px), nicht nur auf schmalen Phones. */

/* Desktop (> 900px): Save-Button bleibt versteckt (Desktop hat einen eigenen
   Speichern-Knopf im Panel-Header, s. design-system.md "Editor-eigener Speichern-Button").
   Toolbar-Zonen (Umbruch links, fix rechts) sind Breakpoint-unabhängig und leben in
   „Notes: Toolbar-Zonen" weiter unten – hier nur der Desktop-Sonderfall. */
@media (min-width: 901px) {
  .ds-note-editor-wrap .ql-save { display: none; }
}

/* ── Notes: Toolbar-Zonen (Ticket 3.310) ──────────────────────────────────
   Loest die vormals auf-/zuklappbare "Mehr Formate"-Zeile 2 (Board-Ticket 595 Paket C) ab –
   die Toolbar ist jetzt EINZEILIG mit automatischem Umbruch, auf JEDER Breite. Linke Zone
   (`.ql-toolbar-zone-left`) trägt alle Format-/Einfuege-Knoepfe in fachlich zusammengehoerigen
   `.ql-formats`-Clustern und bricht bei wenig Platz mehrzeilig um; rechte Zone
   (`.ql-toolbar-zone-right`, "Seite hinzufügen" + Seiten-Toggle) bleibt dank `align-items:
   flex-start` auf dem `.ql-toolbar`-Elternteil (s.o.) IMMER in Zeile 1 stehen – unabhängig
   davon wie oft die linke Zone umbricht (Domenico-Feedback 22.08.2026). Siehe
   ds-note-editor.js `_reorganizeToolbar()` für den Cluster-Aufbau. */
.ds-note-editor-wrap .ql-toolbar-zone-left {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  flex: 1 1 auto;
  min-width: 0;
}
.ds-note-editor-wrap .ql-toolbar-zone-right {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  flex: 0 0 auto;
}
.ds-note-editor-wrap .ql-toolbar-zone-left .ql-formats,
.ds-note-editor-wrap .ql-toolbar-zone-right .ql-formats {
  flex-shrink: 0; /* Icon-Cluster quetschen sich nie zusammen */
  margin-right: 0 !important; /* Quill-Default 15px-Gap ersetzt durch gap: oben */
}
/* Dünne Trennlinie zwischen benachbarten Clustern – die Grenze ergibt sich automatisch aus
   der Cluster-Bildung in ds-note-editor.js _reorganizeToolbar() (P-5: eine Regel deckt jede
   Cluster-Grenze ab, keine Divider-Sonderfaelle pro Knopf-Gruppe). */
.ds-note-editor-wrap .ql-toolbar-zone-left > .ql-formats + .ql-formats {
  padding-left: 0.5rem;
  border-left: 1px solid var(--border);
}

@media (max-width: 900px) {
  /* Editor-Wrap: Toolbar unten (via order), kein column-reverse damit Quill nicht bricht */
  .ds-note-editor-wrap {
    display: flex;
    flex-direction: column;
  }
  .ds-note-editor-wrap .ql-toolbar.ql-snow {
    order: 2; /* Toolbar nach unten schieben */
    /* Sticky-Footer: klebt am unteren Rand des Panels.
       ds-cal-panel ist position:fixed;bottom:0. Bis 2026-07-14 blieb die
       Bottom-Nav bei offenem Panel sichtbar (Flex-Kind des Shells) – der
       56px-Offset hielt die Toolbar darüber. Seit dem Nav-Fix (nav.css,
       body:has(.ds-cal-panel.open) ds-bottom-nav{display:none}) ist die
       Nav bei offenem Panel immer ausgeblendet – nur noch Safe-Area nötig. */
    position: sticky;
    bottom: env(safe-area-inset-bottom);
    z-index: 5;
    background: var(--bg-primary);
    border-top: 1px solid var(--border);
    border-bottom: none;
    border-radius: 0; /* Ticket 3.401.2: kein Karten-Rahmen mehr auf Mobile */
    padding: .5rem .6rem;
  }

  /* ── Notes: Toolbar bleibt bei offener Tastatur sichtbar (Aufgabe #5,
     Spec 20260718 §7-Nachtrag) ────────────────────────────────────────────
     iOS Safari verkleinert beim Öffnen der Tastatur NUR den sichtbaren
     Viewport (window.visualViewport), NICHT den Layout-Viewport – die
     obige `position:sticky;bottom:0`-Toolbar bleibt dadurch im (unver-
     aenderten) Layout-Viewport haengen und landet effektiv HINTER der
     Tastatur. ds-note-editor.js (_applyKeyboardToolbarOffset()) setzt bei
     erkannter Tastatur diese Klasse + einen inline `bottom`-Wert (die
     berechnete Tastatur-Lücke). `.ds-cal-panel`/-`body` setzen kein
     transform/filter → position:fixed bezieht sich hier korrekt auf den
     Viewport, nicht auf einen Zwischen-Container. */
  .ds-note-editor-wrap .ql-toolbar.ql-snow.ds-note-toolbar--kb-fixed {
    position: fixed;
    left: 0;
    right: 0;
    border-radius: 0;
    z-index: 502; /* über ds-cal-panel (401) + Mobile-Bottom-Sheet (501) */
  }

  .ds-note-editor-wrap .ql-container.ql-snow {
    order: 1; /* Editor-Body oben */
    border-radius: 0; /* Ticket 3.401.2: kein Karten-Rahmen mehr auf Mobile */
    /* Letzter Inhalt scrollt hinter die sticky Toolbar – Puffer nötig.
       Muss zum Toolbar-bottom-Offset oben passen (P-5) – seit dem Nav-Fix
       nur noch Safe-Area, keine 56px Nav-Reserve mehr. */
    padding-bottom: env(safe-area-inset-bottom);
  }

  /* Save-Button: IMMER blau (Quill-Default-CSS überschreibt sonst) – !important pflicht.
     44px (Ticket 3.401.3, Mindest-Trefferfläche) – vorher 36px, seit Ticket 3.401.1
     lebt der Knopf in der einzeiligen .ql-toolbar-mobile-row zusammen mit den anderen
     jetzt ebenfalls auf 44px gesetzten Knoepfen (P-5: eine Größe für die ganze Zeile). */
  .ds-note-editor-wrap .ql-toolbar.ql-snow button.ql-save,
  .ds-note-editor-wrap .ql-toolbar button.ql-save,
  .ds-note-editor-wrap button.ql-save {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 44px !important;
    height: 44px !important;
    min-width: 44px;
    padding: 0 !important;
    background: var(--accent) !important;
    color: #fff !important;
    border: none !important;
    border-radius: var(--radius-sm);
    cursor: pointer;
    flex-shrink: 0;
    transition: background var(--transition);
  }
  .ds-note-editor-wrap button.ql-save svg {
    display: block;
    stroke: #fff !important;
    fill: none !important;
    width: 20px;
    height: 20px;
  }
  .ds-note-editor-wrap button.ql-save:hover {
    background: var(--accent-dark) !important;
  }
  .ds-note-editor-wrap button.ql-save:active {
    transform: scale(0.95);
  }

  /* Toolbar-Buttons in beiden Zonen: Touch-Targets sicherstellen (Desktop bleibt bei Quills
     kompakter 28×24px-Größe aus quill.snow.min.css). */
  .ds-note-editor-wrap .ql-toolbar-zone-left button,
  .ds-note-editor-wrap .ql-toolbar-zone-right button {
    width: 36px;
    height: 36px;
    padding: 4px;
    flex-shrink: 0;
  }

  /* Picker-Dropdown (z.B. Heading) öffnet nach oben statt unten,
     sonst clipt der Sticky-Footer das Dropdown außerhalb des Viewports */
  .ds-note-editor-wrap .ql-toolbar.ql-snow .ql-picker-options {
    top: auto !important;
    bottom: 100% !important;
    margin-bottom: 4px;
    box-shadow: var(--shadow-lg);
    z-index: 100 !important; /* über dem Editor-Body (kein z-index default = stacking-conflict) */
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
  }
  /* Picker bekommt position:relative + z-index damit Options bottom:100% korrekt anchored
     UND über dem Editor-Body (.ql-editor) liegen */
  .ds-note-editor-wrap .ql-toolbar.ql-snow .ql-picker {
    position: relative;
  }
  .ds-note-editor-wrap .ql-toolbar.ql-snow .ql-picker.ql-expanded {
    z-index: 100;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   Notes: Mobile Werkzeugleiste – eine Zeile + Einfuegen-/Absatz-Menü +
   Auswahl-Leiste (Ticket 3.401.1) – loest auf < 900px die vier
   umbrechenden Desktop-Zeilen durch EINE waagerecht schiebbare Zeile ab.
   Haeufiges (Fett/Kursiv/Listen/Link) bleibt sichtbar, Seltenes wandert
   hinter zwei Aufklapp-Flächen. Aufbau + volle Herleitung:
   app/assets/js/components/_note-editor-mobile-toolbar.js. Die Desktop-
   Zonen (.ql-toolbar-zone-left/-right, „Notes: Toolbar-Zonen" oben) bleiben
   im DOM unverändert (reorganizeToolbar() läuft unverändert zuerst, AC7
   „oberhalb 900px unverändert") – auf Mobile sind sie nur leere Huellen
   (ihre Kinder wurden weiterverschoben in die Zeile/Menüs unten) und
   werden hier ausgeblendet.
   ══════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .ds-note-editor-wrap .ql-toolbar-zone-left,
  .ds-note-editor-wrap .ql-toolbar-zone-right {
    display: none;
  }

  /* Containing Block für die beiden Aufklapp-Flächen + die Auswahl-Leiste
     unten – greift unabhängig davon ob die Leiste sticky (Normalfall) oder
     fixed positioniert ist (Tastatur offen, .ds-note-toolbar--kb-fixed):
     beides sind bereits "positionierte" Elemente, ein zusätzliches
     position:relative hier aendert daran nichts, macht die Toolbar selbst
     aber explizit zum Anker – keine JS-Positionsberechnung nötig, reine
     CSS-Verankerung. */
  .ds-note-editor-wrap .ql-toolbar.ql-snow {
    position: relative;
  }

  .ql-toolbar-mobile-row {
    display: flex;
    align-items: center;
    gap: .25rem;
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .ql-toolbar-mobile-row::-webkit-scrollbar { display: none; }
  .ql-toolbar-mobile-row .ql-formats {
    display: flex;
    align-items: center;
    gap: .125rem;
    flex-shrink: 0;
    margin-right: 0 !important; /* Quill-Default-Gap ersetzt durch gap: oben */
  }
  .ql-toolbar-mobile-row > .ql-formats + .ql-formats {
    padding-left: .375rem;
    border-left: 1px solid var(--border);
    flex-shrink: 0;
  }

  /* Trefferflächen 44px (Ticket 3.401.3-Vorgabe, hier direkt korrekt gebaut
     statt später nachgezogen – Quills Default ist 28×24px).
     🔒 `.ds-note-editor-wrap .ql-toolbar` PFLICHT-Praefix: quill.snow.min.css
     setzt `.ql-snow.ql-toolbar button, .ql-snow .ql-toolbar button` (2 Klassen
     + Element = Spezifität 0,0,2,1) UND lädt NACH components.css im <head>
     (app/index.php) – eine gleich-spezifische Regel HIER würde bei GLEICHER
     Spezifität vom SPAETER geladenen Quill-CSS überschrieben (Puppeteer-
     bewiesen: erst mit diesem Praefix maß der Bold-Knopf tatsaechlich 44×44px
     statt weiterhin 28×24px). Analoge Falle zu frontend.md „Eine Media-Query
     erhöht die Spezifität NICHT" – hier: „Zwei Klassen sind nicht automatisch
     genug, wenn eine später geladene fremde Bibliothek dieselbe Spezifität
     hat". */
  .ds-note-editor-wrap .ql-toolbar .ql-toolbar-mobile-row button,
  .ds-note-editor-wrap .ql-toolbar .ql-toolbar-mobile-menu button {
    width: 44px;
    height: 44px;
    padding: 0;
    flex-shrink: 0;
  }
  .ds-note-editor-wrap .ql-toolbar .ql-toolbar-mobile-row button svg,
  .ds-note-editor-wrap .ql-toolbar .ql-toolbar-mobile-menu button svg {
    width: 20px;
    height: 20px;
  }

  .ql-mobile-insert-trigger,
  .ql-mobile-format-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    border-radius: var(--radius-sm);
  }
  .ql-mobile-insert-trigger.is-active,
  .ql-mobile-format-trigger.is-active {
    background: var(--accent-light);
    color: var(--accent-dark);
  }

  /* Überschrift-Picker im Absatz-Menü ist KEIN <button> (Quills eigenes
     `.ql-picker`-Konstrukt, `<span>`) – der button-Selektor oben trifft ihn
     nicht. Gleiche Spezifitäts-Falle wie oben: `.ql-snow .ql-picker` hat
     Hoehe 24px fest, höhere Spezifität nötig (Ticket 3.401.3 AC1). */
  .ds-note-editor-wrap .ql-toolbar .ql-toolbar-mobile-menu .ql-picker {
    height: 44px;
  }
  .ds-note-editor-wrap .ql-toolbar .ql-toolbar-mobile-menu .ql-picker-label {
    display: flex;
    align-items: center;
  }

  /* Zwei kompakte Flächen über der Zeile – position:absolute, verankert an
     .ql-toolbar (s.o.). bottom:100% hält sie IMMER direkt über der Zeile,
     egal ob die Leiste gerade sticky am Panel-Rand oder fixed über der
     Tastatur steht. */
  .ql-toolbar-mobile-menu {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;
    margin-bottom: 6px;
    max-height: 50vh;
    overflow-y: auto;
    flex-wrap: wrap;
    gap: .25rem;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    padding: .5rem;
    z-index: 40;
  }
  .ql-toolbar-mobile-menu.is-open {
    display: flex;
  }
  .ql-toolbar-mobile-menu .ql-formats {
    display: flex;
    gap: .25rem;
    flex-wrap: wrap;
  }

  /* Auswahl-Leiste – schwebt über der Textauswahl. Position via
     --selbar-top/--selbar-left (identisches Muster zu
     .ds-note-editor-mention-list --mention-top/--mention-left, s.o.). */
  .ql-mobile-selbar {
    display: none;
    position: absolute;
    top: var(--selbar-top, 0);
    left: var(--selbar-left, 0);
    width: 200px; /* 4 × 44px Trefferfläche + Abstand (Ticket 3.401.3 AC1) */
    align-items: center;
    justify-content: space-around;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    padding: .25rem;
    z-index: 45;
  }
  .ql-mobile-selbar.is-open {
    display: flex;
  }
  .ql-mobile-selbar button {
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    border-radius: var(--radius-sm);
  }
  .ql-mobile-selbar button svg { width: 18px; height: 18px; }
  .ql-mobile-selbar button:active { background: var(--bg-tertiary); }
}

/* Live-Resize-Absicherung (Desktop-Fenster über 900px): die mobile Zeile/
   Menüs/Auswahl-Leiste entstehen nur, wenn isMobile() beim Konstruieren
   der Toolbar zutraf (JS-Snapshot, s. ds-note-editor.js _initQuill()) – bei
   einem echten Telefon unverändert während der ganzen Sitzung true. Ein
   während des Bearbeitens über 900px vergrößertes Browserfenster soll
   diese DOM-Reste trotzdem nie zeigen (analog .ds-note-nav-backdrop/-sheet
   oben). */
@media (min-width: 901px) {
  .ql-toolbar-mobile-row,
  .ql-toolbar-mobile-menu,
  .ql-mobile-selbar {
    display: none !important;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   Notes: Mobile – eine Kopfzeile statt zwei, Editor auf volle Fläche
   (Ticket 3.401.2) – loest die vormals doppelte Kopfzeile (app-weiter
   ds-app-header + eigene .notes-panel-header) durch EINE schlanke Zeile ab:
   Zurück/Titel/Speichern/Mehr (Aufbau: _note-editor-mobile-header.js).
   Karten-Rahmen faellt weg, der Text läuft bis an die Ränder.
   ══════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  /* App-weite Kopfzeile tritt zurück, solange der Editor als eigene Seite
     offen ist (Lese- UND Bearbeiten-Ansicht haben bereits ihre eigene
     .notes-panel-header-Zeile). page-note-editor ist eine GEROUTETE Seite
     (kein Panel/Overlay) – body:has() trägt ihre Anwesenheit zuverlaessig,
     solange sie gemountet ist.
     🔒 Kanonischer Ort wäre die bestehende body:has()-Selektorliste in
     nav.css (analog zur dortigen ds-bottom-nav-Liste, "eine gepflegte
     Auswahlliste, kein zweiter JS-verwalteter Mechanismus") – nav.css liegt
     aber AUSSERHALB des Datei-Scopes dieses Tickets (_notes.css ist es).
     Regel bewusst hier belassen: components.css (← _notes.css) lädt VOR
     nav.css im <head> (app/index.php), keine dort kollidierende Regel
     existiert – funktional gleichwertig. Konsolidierung nach nav.css als
     Folgeschritt vorgeschlagen, s. Session-Report. */
  body:has(page-note-editor) ds-app-header {
    display: none;
  }

  /* EINE Kopfzeile: Zurück, Titel, Speichern/Bearbeiten, Mehr-Menü.
     Basis-Layout/-Optik kommt aus .ds-panel-toolbar/.ds-toolbar-item
     (Design-System, _core.css) – hier nur Größe (44px Mindest-Trefferfläche,
     Ticket 3.401.3-Vorgabe direkt mitgebaut) + Titel-Ellipsis gescopt. */
  .notes-panel-header-mobile-single {
    flex-wrap: nowrap;
    gap: .375rem;
    /* Ticket 3.401.3 "Abstände vereinheitlichen": dieselbe horizontale Stufe
       wie .notes-header-fields-row/.notes-preview-hidden-row darunter
       (1rem) statt der generischen .ds-panel-toolbar-Vorgabe (.75rem). */
    padding-left: 1rem;
    padding-right: 1rem;
  }
  .notes-panel-header-mobile-single .ds-toolbar-item {
    height: 44px;
    min-width: 44px;
    padding: 0 .5rem;
    flex-shrink: 0;
  }
  .notes-mobile-back-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: none;
    background: none;
    color: var(--text-secondary);
    border-radius: var(--radius-sm);
    cursor: pointer;
    flex-shrink: 0;
    transition: background var(--transition), color var(--transition);
  }
  .notes-mobile-back-btn:hover,
  .notes-mobile-back-btn:active {
    background: var(--bg-tertiary);
    color: var(--text-primary);
  }
  .notes-mobile-header-title {
    flex: 1;
    min-width: 0;
    font-size: .9375rem;
  }

  /* Kein Karten-Rahmen mehr – der Text läuft bis an die Ränder, mit
     ruhigem Innenabstand (.ql-editor liefert ihn weiterhin unverändert:
     .75rem 1rem). Die Toolbar-/Menü-Border/-Radius-Werte wurden oben in
     „Notes: Mobile Sticky-Footer Toolbar" bereits auf 0 gesetzt.
     🔒 Das `padding:0` für .notes-editor-page-body selbst steht NICHT hier,
     sondern erst NACH dessen eigener Basisregel weiter unten in dieser Datei
     (── Notes: Layout ── Block) – eine Media-Query erhöht die Spezifität
     NICHT, eine gleich-spezifische Regel VOR der Basisregel wäre von ihr
     überschrieben worden (frontend.md „Eine Media-Query erhöht die
     Spezifität NICHT"; per Puppeteer bewiesen: pageBodyPad blieb 24px). */
  .ds-note-editor-wrap {
    border: none;
    border-radius: 0;
  }
  /* Die drei Zeilen unterhalb der Kopfzeile (Titel/Notizbuch, Vorschau-
     Verbergen-Umschalter, "Verknüpft mit") hatten ihren seitlichen Abstand
     bisher ALLEIN von .notes-editor-page-body geerbt (nur vertikales eigenes
     Padding) – mit dessen Padding auf 0 brauchen sie ihn jetzt selbst, sonst
     kleben Eingabefelder/Chips an der Bildschirmkante. Der Editor selbst
     bleibt bewusst OHNE diesen Ausgleich (edge-to-edge, s.o. – .ql-editor
     liefert dort den Innenabstand). */
  .notes-header-fields-row,
  .notes-preview-hidden-row,
  .notes-api-excluded-row,
  .notes-panel-mentions {
    padding-left: 1rem;
    padding-right: 1rem;
  }

  /* "Web"-Format-Pill gehört zur Seitenform, nicht zum Schreiben (Ticket
     3.401.2, Umsetzungspunkt 4) – wandert ins Mehr-Menü ("Format & Seiten",
     ruft denselben Sheet via ds-note-editor.js openMobilePageSheet() auf).
     Scoped auf page-note-editor: ds-note-editor ist an keiner anderen Stelle
     editierbar gemountet (grep-geprüft), der Pill bleibt für künftige
     Mount-Punkte unangetastet sichtbar. */
  page-note-editor .ds-note-nav-mobile-btn {
    display: none;
  }
}

/* ── Notes: Layout ─────────────────────────────────────────────────── */
/* Fix 1: host-Element auf overflow-x:hidden damit kein horizontaler Scroll
   entsteht (ds-cal-panel ist position:fixed und gehört nicht in scrollende Container) */
page-notes {
  display: block;
  overflow-x: hidden;
}

.notes-layout {
  display: flex;
  position: relative;
  gap: 0;
  height: 100%;
  overflow: hidden;
}

.notes-sidebar {
  width: 220px;
  min-width: 220px;
  flex-shrink: 0;
  border-right: 1px solid var(--border);
  padding: .5rem 0;
  overflow-y: auto;
  background: var(--bg-primary);
  display: flex;
  flex-direction: column;
  gap: 0;
  transition: width .2s ease, min-width .2s ease;
  position: relative; /* Containing Block für den Ziehgriff, Ticket 3.220.2 */
}

/* Sidebar-Collapse (Desktop, an Todos-Sidebar angeglichen – seit 2026-07-16) */
.notes-layout.sidebar-collapsed .notes-sidebar {
  width: 0;
  min-width: 0;
  overflow: hidden;
}

/* Ticket 3.299: Position leitet sich aus --ds-sidebar-w ab (gesetzt von
   core/sidebar-resize.js auf .notes-layout, dem gemeinsamen Elternteil von
   .notes-sidebar UND .notes-sidebar-toggle – s. Docblock dort). Vorher stand
   hier ein roher Wert (208px = ehemalige Festbreite 220px minus halbe
   Knopfbreite), der bei jeder gezogenen Breite falsch war – identischer Bug
   wie .todos-sidebar-toggle vor Ticket 3.297 (dort bereits gefixt, hier
   nachgezogen). Fallback 220px = Default-Breite ohne aktiven Ziehgriff
   (Erstrender vor firstUpdated()/auf Mobile, wo der Griff nie angehaengt
   wird). Die .sidebar-collapsed-Regel (nächste Zeile) überschreibt `left`
   per höherer Selektor-Spezifität weiterhin unabhängig vom aktuellen
   Variablenwert – dieselbe Kaskaden-Eigenschaft wie in _todos.css. */
.notes-sidebar-toggle {
  position: absolute;
  left: calc(var(--ds-sidebar-w, 220px) - 12px);
  top: .5rem;
  z-index: 5;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--bg-primary);
  cursor: pointer;
  transition: left .2s ease;
  color: var(--text-tertiary);
  padding: 0;
}
.notes-sidebar-toggle:hover {
  color: var(--text-primary);
  background: var(--bg-secondary);
}
.notes-layout.sidebar-collapsed .notes-sidebar-toggle {
  left: 0;
}
/* Während des Ziehens (body.ds-sidebar-resizing, gesetzt von
   core/sidebar-resize.js für jeden der 5 Konsumenten) folgt der Knopf
   OHNE Verzoegerung – die .2s-ease-Transition ist nur für den Ein-/
   Ausklapp-Wechsel gedacht (Klick auf .notes-sidebar-toggle), nicht für
   den kontinuierlichen Drag. Analog _todos.css. */
body.ds-sidebar-resizing .notes-sidebar-toggle { transition: none; }

.notes-sidebar-section {
  display: flex;
  flex-direction: column;
  gap: .125rem;
  margin-bottom: .75rem;
}

.notes-sidebar-label {
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--text-tertiary);
  letter-spacing: .05em;
  padding: .75rem 1rem .25rem;
  border-top: 1px solid var(--border);
}

.notes-sidebar-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .4rem .75rem;
  border-radius: var(--radius-sm);
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--text-secondary);
  font-size: .875rem;
  text-align: left;
  width: auto;
  margin: 0 .25rem;
  transition: background var(--transition), color var(--transition);
}
.notes-sidebar-item svg {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
}
.notes-sidebar-item:hover    { background: var(--bg-secondary); color: var(--text-primary); }
.notes-sidebar-item.is-active { background: var(--accent-light); color: var(--accent); font-weight: 600; }

.notes-sidebar-count {
  margin-left: auto;
  font-size: .75rem;
  color: var(--text-tertiary);
}

.notes-sidebar-add {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem .75rem;
  font-size: .8rem;
  color: var(--text-tertiary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  margin: 0 .25rem;
  background: none;
  border: none;
  transition: color var(--transition), background var(--transition);
}
.notes-sidebar-add:hover {
  color: var(--accent);
  background: var(--accent-light);
}
.notes-sidebar-add svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.notes-ws-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* ── Notes: Mobile Drawer-Toggle ("≡ Notizbücher", ersetzt die frühere
   durchsuchbare Selectbox – Nutzer-Feedback) ──
   Zeilen-Anordnung (Toggle-Button + dezentes, nicht-interaktives Kontext-
   Label mit dem aktiven Workspace-Namen) lebt jetzt in der geteilten
   Klassen-Familie `.ds-mobile-navbar*` (_core.css, P-5 – identisches Pattern
   in pages/todos/page-todos.js `_renderMobileNavBar()`). Der Drawer-Inhalt
   selbst (_renderDrawer() in pages/notes.js) ist die volle .notes-sidebar-
   Struktur unten – kein eigenes Layout nötig, nur ein Breiten-Reset s.u. */

/* Die Desktop-Sidebar (.notes-sidebar) wird 1:1 als Drawer-Inhalt wiederverwendet
   (pages/notes.js _renderDrawer() ruft _renderWorkspaceSidebar(), P-5 – kein
   Nachbau) – hier nur die Desktop-Fixbreite/den Border-Right zurücksetzen,
   damit sie die volle Drawer-Breite ausfuellt. */
.ds-drawer .notes-sidebar {
  width: 100%;
  min-width: 0;
  border-right: none;
}

.notes-ws-filter-edit-btn {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.notes-ws-filter-edit-btn:hover:not(:disabled) { background: var(--bg-secondary); color: var(--accent); }
.notes-ws-filter-edit-btn:disabled             { opacity: .35; cursor: not-allowed; }

/* Workspace-Zeile: Auswahl-Button + Bearbeiten-Pencil als Geschwister (kein
   verschachteltes <button>). Diese eine Zeilen-Struktur bedient SOWOHL die
   Desktop-Sidebar ALS AUCH den Mobile-Drawer-Inhalt (_renderWorkspaceSidebar()
   wird an beiden Stellen gerufen, P-5). Pencil reused: .notes-ws-filter-edit-btn
   (identischer Icon-Button-Stil); permanent sichtbar (nicht mehr hover-basiert –
   Nutzer-Feedback #1: Hover-Reveal liess das Zeilen-Layout beim Hover springen). */
.notes-sidebar-item-row {
  display: flex;
  align-items: center;
  gap: .125rem;
  margin: 0 .25rem;
  position: relative;
  touch-action: pan-y;
}
.notes-sidebar-item-row .notes-sidebar-item {
  flex: 1;
  min-width: 0;
  margin: 0;
}
.notes-sidebar-item-row .notes-ws-filter-edit-btn {
  display: flex;
  width: 1.75rem;
  height: 1.75rem;
  flex-shrink: 0;
}

/* ── Notes: Workspace-Sidebar Drag & Drop sortieren (Nutzer-Feedback #4) ──
   Desktop: natives HTML5-DnD auf .notes-sidebar-item-row, Griff-Icon permanent
   sichtbar (analog dem Bearbeiten-Pencil oben – Nutzer-Feedback #1: kein
   Hover-Reveal mehr, sonst springt das Zeilen-Layout). is-dragging/is-drop-
   target werden während der Drag-Geste per direkter JS-classList-Mutation
   gesetzt (kein Lit-Re-Render möglich, s. pages/notes.js Kommentar). */
.notes-sidebar-drag-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.125rem;
  height: 1.75rem;
  flex-shrink: 0;
  color: var(--text-tertiary);
  cursor: grab;
}
.notes-sidebar-item-row.is-dragging {
  opacity: .45;
  cursor: grabbing;
}
.notes-sidebar-item-row.is-dragging .notes-sidebar-drag-handle {
  cursor: grabbing;
}
.notes-sidebar-item-row.is-drop-target::before {
  content: '';
  position: absolute;
  left: .25rem;
  right: .25rem;
  top: -2px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
}

/* Main content area */
.notes-main {
  flex: 1;
  min-width: 0;
  overflow-y: auto;
  padding: 1rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: .75rem;
}

/* ── Notes: Karten-Grid ─────────────────────────────────────────────── */
.notes-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: .75rem;
}

.notes-card {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .875rem 1rem;
  cursor: pointer;
  transition: box-shadow var(--transition), border-color var(--transition);
  display: flex;
  flex-direction: column;
  gap: .375rem;
}
.notes-card:hover        { box-shadow: var(--shadow-sm); border-color: var(--accent); }
.notes-card--pinned      { border-color: var(--amber); }

.notes-card-header {
  display: flex;
  align-items: flex-start;
  gap: .375rem;
}

.notes-card-title {
  font-weight: 600;
  font-size: .9rem;
  color: var(--text-primary);
  flex: 1;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.notes-card-pin {
  font-size: .75rem;
  flex-shrink: 0;
  color: var(--amber);
}

.notes-card-preview {
  font-size: .82rem;
  color: var(--text-secondary);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Vorschau-Verbergen (note.preview_hidden=1): Karten-Vorschau als verwischter
   Fuell-Text statt echtem Inhalt – der Inhalt kommt bei preview_hidden=1
   serverseitig in der Listen-Response ohnehin nicht mit (_blurredPreviewFiller
   in pages/notes.js). */
.notes-card-preview--hidden {
  color: var(--text-tertiary);
  filter: blur(4px);
  user-select: none;
  pointer-events: none;
}

.notes-card-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: .25rem;
}

.notes-card-time {
  font-size: .75rem;
  color: var(--text-tertiary);
}

.notes-card-tags {
  display: flex;
  gap: .25rem;
  flex-wrap: wrap;
}

/* Nutzer-Feedback #1: Workspace-Zuordnung unten rechts auf der Karte –
   haengt sich per margin-left:auto an das Ende der Meta-Zeile (mit .notes-card-time
   + optional .notes-card-tags), .notes-card-meta ist per flex-wrap:wrap tolerant
   falls der Platz auf schmalen Karten nicht reicht (eigene Zeile, weiterhin
   rechtsbündig durch margin-left:auto). */
.notes-card-ws {
  display: flex;
  align-items: center;
  gap: .3rem;
  margin-left: auto;
  min-width: 0;
  max-width: 55%;
  font-size: .72rem;
  color: var(--text-tertiary);
}

.notes-card-ws-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

/* Notizliste auf Mobile (Ticket 3.401.3): Titel bleibt führend (bereits
   line-clamp:2), Vorschau auf ZWEI statt drei Zeilen begrenzt, Metadaten
   (Datum, Notizbuch) eine Stufe größer + mehr Zeilenabstand – bewusst nur
   eine Stufe (886-Fallstrick: zu gross frisst den in 3.401.2 gewonnenen
   Platz wieder auf). Karten-Innenabstand bleibt unverändert (bereits
   grosszuegig genug für eine sichere Daumen-Trefferfläche). */
@media (max-width: 900px) {
  .notes-card-preview {
    -webkit-line-clamp: 2;
  }
  .notes-card-time,
  .notes-card-ws {
    font-size: .8rem;
    line-height: 1.5;
  }
}

/* Papierkorb-Karte (B38 N2) – eigene Actions-Zeile statt Klick-zum-Öffnen */
.notes-card--trashed {
  cursor: default;
}
.notes-trash-actions {
  display: flex;
  gap: .5rem;
  margin-top: .5rem;
  flex-wrap: wrap;
}
.notes-trash-hint {
  margin: .5rem 0 0;
  font-size: .75rem;
  color: var(--text-tertiary);
}

/* ── Notes: Empty-State ─────────────────────────────────────────────── */
.notes-empty-state {
  text-align: center;
  color: var(--text-secondary);
  padding: 3rem 1rem;
  font-size: .9rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .75rem;
}

.notes-empty-state svg {
  color: var(--text-tertiary);
  opacity: .5;
}

/* ── Notes: Panel-Details ───────────────────────────────────────────── */
.notes-panel-mentions {
  display: flex;
  align-items: center;
  gap: .375rem;
  flex-wrap: wrap;
  padding: .5rem 0;
  border-top: 1px solid var(--border);
  margin-top: .5rem;
  font-size: .82rem;
}
/* Metadaten um den Text lesbar machen (Ticket 3.401.3): eine Stufe größer
   + mehr Zeilenabstand, nur Mobile (Gegenprobe: Schreibtisch unverändert). */
@media (max-width: 900px) {
  .notes-panel-mentions {
    font-size: .875rem;
    line-height: 1.5;
  }
  .notes-preview-hidden-label {
    font-size: .875rem;
  }
  .notes-api-excluded-hint {
    font-size: .8125rem;
  }
}

.notes-panel-mentions-label { color: var(--text-tertiary); }

.notes-panel-mention-link {
  color: var(--accent);
  text-decoration: none;
}
.notes-panel-mention-link:hover { text-decoration: underline; }

/* Auto-Save-Indikator im Panel */
.notes-saved-indicator {
  font-size: .75rem;
  color: var(--text-tertiary);
  padding: .25rem .5rem;
  align-self: center;
}

/* ── Notes: CRM-Contact-Feed ────────────────────────────────────────── */
.contact-notes-section {
  border-top: 1px solid var(--border);
  padding-top: .75rem;
  margin-top: .75rem;
}

.contact-notes-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .5rem;
  font-weight: 500;
  font-size: .875rem;
  color: var(--text-primary);
}

.notes-contact-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .375rem .5rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition);
}
.notes-contact-item:hover { background: var(--bg-secondary); }

.notes-contact-title {
  font-size: .875rem;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
}

.notes-contact-time {
  font-size: .75rem;
  color: var(--text-tertiary);
  flex-shrink: 0;
}

.notes-empty-text {
  font-size: .82rem;
  color: var(--text-tertiary);
  padding: .5rem .25rem;
}

/* ── Notes: Workspace-Farb-Input ────────────────────────────────────── */
/* Native color-picker – normalisiert auf einheitliche Größe */
.notes-ws-color-input {
  width: 2.5rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  background: none;
}
.notes-ws-color-input::-webkit-color-swatch-wrapper { padding: 2px; }
.notes-ws-color-input::-webkit-color-swatch         { border: none; border-radius: var(--radius-sm); }

/* Ticket 3.367.5: Workspace-Formular "Aufgaben-Anbindung" – schlichte Flex-
   Zeile (Farb-Feld + Aktionsleiste) und Etiketten-Mehrfachauswahl als
   umbrechende Chip-Reihe (reused .filter-chip/.active, kein neues Pattern). */
.notes-ws-inline-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
}
.notes-ws-label-chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}
.notes-ws-label-empty {
  font-size: .8rem;
  color: var(--text-tertiary);
}

/* Ticket 3.196.1: bleibt fix stehen, wenn .notes-editor-page-body zur
   hoehenbeschraenkten Flex-Spalte wird – nur .ql-container soll scrollen.
   .ql-toolbar hat dasselbe bereits (s. .ds-note-editor-toolbar oben). */
.notes-panel-header {
  flex-shrink: 0;
}

.notes-panel-header-title {
  flex: 1;
  min-width: 0;
  font-size: .9375rem;
  font-weight: 600;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Ticket 3.367.2: Export-Knopf (Drucker-Icon) öffnet ein Zwei-Einträge-
   Menü (PDF/Markdown) statt direkt zu exportieren – kleiner Chevron-Indikator
   unten rechts am Icon signalisiert "hier klappt etwas auf", ohne ein zweites
   Knopf-Element in der engen Symbolleiste zu brauchen. */
.notes-export-menu-btn {
  position: relative;
}
.notes-export-menu-btn::after {
  content: '';
  position: absolute;
  right: 3px;
  bottom: 3px;
  width: 5px;
  height: 5px;
  border-right: 1.5px solid var(--text-tertiary);
  border-bottom: 1.5px solid var(--text-tertiary);
  transform: rotate(45deg);
  pointer-events: none;
}

/* Edit-Modus, MOBIL: Titel + Workspace nebeneinander statt gestapelter
   ds-form-row (mehr Schreibfläche für den Editor darunter). Seit Ticket
   3.367.3 nur noch mobil – Desktop hat Titel+Workspace in die Toolbar
   verschoben (.notes-header-title-ws, s.u.), Mobil bleibt unverändert. */
.notes-header-fields-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .625rem 0;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0; /* Ticket 3.196.1 – Geschwister von .notes-panel-header, gleiche Regel */
}
.notes-header-fields-row .input  { flex: 1.6; min-width: 0; }
.notes-header-fields-row .select { flex: 1;   min-width: 0; }

/* Ticket 3.367.3 (Desktop, Edit-Modus): Titel + durchsuchbare Workspace-
   Auswahl im freien Mittelbereich der Toolbar – ersetzt dort den
   .ds-toolbar-spacer. Kompakte 32px-Optik passend zu den umgebenden
   .ds-toolbar-item-Knoepfen (Standard .input/.select bringen 44px). */
.notes-header-title-ws {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex: 1;
  min-width: 0;
}
.notes-header-title-input {
  flex: 1;
  /* Ticket 3.408.1: Mindestbreite statt 0 – bei zugeklappter Kopfzeile rücken
     ein weiterer Speichern-Knopf + Export in dieselbe Zeile, das Titelfeld
     schrumpft dadurch automatisch (.ds-panel-toolbar ist flex-wrap:wrap), soll
     aber auf einem schmalen Fenster nie auf Null zusammenfallen. */
  min-width: 96px;
  height: 32px;
  min-height: 32px;
  padding: 0 .625rem;
  font-size: .8125rem;
  overflow: hidden;
  text-overflow: ellipsis;
}
.notes-header-ws-select {
  flex: 0 0 auto;
  min-width: 190px;
  max-width: 260px;
}
.notes-header-ws-select .ss-trigger {
  height: 32px;
  min-height: 32px;
  padding: 0 .625rem;
  font-size: .8125rem;
}

/* Vorschau-Verbergen- + API-Ausschließen-Toggle-Zeile (unter der Titel-/
   Workspace-Zeile) – Layout analog .ds-bookkeeping-tx-panel-row
   (bookkeeping.js). Seit Ticket 3.425 trägt diese EINE Zeile BEIDE Schalter
   (vorher zwei gestapelte Zeilen, s. `.notes-toggle-pair` + Kopfkommentar in
   note-editor.js) – `flex-wrap` lässt sie auf schmalen Bildschirmen
   untereinander fallen, ohne dass dafür eine zweite Media-Query-Struktur
   nötig ist (Ziel ist Desktop, schmal bleibt nutzbar). */
.notes-preview-hidden-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .375rem 1.25rem;
  padding: .625rem 0;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0; /* Ticket 3.196.1 – s. .notes-panel-header */
}
/* Ein Schalter + sein Label als untrennbares Paar (Ticket 3.425) – bricht
   die Zeile nur ZWISCHEN den Paaren um, nie mitten in einem. */
.notes-toggle-pair {
  display: flex;
  align-items: center;
  gap: .625rem;
  flex-shrink: 0;
}
.notes-preview-hidden-label {
  font-size: .8125rem;
  color: var(--text-secondary);
}
/* Ticket 3.367.3 (Desktop): beschrifteter Speichern-Knopf rechtsbündig in
   derselben Zeile wie die Schalter – margin-left:auto reicht, da die
   vorangehenden Kinder (`.notes-toggle-pair`) links stehenbleiben. */
.notes-save-btn-row {
  margin-left: auto;
}

/* Ticket 3.393.4: Notiz von der Notizen-Schnittstelle ausnehmen –
   eigene Zeile unter dem Vorschau-Verbergen-Schalter, weil der Erklärsatz
   zweizeilig ist (Toggle + Label bleiben oben ausgerichtet statt zentriert). */
.notes-api-excluded-row {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
  padding: .625rem 0;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.notes-api-excluded-row .ds-theme-toggle {
  margin-top: .125rem;
}
.notes-api-excluded-label {
  display: flex;
  flex-direction: column;
  gap: .1875rem;
  font-size: .8125rem;
  color: var(--text-secondary);
}
.notes-api-excluded-hint {
  font-size: .75rem;
  line-height: 1.4;
  color: var(--text-tertiary);
}
/* 🔒 Mobile-Override MUSS nach der Basisregel stehen (s. "Eine Media-Query
   erhöht die Spezifität NICHT" oben in diesem File) – die frühere
   Gruppen-Regel weiter oben (.notes-header-fields-row/-preview-hidden-row/
   -api-excluded-row { padding-left/right:1rem }) steht VOR dieser Basisregel
   und wird von deren padding-Shorthand (padding:.625rem 0, setzt links/rechts
   auf 0) überschrieben – für diese neue Zeile hier eigens nachgezogen. */
@media (max-width: 900px) {
  .notes-api-excluded-row {
    padding-left: 1rem;
    padding-right: 1rem;
  }
}



/* ── Notes: Mobile ──────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .notes-layout { display: block; overflow: visible; height: auto; }
  .notes-sidebar-toggle { display: none; }
  /* padding-top:0 – die "≡ Notizbücher"-Navbar (erstes Kind) dockt bündig
     an die weisse App-Leiste an (nav.css .ds-content-body:has(page-notes)
     gibt zusätzlich das Body-Padding oben frei). Seitliches/unteres
     Polster bleibt für den restlichen Content erhalten. */
  .notes-main   { padding: 0 .75rem .75rem; gap: .5rem; }
  /* Navbar selbst bleedet über das .notes-main-Seitenpolster hinaus, damit
     ihre border-bottom die volle Bildschirmbreite spannt (wie bei Todos, wo
     die Navbar top-level statt in einem gepolsterten Container sitzt) –
     Innen-Padding hält Button/Label auf der Content-Fluchtlinie. */
  page-notes .notes-main > .ds-mobile-navbar {
    margin-left: -.75rem;
    margin-right: -.75rem;
    padding-left: .75rem;
    padding-right: .75rem;
  }
  .notes-list   { grid-template-columns: 1fr; }
  /* H1 auf Mobile ausblenden – App-Shell liefert den Seitentitel */
  page-notes .page-header h1    { display: none; }
  /* Page-Header-Actions nur als FAB sichtbar – Header-Button ausblenden */
  page-notes .page-header-actions { display: none; }
  /* Offline-Banner auf Mobile: Text kann umbrechen, kein Overflow */
  .notes-offline-banner { flex-wrap: wrap; font-size: .8125rem; }
  .notes-offline-banner-text { flex: 1; min-width: 0; }
  /* Ticket 3.97: dieselbe Umbruch-Regel für die "sichtbar aufgegeben"-Zeile */
  .notes-offline-failed { flex-wrap: wrap; font-size: .8125rem; }
  .notes-offline-failed-text { flex: 1; min-width: 0; }
}

/* ── Notes: Offline ──────────────────────────────────────────────────── */

.notes-offline-banner {
  display: flex;
  align-items: center;
  gap: .5rem;
  background: var(--amber-light);
  color: var(--amber);
  font-size: .875rem;
  font-weight: 500;
  padding: .625rem 1rem;
  border-radius: var(--radius-sm);
  margin-bottom: 1rem;
  line-height: 1.4;
}

.notes-offline-banner svg {
  flex-shrink: 0;
  color: var(--amber);
}

.notes-offline-banner-text {
  flex: 1;
  min-width: 0;
}

.notes-offline-banner-count {
  flex-shrink: 0;
  font-size: .8125rem;
  font-weight: 600;
  background: var(--amber);
  color: #fff;
  padding: .125rem .5rem;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}

/* Ticket 3.97 (Notizen offline: Bilder nachträglich hochladen) – sichtbar
   aufgegebenes Offline-Bild (nach mehreren Fehlversuchen). Eigener Ton
   (--danger statt --amber): das ist kein "wartet noch"-Zustand mehr, sondern
   ein Ergebnis, das eine Nutzer-Entscheidung braucht (Bild sichern). Rendert
   UNABHAENGIG vom Online-Status, s. NotesOfflineController.renderBanner(). */
.notes-offline-failed {
  display: flex;
  align-items: center;
  gap: .5rem;
  background: var(--danger-light);
  color: var(--danger);
  font-size: .875rem;
  font-weight: 500;
  padding: .625rem 1rem;
  border-radius: var(--radius-sm);
  margin-bottom: .5rem;
  line-height: 1.4;
}

.notes-offline-failed svg {
  flex-shrink: 0;
  color: var(--danger);
}

.notes-offline-failed-text {
  flex: 1;
  min-width: 0;
}

.notes-offline-failed-save {
  flex-shrink: 0;
  font-size: .8125rem;
  font-weight: 600;
  background: var(--danger);
  color: #fff;
  border: none;
  padding: .3rem .75rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
}

.notes-offline-failed-save:hover {
  opacity: .85;
}

/* Pending-Modifier auf der Note-Card */
.notes-card--pending {
  position: relative;
  border-left: 3px solid var(--amber) !important; /* sichtbar gegen modul-eigene Border-Left-Varianten */
}

/* Amber-Dot oben rechts auf der Card */
.notes-card-pending-dot {
  position: absolute;
  top: .625rem;
  right: .625rem;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--amber);
  animation: notes-pending-pulse 1.8s ease-in-out infinite;
}

@keyframes notes-pending-pulse {
  0%, 100% { opacity: 1;   transform: scale(1); }
  50%       { opacity: .45; transform: scale(.8); }
}

/* Sync-Spinner-Indikator während _flushing = true */
.notes-sync-indicator {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  font-size: .8125rem;
  color: var(--text-tertiary);
}

.notes-sync-indicator svg {
  animation: notes-spin 1s linear infinite;
}

@keyframes notes-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* ── Notes: Web-Read scrollt in der App-Content-Fläche (.ds-content-body),
   NIE in einem inneren Container (Spec 20260728, W1 Kopplung 1) – NUR
   readOnly + Web-Format. A4/A5-Read bleibt unverändert (jeder Selektor hier
   verlangt `:not(.ds-note-page-mode)` – matcht auf A4/A5 nie, die tragen
   immer `.ds-note-page-mode`). Bricht die Flex(column)/`overflow:hidden`/
   `min-height:0`-Kette auf, die A4/A5 bewusst nutzt um das Scrollen nach
   `.ql-container` zu verlagern (Mobile-Momentum/Pull-to-Refresh/Scroll-
   Position sollen im Web-Format an der normalen Seiten-Scrollfläche haengen,
   nicht an einem inneren Container).
   🔒 Ticket 3.196.1 haengt EIN weiteres Kettenglied OBERHALB an – die
   analoge `.ds-content-body:has(...)`-Ausnahme lebt aus Organisationsgruenden
   in `nav.css` (dort stehen ALLE `.ds-content-body`-Seiten-Overrides,
   inkl. der neuen Full-Bleed-Regel für page-note-editor selbst). Wer diese
   Kette anfasst: das Gegenstück dort nicht vergessen. */
.notes-editor-page-body:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  display: block;
  overflow: visible;
}
.ds-form-row--description:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  display: block;
  flex: none;
  min-height: 0;
}
.ds-form-row--description:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) .ds-form-row-content {
  display: block;
  flex: none;
  min-height: 0;
}
.notes-read-body:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  display: block;
  flex: none;
  min-height: 0;
}
ds-note-editor:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  display: block;
  flex: none;
  min-height: 0;
}
ds-note-editor:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) .ds-note-editor-row {
  flex: none;
  min-height: 0;
}
/* 🔒 .ds-note-editor-wrap bewusst NICHT auf flex:none gesetzt (Regression
   2026-07-28, live gefunden): der Wrap ist gleichzeitig Flex-ITEM von
   .ds-note-editor-row (flex-direction:row – hier bestimmt flex/min-width die
   BREITE) und selbst Flex-CONTAINER (column) für Toolbar+Body. Die Basis-
   Regel `.ds-note-editor-row .ds-note-editor-wrap{flex:1;min-width:0}`
   (weiter oben in dieser Datei) MUSS aktiv bleiben, sonst verweigert der Wrap
   das Schrumpfen auf die verfügbare Zeilenbreite (flex-basis:auto nimmt die
   ungebrochene Content-Breite als Basis, flex-shrink:0 verbietet das
   Zurückschrumpfen) → lange Fliesstext-Absaetze brechen nicht mehr um,
   der Wrap wird breiter als der Viewport. Die Hoehen-Kette ist bereits EINE
   Ebene hoeher (an `.ds-note-editor-row` oben) durchbrochen – hier ist kein
   weiterer Eingriff nötig oder sicher. */
.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode) .ql-container.ql-snow,
.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode) .ds-note-editor-body {
  flex: none;
  overflow: visible;
  height: auto;
}

/* ── Notes: Web-Read + Seitenleiste (Notiz-Liste ODER Aufgaben) — Re-Fix
   Ticket 3.419: die Leiste reichte nicht immer bis nach unten ─────────────
   Web-Read bricht oben BEWUSST die begrenzte Hoehen-Kette auf, damit eine
   lange Notiz normal im Dokument scrollt. Ist dabei eine der beiden
   Seitenleisten sichtbar (`page-note-editor.has-note-list-sidebar`/
   `.has-task-sidebar`), zerstoert genau das ihre Vollhoehe: `.ds-content-
   body` (nav.css) faellt auf `display:block` zurueck, `page-note-editor`
   (Flex-Zeile) bekommt dadurch keine begrenzte Hoehe mehr durchgereicht und
   schrumpft auf die Inhaltshoehe der Notiz — bei kurzem Text bleibt darunter
   grauer Leerraum (Domenico-Screenshot, 02.09.2026). Reproduziert per
   Puppeteer: `.ds-content-body` computed `display:block` bei einer kurzen
   Web-Notiz mit offener Notiz-Listen-Leiste, exakt der gemeldete Zustand.
   Fix: mit sichtbarer Seitenleiste verhaelt sich Web-Read wieder wie
   Edit-Mode/A4/A5 — begrenzte Zeilen-Hoehe, Scroll wandert zurueck in
   `.ql-container` (dieselbe, bereits ueberall sonst funktionierende Kette).
   Jede Regel hier hebt EXAKT eine der Web-Read-Regeln oben (+ die nav.css-
   Regel) wieder auf, mit den Werten der jeweiligen unconditional Basisregel
   — Selektor-Paare bewusst nebeneinander gehalten zum Nachvollziehen.
   🔒 Hoehere Spezifitaet (zusaetzliche `page-note-editor`-Klasse im
   Selektor) gewinnt unabhaengig von der Ladereihenfolge gegen nav.css UND
   gegen die generischen Web-Read-Regeln oben — kein `!important` noetig. */
.ds-content-body:has(page-note-editor:is(.has-note-list-sidebar, .has-task-sidebar)):has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
page-note-editor:is(.has-note-list-sidebar, .has-task-sidebar) .notes-editor-page-body:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  display: flex;
  overflow: hidden;
}
page-note-editor:is(.has-note-list-sidebar, .has-task-sidebar) .ds-form-row--description:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  display: flex;
  flex: 1;
  min-height: 0;
}
page-note-editor:is(.has-note-list-sidebar, .has-task-sidebar) .ds-form-row--description:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) .ds-form-row-content {
  display: flex;
  flex: 1;
  min-height: 0;
}
page-note-editor:is(.has-note-list-sidebar, .has-task-sidebar) .notes-read-body:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  display: flex;
  flex: 1;
  min-height: 0;
}
page-note-editor:is(.has-note-list-sidebar, .has-task-sidebar) ds-note-editor:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  display: flex;
  flex: 1;
  min-height: 0;
}
page-note-editor:is(.has-note-list-sidebar, .has-task-sidebar) ds-note-editor:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) .ds-note-editor-row {
  flex: 1;
  min-height: 0;
}
page-note-editor:is(.has-note-list-sidebar, .has-task-sidebar) .ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode) .ql-container.ql-snow,
page-note-editor:is(.has-note-list-sidebar, .has-task-sidebar) .ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode) .ds-note-editor-body {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  height: auto;
}

/* ── Notes: Fix 4 – Read-Mode Toolbar-Hide + Mention-Klickbarkeit ───── */

/* .ds-note-editor--read auf dem wrap → Quill-Toolbar verstecken */
.ds-note-editor--read .ql-toolbar { display: none !important; }

/* Quill-Editor im Read-Mode: Border oben wieder zeigen (weil Toolbar weg) */
.ds-note-editor--read .ql-container { border-top: 1px solid #ccc; border-radius: var(--radius-sm); }

/* Dark Mode: Quill-Container-Border im Read-Mode (nur expliziter data-theme="dark"-Toggle) */
:root[data-theme="dark"] .ds-note-editor--read .ql-container { border-color: var(--border); }

/* Mention-Blots im Read-Mode klickbar halten (Quill deaktiviert pointer-events) */
.ds-note-editor--read .ql-editor .ql-mention {
  pointer-events: auto;
  cursor: pointer;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* A4/A5 Read-Mode (Aufgabe Read-Seitenansicht): der graue "Schreibtisch"-
   Canvas ist bereits vollstaendig vom .ds-note-editor-wrap umrandet – die
   generische Read-Mode-Top-Border oben (für eine schlichte Web-Format-
   Textanzeige gedacht) würde im Seitenmodus nur eine unnötige zweite Linie
   gegen den grauen Canvas ziehen. Rundet stattdessen die (durch die
   versteckte Toolbar sonst eckigen) oberen Ecken passend zum Wrap nach
   (var(--radius-md) statt der generischen --radius-sm oben). Höhere
   Spezifität (3 Klassen auf dem Ziel-Element) gewinnt unabhängig von der
   Reihenfolge gegen die generische Regel oben. */
.ds-note-editor-wrap.ds-note-page-mode.ds-note-editor--read .ql-container {
  border-top: none;
  border-radius: var(--radius-md);
}

/* Web-Read: derselbe Doppelrahmen-Fix wie A4/A5 oben – Toolbar ist per
   `.ds-note-editor--read .ql-toolbar{display:none}` weg, `.ql-container`
   bekaeme sonst eine zusätzliche Top-Border obendrauf zum bereits
   vorhandenen `.ds-note-editor-wrap`-Rahmen. */
.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode) .ql-container {
  border-top: none;
  border-radius: var(--radius-md);
}

/* Web-Read: großzügigerer Innenabstand statt der Editor-Kompaktwerte (A4-
   Ränder `--note-page-pad` gibt es hier nicht). Volle Breite bleibt
   (Domenico-Entscheid) – nur mehr Innenabstand. */
.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode) .ql-editor {
  padding: 1.5rem clamp(1rem, 4vw, 3rem);
}

/* Titel-Anzeige im Read-Mode – DEPRECATED (Aufgabe #1 Folge-Session): Desktop
   zeigte den Titel früher hier (gestapelte ds-form-row); der Titel lebt jetzt
   für Desktop UND Mobile in der konsolidierten .notes-panel-header-title-Zeile.
   CSS bleibt aus Rückwaerts-Kompatibilitaet, wird nicht mehr gerendert. */
.notes-title-read {
  font-size: 1rem;
  font-weight: 500;
  color: var(--text-primary);
  padding: .375rem 0;
  line-height: 1.4;
}

/* ── Notes: Bug 4 – Pin-Stern immer sichtbar ─────────────────────────────── */
/* Stern immer anzeigen: gedimmt wenn nicht angeheftet, amber wenn angeheftet */
.notes-card-star {
  flex-shrink: 0;
  color: var(--text-tertiary);
  cursor: pointer;
  padding: .125rem;
  border-radius: var(--radius-sm);
  transition: color var(--transition), opacity var(--transition);
  line-height: 0;
  /* Verhindert Cursor-Übertragung auf die gesamte Card */
  pointer-events: auto;
}
.notes-card-star:hover         { color: var(--amber); }
.notes-card-star--pinned       { color: var(--amber); }

/* Ticket 3.393.4: unaufdringliches Schloss-Zeichen für "von der Notizen-
   Schnittstelle ausgenommen" – reine Anzeige, kein eigener Klick-Handler. */
.notes-card-api-excluded {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  color: var(--text-tertiary);
  padding: .125rem;
  line-height: 0;
}


/* ── Notes: Bug 6 – Read-Mode Markdown-HTML ──────────────────────────────── */
/* Wrapper für das Read-Mode-Body – nimmt den gesamten verfügbaren Raum.
   display:flex/flex-direction:column (Aufgabe Read-Seitenansicht, s.o.):
   nötig damit eine geschachtelte readOnly <ds-note-editor> (A4/A5) ihre
   flex:1/min-height:0-Kette bis .ql-container geerbt bekommt und intern
   scrollen kann – sonst hätte .notes-editor-page-body zwar
   auf overflow:hidden umgeschaltet, der Seiteninhalt aber keinen Scroll-
   Mechanismus mehr (bei >1 DIN-Seite nicht mehr erreichbar). Seit Spec
   20260728 (W1) rendert der Read-Modus IMMER `<ds-note-editor readOnly>`
   (Web + A4/A5) oder – bei fehlendem/kaputtem Delta – den
   `.notes-plain-fallback`-Block; es gibt keinen separaten Markdown-Renderer
   mehr. Für Web-Read wird diese Flex-Kette gezielt wieder aufgebrochen
   (s. Regeln oben, `:not(.ds-note-page-mode)`) – Dokument-Scroll statt
   innerem Container. */
.notes-read-body {
  flex: 1;
  min-height: 200px;
  padding: .5rem 0;
  cursor: default;
  display: flex;
  flex-direction: column;
  /* Doppelklick-Hinweis via title-Attribut – kein visual Indicator nötig */
}
.notes-read-body:hover {
  /* Subtiler Hinweis dass Doppelklick editiert */
  opacity: .97;
}

/* Plaintext-Fallback wenn kein gültiges Quill-Delta vorliegt (Alt-Notizen
   ohne body, kaputte Offline-Drafts) – Spec 20260728 W1 Kopplung 2. */
.notes-plain-fallback {
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--text-primary);
  font-size: .9rem;
  line-height: 1.6;
  padding: .5rem 0;
}

/* ── Notes: Änderung 2 – Pin-Stern-Icon vor dem Titel ───────────────────── */
/* Kleiner Icon-Only-Button ohne Button-Optik – ersetzt ICON_TEXT Burger */
.notes-pin-icon {
  background: transparent;
  border: 0;
  padding: .25rem;
  color: var(--text-tertiary);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
  flex-shrink: 0;
}
.notes-pin-icon:hover          { color: var(--amber); background: var(--amber-light); }
.notes-pin-icon.is-pinned      { color: var(--amber); }
.notes-pin-icon.is-pinned:hover { background: var(--amber-light); }

/* Editor-Seiten-Scroll-Container (B38 N3 – ersetzt die frühere
   page-notes/ds-cal-panel-Kopplung, jetzt eine eigene Seite).
   🔒 Ticket 3.196.1: flex:1/min-height:0 ergänzt – vorher besass dieser
   Container KEINE begrenzte Hoehe (die Kette zu .ds-content-body über
   page-note-editor fehlte komplett, s. nav.css "Notizen-Editor"), wodurch
   `overflow:hidden` wirkungslos blieb und stattdessen die GANZE Seite
   scrollte (Kopf-/Formatierungsleiste wanderten mit weg, der Seiten-
   Navigator konnte "+ Seite" nie an seine eigene Spalte pinnen). Padding
   ist NEU hier (vorher lieferte ausschließlich das jetzt genullte
   .ds-content-body-Padding den Innenabstand – ohne Ersatz hätte der
   komplette Editor nach dem Full-Bleed-Fix flach an den Viewport-Kanten
   geklebt) – Wert 1:1 wie der vorige `.ds-content-body`-Default UND wie
   `.todos-content` (page-todos.js), unconditional/nicht responsiv (gleiche
   Konvention). */
.notes-editor-page-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  padding: 1.5rem;
  overflow: hidden; /* Scroll-Verantwortung an ql-container übergeben */
}

/* Mobile (Ticket 3.401.2): kein Karten-Rahmen mehr – MUSS nach der Basisregel
   stehen (s. Kommentar bei „Notes: Mobile – eine Kopfzeile" weiter oben). */
@media (max-width: 900px) {
  .notes-editor-page-body {
    padding: 0;
  }
}

/* ds-note-editor selbst muss als Flex-Kind wachsen */
ds-note-editor {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/* Quill-Editor-Body erhält flex:1 – wird durch .ds-note-editor-wrap (schon flex) durchgereicht */
.ds-note-editor-wrap .ql-container.ql-snow {
  flex: 1;
  overflow-y: auto;
}

/* ── Notes: Workspace-Settings-Page Mobile ────────────────────────────── */
@media (max-width: 900px) {
  /* H1 ausblenden – App-Shell liefert Seitentitel */
  page-notes-workspaces .page-header h1    { display: none; }
  /* Header-Button ausblenden – FAB übernimmt */
  page-notes-workspaces .page-header-actions { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   Notes: Web-Read Darstellung vollstaendig (Spec 20260728, W2 / Teil B)
   ══════════════════════════════════════════════════════════════════════
   Nach W1 (Renderer vereinheitlicht – Web-Read nutzt immer
   <ds-note-editor readOnly>) rendern Überschriften, fett/kursiv/
   unterstrichen/durchgestrichen, Listen (inkl. Verschachtelung), Zitate,
   Links, Mentions, Bilder und align/color/size bereits automatisch korrekt
   aus dem globalen quill.snow.min.css (app/index.php). Hier nur die Lücken:
   Tabellen-Zellrahmen, Task-Listen-Farbe/Daempfung, Seitenumbruch im
   Web-Read als reine Trennlinie, Code-Block-/Blockquote-Feinschliff. Alle
   Regeln gescopt auf .ds-note-editor-wrap .ql-editor (Notiz-Editor-Kontext
   – betrifft NICHT ds-rich-editor/NDA-Editor). */

/* 1. Tabellen-Styling (der eigentliche Fix für Symptom 3). Quills
   eingebautes Table-Modul erzeugt echte <table><tbody><tr><td> – es gibt
   KEIN <th> (kein Header-Zeilen-Konzept im Blot), Header-Optik wird daher
   über tr:first-child simuliert. quill.snow.min.css setzt
   table-layout:fixed;width:100% (Spalten immer gleichmaessig verteilt,
   kein natuerliches Überlaufen) UND td{border:1px solid #000} (hart-
   codiertes Schwarz, kein Light/Dark-Support) – beides wird überschrieben:
   table-layout:auto;width:auto macht die Tabelle so breit wie ihr Inhalt
   braucht; display:block+overflow-x:auto macht das <table>-Element selbst
   zum horizontal scrollbaren Block bei Überbreite (Mobile UND Desktop,
   kein zusätzlicher @media-Block nötig – greift automatisch). Farben
   ausschließlich aus CSS-Variablen – Light UND Dark automatisch korrekt. */
.ds-note-editor-wrap .ql-editor table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  table-layout: auto;
  width: auto;
  border-collapse: collapse;
  margin: .5rem 0;
}
/* Ticket 3.196.3 – Tabellen-Zeilen-Pagination (A4/A5): border-collapse:collapse
   zusammen mit transform auf <tr> (s. ds-note-editor.js _splitTableAcrossPages())
   erzeugt einen Chromium-Renderartefakt – verwaiste Rahmen-Fragmente einer
   vorangehenden, jetzt wegverschobenen Zeile "bluten" sichtbar in den PAD-Bereich
   der neuen Seite (kein DOM-Element sitzt dort, rein paint-seitig, empirisch per
   Screenshot + elementFromPoint verifiziert). border-collapse:separate +
   border-spacing:0 beseitigt den Effekt restlos und ist für eine Tabelle ohne
   Rowspan visuell nicht von collapse zu unterscheiden (Vergleichs-Screenshots
   außerhalb der Split-Grenze deckungsgleich). Klasse wird NUR von JS auf
   Tabellen gesetzt, die tatsächlich zeilenweise gesplittet wurden – alle
   anderen (klein genug für eine Seite, Web-Format) bleiben unangetastet. */
.ds-note-editor-wrap .ql-editor table.ds-note-table-split {
  border-collapse: separate;
  border-spacing: 0;
}
.ds-note-editor-wrap .ql-editor th,
.ds-note-editor-wrap .ql-editor td {
  border: 1px solid var(--border);
  padding: .4rem .6rem;
  min-width: 80px;
  vertical-align: top;
}
.ds-note-editor-wrap .ql-editor tr:first-child td,
.ds-note-editor-wrap .ql-editor th {
  background: var(--bg-secondary);
  font-weight: 600;
}

/* 2. Task-Listen-Styling. Quill erzeugt Task-Listen automatisch über
   "[ ]"/"[x]"+Leerzeichen (kein Toolbar-Button nötig) als
   <li data-list="checked">/<li data-list="unchecked">. Die Checkbox-
   Glyphen (☑/☐) kommen bereits aus quill.snow.min.css
   (li[data-list]>.ql-ui:before), hartcodiert color:#777 – hier nur Farbe
   (CSS-Variable) + Daempfung erledigter Einträge. Im readOnly-Modus setzt
   Quill .ql-disabled auf .ql-container → die Checkbox ist dort bereits
   automatisch nicht-klickbar (quill.snow.min.css), kein zusätzliches CSS
   nötig. */
.ds-note-editor-wrap .ql-editor li[data-list="checked"] > .ql-ui:before,
.ds-note-editor-wrap .ql-editor li[data-list="unchecked"] > .ql-ui:before {
  color: var(--accent);
}
.ds-note-editor-wrap .ql-editor li[data-list="checked"] {
  color: var(--text-tertiary);
  text-decoration: line-through;
}

/* 3. Seitenumbruch im Web-Read nur als dezente Trennlinie – keine
   Bedienelemente. Der manuelle Seitenumbruch-Blot (.ds-note-break-blot)
   rendert immer Label + Hoch/Quer-Toggle + Löschen-Button (statisches
   create(), kein Modus-Bewusstsein – s. ds-note-editor.js
   _registerPageBreakBlot). Im Web-Read (seit W1 überhaupt erst sichtbar
   – der entfernte notes-md-view-Renderer hat ihn vorher stillschweigend
   verschluckt) sollen nur Trennlinie + Label sichtbar sein. Beide
   Bedienelemente sitzen im selben .ds-note-break-blot-orient-Wrapper-Span
   – ein Selektor genuegt. A4/A5-Read bleibt unverändert (Selektor
   verlangt :not(.ds-note-page-mode), matcht dort nie). */
.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode) .ds-note-break-blot-orient {
  display: none;
}

/* 4. Code-Block-Feinschliff (optional – Syntax-Highlighting ist bewusst
   out of scope, modules/syntax ist nicht aktiviert). Basis-Optik
   (dunkler Block, monospace, funktioniert in Light UND Dark) kommt
   bereits aus quill.snow.min.css – nur Radius/Overflow an den App-Stil
   angeglichen (langer Code läuft horizontal statt den Layout zu
   brechen). */
.ds-note-editor-wrap .ql-editor .ql-code-block-container {
  border-radius: var(--radius-sm);
  overflow-x: auto;
}

/* 5. Blockquote-Akzentfarbe (optional – Konsistenz zur entfernten
   notes-md-blockquote-Optik, die border-left:3px solid var(--accent)
   nutzte). quill.snow.min.css setzt hartcodiert border-left:4px solid
   #ccc – hier nur Farbe/Textfarbe überschrieben. */
.ds-note-editor-wrap .ql-editor blockquote {
  border-left-color: var(--accent);
  color: var(--text-secondary);
}


/* ══════════════════════════════════════════════════════════════════════
   Aufgaben-Seitenleiste im Notiz-Editor (Ticket 3.367.6)
   ══════════════════════════════════════════════════════════════════════ */

/* `page-note-editor` bleibt via nav.css EIN einzelnes Kind ("flex-direction:
   column") – diese Klasse (von note-editor.js `updated()` getoggelt) kippt
   NUR für diese Seite auf "row", damit die Aside neben `.notes-editor-page-
   body` steht. Selektor-Spezifität (.ds-content-body > page-note-editor
   .has-task-sidebar = 0,2,1) schlaegt nav.css' `.ds-content-body >
   page-note-editor` (0,1,1) UNABHAENGIG von der Ladereihenfolge – nav.css
   selbst bleibt unangetastet (außerhalb des Änderungs-Scopes). */
.ds-content-body > page-note-editor.has-task-sidebar {
  flex-direction: row;
}
page-note-editor.has-task-sidebar .notes-editor-page-body {
  min-width: 0;
}
/* Web-Read-Sonderfall (Ticket 3.196.1, s. Kommentar weiter oben in dieser
   Datei): `.notes-editor-page-body` wechselt dort auf `display:block;
   flex:none` (Dokument-Scroll statt innerem Scroll). `flex:none` würde die
   Spalte in einer Zeilen-Anordnung auf ihre Inhaltsbreite schrumpfen lassen
   – hier gezielt wieder auf volle Breite gestellt, OHNE das `display:block`
   selbst zu berühren (Scroll-Verhalten bleibt exakt wie vorher). */
page-note-editor.has-task-sidebar .notes-editor-page-body:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  flex: 1 1 0%;
}

/* Ticket 3.419.1: identisches Muster für die LINKE Notiz-Listen-Leiste –
   beide Klassen können gleichzeitig aktiv sein (Aufgaben-Aside rechts,
   Notiz-Liste links), `flex-direction: row` wird dann zweimal auf denselben
   Wert gesetzt (kein Konflikt). */
.ds-content-body > page-note-editor.has-note-list-sidebar {
  flex-direction: row;
}
page-note-editor.has-note-list-sidebar .notes-editor-page-body {
  min-width: 0;
}
page-note-editor.has-note-list-sidebar .notes-editor-page-body:has(.ds-note-editor-wrap.ds-note-editor--read:not(.ds-note-page-mode)) {
  flex: 1 1 0%;
}

.notes-task-sidebar {
  flex: 0 0 280px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-left: 1px solid var(--border);
  background: var(--bg-primary);
  overflow-y: auto;
}
.notes-task-sidebar.is-collapsed {
  flex-basis: 44px;
  overflow: visible;
}

.notes-task-sidebar-head {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: 1rem 1rem .5rem;
  flex-shrink: 0;
}
.notes-task-sidebar.is-collapsed .notes-task-sidebar-head {
  padding: 1rem .5rem;
  justify-content: center;
}
.notes-task-sidebar-title {
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-primary);
  flex: 1;
}
.notes-task-sidebar-toggle {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  color: var(--text-secondary);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.notes-task-sidebar-toggle:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.notes-task-sidebar-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.notes-task-sidebar-empty {
  padding: .5rem 1rem 1rem;
  font-size: .8125rem;
  color: var(--text-tertiary);
  line-height: 1.5;
}
.notes-task-sidebar-empty p { margin: 0 0 .5rem; }
.notes-task-sidebar-empty-link {
  border: none;
  background: none;
  padding: 0;
  color: var(--accent);
  font-size: .8125rem;
  font-weight: 600;
  cursor: pointer;
}
.notes-task-sidebar-empty-link:hover { text-decoration: underline; }
.notes-task-sidebar-empty-inline {
  margin: 0;
  padding: .25rem 1rem;
  font-size: .8125rem;
  color: var(--text-tertiary);
}

.notes-task-sidebar-list {
  display: flex;
  flex-direction: column;
  gap: .125rem;
  padding: 0 .5rem;
}

/* Ticket 3.408.3: generischer Abschnitts-Rahmen – Aufgaben (`--tasks`-
   Modifier, aktuell ohne eigene Regeln, Erweiterungspunkt) + Personen/Firmen/
   Projekte teilen sich denselben Kopf-Stil (Icon+Titel+Zähler). Ein
   künftiger Abschnitt (Anhänge, Termine) reiht sich hier ein, ohne diese
   Regeln zu ändern. */
.notes-task-sidebar-sections {
  display: flex;
  flex-direction: column;
  padding-bottom: .5rem;
}
.notes-linked-section {
  padding: .75rem 0;
  border-top: 1px solid var(--border);
}
.notes-linked-section:first-child {
  padding-top: 0;
  border-top: none;
}
.notes-linked-section-head {
  display: flex;
  align-items: center;
  gap: .375rem;
  padding: 0 1rem;
  margin-bottom: .375rem;
  color: var(--text-tertiary);
}
.notes-linked-section-title {
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
}
.notes-linked-section-count {
  margin-left: auto;
  padding: .0625rem .375rem;
  border-radius: 999px;
  background: var(--bg-secondary);
  font-size: .7rem;
  font-weight: 600;
  color: var(--text-secondary);
}
.notes-linked-section-list {
  display: flex;
  flex-direction: column;
  gap: .125rem;
  padding: 0 .5rem;
}
.notes-linked-item {
  display: block;
  padding: .375rem .5rem;
  border-radius: var(--radius-sm);
  font-size: .8125rem;
  color: var(--text-primary);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: background var(--transition);
}
.notes-linked-item:hover {
  background: var(--bg-secondary);
  text-decoration: underline;
}
.notes-linked-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.notes-task-sidebar-list--done { margin-top: .25rem; }

.notes-task-item {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  padding: .5rem .5rem;
  border-radius: var(--radius-sm);
}
.notes-task-item:hover { background: var(--bg-secondary); }

.notes-task-check {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  margin-top: .0625rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid var(--border);
  border-radius: 50%;
  background: var(--bg-primary);
  color: var(--bg-primary);
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.notes-task-check:hover:not(:disabled) { border-color: var(--accent); }
.notes-task-check:disabled { cursor: not-allowed; opacity: .5; }
.notes-task-check.is-checked {
  background: var(--accent);
  border-color: var(--accent);
}

.notes-task-item-body {
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .125rem;
}
.notes-task-item-title {
  display: flex;
  align-items: center;
  gap: .375rem;
  min-width: 0;
  border: none;
  background: none;
  padding: 0;
  text-align: left;
  font-size: .8125rem;
  color: var(--text-primary);
  cursor: pointer;
}
.notes-task-item-title:hover .notes-task-item-title-text { text-decoration: underline; }
.notes-task-item-title-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.notes-task-item.is-done .notes-task-item-title-text {
  color: var(--text-tertiary);
  text-decoration: line-through;
}
.notes-task-priority-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
}
.notes-task-item-due {
  font-size: .7rem;
  color: var(--text-tertiary);
}
.notes-task-item-due.is-overdue { color: var(--coral); }

.notes-task-sidebar-done {
  margin-top: .25rem;
  padding: 0 .5rem .5rem;
}
.notes-task-sidebar-done-toggle {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  border: none;
  background: none;
  padding: .375rem .5rem;
  color: var(--text-secondary);
  font-size: .78125rem;
  font-weight: 600;
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.notes-task-sidebar-done-toggle:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}

/* Mobile: Ticket 3.408.4 – der frühere schwebende Aufgaben-Reiter
   (`.notes-task-tab`) ist entfallen (ein Zugang statt zwei: die Aside ist
   jetzt ausschließlich über das Mehr-Menü der mobilen Kopfzeile
   erreichbar, s. `_note-editor-mobile-header.js` + `_notes-task-sidebar.js`
   `toggleMobileDrawer()`). Der Drawer selbst (`.ds-drawer`/`.ds-drawer--right`)
   ist ein geteiltes, app-weites Pattern (s. frontend.md) – braucht hier
   keine eigene Media-Query mehr. */
@media (max-width: 900px) {
  .notes-task-sidebar { display: none; }
  .notes-task-sidebar-body { padding-bottom: 1rem; }
}

/* ── ds-note-api-keys – API-Key-Verwaltung der Notizen-API (Ticket 3.393.3) ─
   Modul-eigene Analogie zu `.todo-api-*` (_todos.css) – eigene Klassen statt
   Wiederverwendung, damit die Klassennamen im DevTools zum Modul passen; das
   Muster selbst (Card/Scope-Toggle/Docs-Details) ist bewusst identisch. */
.notes-api-keys-wrap { padding: 0.25rem 0 1.5rem; }
.notes-api-intro-text { font-size: 0.875rem; color: var(--text-secondary); margin: 0 0 1.25rem; }
.notes-api-create-trigger { margin-bottom: 1.25rem; }
.notes-api-empty-text { color: var(--text-secondary); padding: 1rem 0; font-size: 0.9rem; }
.notes-api-required { color: var(--coral); }

.notes-api-newkey-card { border: 2px solid var(--teal); margin-bottom: 1.5rem; }
.notes-api-newkey-title { font-weight: 600; margin-bottom: 0.5rem; }
.notes-api-newkey-code {
  display: block;
  padding: 0.75rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  word-break: break-all;
  margin-bottom: 0.75rem;
}
.notes-api-newkey-warn { color: var(--amber); font-size: 0.875rem; margin-top: 0.75rem; }
.notes-api-newkey-close-btn { margin-top: 1rem; width: 100%; }
.notes-api-copy-icon { margin-right: 0.25rem; }

.notes-api-create-card { margin-bottom: 1.5rem; }
.notes-api-create-title { font-weight: 600; }

.notes-api-scope-all-group { margin: 0.75rem 0 1rem; }
.notes-api-scope-all-warn { margin-top: 0.5rem; }
.notes-api-scope-hint-text { margin-top: 0.375rem; }

.notes-api-scopes { margin-top: 1rem; }
.notes-api-scope-row { display: flex; align-items: flex-start; gap: 0.75rem; padding: 0.5rem 0.25rem; }
.notes-api-scope-row + .notes-api-scope-row { border-top: 1px solid var(--border); }
.notes-api-scope-text { display: flex; flex-direction: column; gap: 0.1rem; }
.notes-api-scope-label { font-weight: 600; font-size: 0.875rem; color: var(--text-primary); }
.notes-api-scope-desc { font-size: 0.78rem; color: var(--text-secondary); }
.notes-api-scope-warn { color: var(--coral); font-size: 0.8rem; margin: 0.5rem 0.25rem 0; }
.notes-api-scope-hint {
  font-size: 0.78rem;
  color: var(--text-tertiary);
  margin: 0.75rem 0.25rem 0;
  line-height: 1.5;
}
.notes-api-scope-none { color: var(--text-tertiary); }
.notes-api-scope-badges { display: flex; flex-wrap: wrap; gap: 0.25rem; }

.notes-api-actions-row { display: flex; gap: 0.5rem; margin-top: 1rem; }
.notes-api-actions-primary { flex: 1; }

.notes-api-table-wrap { margin-bottom: 1.5rem; }
.notes-api-cell-label { font-weight: 500; }
.notes-api-cell-muted { color: var(--text-secondary); font-size: 0.875rem; }
.notes-api-prefix-code {
  font-size: 0.8rem;
  background: var(--bg-secondary);
  padding: 0.15rem 0.4rem;
  border-radius: var(--radius-sm);
}

.notes-api-revoke-cell { padding: 0; }
.notes-api-revoke-card { border: 1px solid var(--coral); margin-bottom: 0.75rem; }
.notes-api-revoke-title { font-weight: 600; margin-bottom: 0.5rem; }
.notes-api-revoke-text { font-size: 0.875rem; color: var(--text-secondary); margin-bottom: 0.75rem; }
.notes-api-revoke-confirm-label { font-size: 0.875rem; margin-bottom: 0.5rem; }
.notes-api-revoke-actions { display: flex; gap: 0.5rem; margin-top: 0.75rem; }

.notes-api-docs { margin-top: 1.5rem; }
.notes-api-docs-summary {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  cursor: pointer;
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--text-primary);
  list-style: none;
}
.notes-api-docs-summary::-webkit-details-marker { display: none; }
.notes-api-docs-summary-chevron { transition: transform var(--transition); flex-shrink: 0; }
.notes-api-docs[open] .notes-api-docs-summary-chevron { transform: rotate(90deg); }
.notes-api-docs-body { margin-top: 1rem; display: flex; flex-direction: column; gap: 1.25rem; }
.notes-api-docs-section-title {
  font-weight: 600;
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-tertiary);
  margin: 0 0 0.5rem;
}
.notes-api-docs-text { font-size: 0.875rem; color: var(--text-secondary); line-height: 1.55; margin: 0 0 0.5rem; }
.notes-api-docs-text code {
  font-size: 0.8rem;
  background: var(--bg-secondary);
  padding: 0.1rem 0.3rem;
  border-radius: var(--radius-sm);
}
.notes-api-docs-table-wrap { margin: 0 0 0.5rem; }
.notes-api-docs-table-wrap code { font-size: 0.8125rem; }

/* ══════════════════════════════════════════════════════════════════════
   Notiz-Listen-Leiste im Notiz-Editor (Ticket 3.419.1) – Desktop-only,
   links im Notiz-Editor. Kollaps-Mechanik + Masse identisch zur Aufgaben-
   Seitenleiste (`.notes-task-sidebar`, s.o.) – gespiegelt auf die linke
   Seite (border-right statt border-left).
   ══════════════════════════════════════════════════════════════════════ */

.notes-list-sidebar {
  flex: 0 0 240px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--border);
  background: var(--bg-primary);
  overflow: hidden; /* Kopf + Filter bleiben fix, nur .notes-list-sidebar-body scrollt */
}
/* 🔒 Korrektur zu Ticket 3.424 (Ticket 3.426): der Kopf-Pfeil (`.notes-list-
   sidebar-toggle`) navigiert seit 3.424 zur Notizenübersicht — das bleibt
   so. Das EIN-/AUSKLAPPEN der Leiste selbst (von Domenico im 3.419-Re-Fix
   ausdrücklich bestätigt, Vorbild `_notes-task-sidebar.js`) ist ein
   EIGENER, unabhängiger Schalter (`.notes-list-sidebar-collapse-toggle`) —
   die Ticket-Zeile "Pfeil und Kreuz rufen dieselbe Funktion" beantwortete
   nur, WAS der Pfeil tut, nicht dass das Zuklappen entfallen darf. */
.notes-list-sidebar.is-collapsed {
  flex-basis: 44px;
}

.notes-list-sidebar-head {
  display: flex;
  align-items: center;
  gap: .375rem;
  padding: 1rem .75rem .5rem 1rem;
  flex-shrink: 0;
}
.notes-list-sidebar.is-collapsed .notes-list-sidebar-head {
  padding: 1rem .5rem;
  justify-content: center;
}
/* Root-Drop-Ziel des Ordner-Baums (Ticket 3.419.2, "zurück auf oberste
   Ebene") – der Kopf ist als grosse, immer sichtbare Fläche das
   verlässlichste Ziel dafür, s. `_onRootDragOver`/`_onRootDrop`. NICHT
   aktiv im kollabierten Zustand (JS rendert dort keinen Drop-Handler mehr
   auf dem Kopf, s. render()). */
.notes-list-sidebar-head.is-drop-target {
  background: var(--accent-light);
  border-radius: var(--radius-sm);
}
/* Ticket 3.424: zeigt den Workspace-Namen statt "Notizen" – min-width:0 ist
   Pflicht, sonst ignoriert ein Flex-Kind text-overflow:ellipsis (der Text
   würde den Container stattdessen sprengen). */
.notes-list-sidebar-title {
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-primary);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.notes-list-sidebar-toggle,
.notes-list-sidebar-collapse-toggle,
.notes-list-sidebar-new {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  color: var(--text-secondary);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.notes-list-sidebar-toggle:hover,
.notes-list-sidebar-collapse-toggle:hover,
.notes-list-sidebar-new:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.notes-list-sidebar-toggle:focus-visible,
.notes-list-sidebar-collapse-toggle:focus-visible,
.notes-list-sidebar-new:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.notes-list-sidebar-filter-wrap {
  padding: 0 .75rem .5rem;
  flex-shrink: 0;
}
/* Kompakte Suchfeld-Optik (Muster .mail-search-input, _core.css) statt der
   44px hohen Formular-.input-Basisregel – ein Filterfeld in einer schmalen
   Leiste braucht keine Formularhöhe. */
.notes-list-sidebar-filter {
  width: 100%;
  min-height: unset;
  height: 32px;
  padding: .375rem .625rem;
  font-size: .8125rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.notes-list-sidebar-filter:focus {
  background: var(--bg-primary);
  border-color: var(--accent);
}
.notes-list-sidebar-filter::-webkit-search-cancel-button,
.notes-list-sidebar-filter::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
}

.notes-list-sidebar-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0 .5rem .5rem;
}

.notes-list-sidebar-list {
  display: flex;
  flex-direction: column;
  gap: .125rem;
  min-height: 100%; /* Leerraum unterhalb der letzten Zeile bleibt Root-Drop-Ziel (_onRootDragOver/-Drop) */
}
.notes-list-sidebar-list.is-drop-target {
  background: var(--accent-light);
  border-radius: var(--radius-sm);
}

/* Blatt-Notiz (kein Unterinhalt) – `--tree-level` (0..MAX_TREE_DEPTH, JS
   gedeckelt, Akzeptanz #9) steuert ausschließlich den Einzug. Der Zusatz-
   Offset (1.125rem) reserviert den Platz, den eine Ordnerzeile für ihren
   Auf-/Zuklapp-Pfeil braucht – Notiz-Titel richten sich dadurch optisch am
   Ordner-NAMEN aus, nicht am Pfeil. */
.notes-list-sidebar-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: .4rem .5rem;
  padding-left: calc(.5rem + var(--tree-level, 0) * .875rem + 1.125rem);
  border-radius: var(--radius-sm);
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--text-secondary);
  font-size: .8125rem;
  transition: background var(--transition), color var(--transition);
}
.notes-list-sidebar-item:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.notes-list-sidebar-item.is-active {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
}
.notes-list-sidebar-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.notes-list-sidebar-item.is-dragging {
  opacity: .45;
}
.notes-list-sidebar-item-title {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Ordner-Baum (Ticket 3.419.2) ──────────────────────────────────────
   Eine Ordnerzeile = Auf-/Zuklapp-Pfeil (`.notes-list-sidebar-tree-toggle`)
   + Ordner-Button (Icon+Name, Klick toggelt ebenfalls). Die ganze Zeile ist
   Drag-Quelle UND Drop-Ziel gleichzeitig (Muster `.notes-sidebar-item-row`
   der Workspace-Sidebar, hier aber ohne separaten Ziehgriff – anders als
   dort hat eine Ordnerzeile keine benachbarte "Bearbeiten"-Aktion, mit der
   ein reiner Zeilenklick kollidieren könnte). */
.notes-list-sidebar-folder-row {
  display: flex;
  align-items: center;
  gap: .125rem;
  padding-left: calc(.25rem + var(--tree-level, 0) * .875rem);
  border-radius: var(--radius-sm);
  position: relative;
}
.notes-list-sidebar-folder-row.is-dragging {
  opacity: .45;
}
.notes-list-sidebar-folder-row.is-drop-into {
  background: var(--accent-light);
  outline: 1px dashed var(--accent);
  outline-offset: -1px;
}
.notes-list-sidebar-tree-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.125rem;
  height: 1.75rem;
  flex-shrink: 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: transform var(--transition), color var(--transition);
}
.notes-list-sidebar-tree-toggle:hover {
  color: var(--text-primary);
}
.notes-list-sidebar-tree-toggle.is-expanded {
  transform: rotate(90deg);
}
.notes-list-sidebar-folder-btn {
  display: flex;
  align-items: center;
  gap: .375rem;
  flex: 1;
  min-width: 0;
  padding: .4rem .5rem .4rem .125rem;
  border-radius: var(--radius-sm);
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--text-secondary);
  font-size: .8125rem;
  font-weight: 500;
  text-align: left;
  transition: background var(--transition), color var(--transition);
}
.notes-list-sidebar-folder-btn:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.notes-list-sidebar-folder-btn svg {
  flex-shrink: 0;
  color: var(--text-tertiary);
}
.notes-list-sidebar-folder-btn .notes-list-sidebar-item-title {
  flex: 1;
}

.notes-list-sidebar-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem .5rem;
  text-align: center;
}
.notes-list-sidebar-empty p {
  margin: 0;
  font-size: .8125rem;
  color: var(--text-tertiary);
  line-height: 1.5;
}

/* Desktop-only Feature (isDesktopVisible() gated bereits in JS) – zusätzlich
   defensiv per CSS ausgeblendet, falls der Toggle vor einem Resize hängen
   bleibt (Bildschirmgrößen-Wechsel ohne Reload). */
@media (max-width: 900px) {
  .notes-list-sidebar { display: none; }
}
/* ── Receipts (Belege) ─────────────────────────────────────── */

/* D3 (Spec 20260730_receipt_inbox_media_library.md Abschnitt 2): Eingang/
   Zugeordnet/Alle-Reiter — Abstand unter dem .tab-filter (weder .page-header
   noch .search-bar tragen selbst einen unteren Rand, s. layout.css/_core.css). */
.receipts-period-tabs {
  margin: 0 0 0.75rem;
}

/* Monats-Gruppenkopf im "Zugeordnet"-Reiter — Desktop <td colspan> UND Mobile
   <div> teilen sich dieselbe Klasse (keine display-Abhängigkeit in den Regeln). */
.receipts-group-row-label {
  padding: 0.5rem 1rem;
  font-weight: 600;
  font-size: 0.75rem;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

/* Ersetzt die vormalige inline style="cursor:pointer" auf der klickbaren
   Desktop-Tabellenzeile (Pflicht: keine neuen Inline-Styles). */
.receipts-clickable-row {
  cursor: pointer;
}

/* Empty-State-Textblock (D3: reiter-abhängige Botschaften) — Icon selbst
   nutzt die bereits bestehende .receipts-empty-state svg-Regel weiter unten. */
.receipts-empty-state-title {
  font-weight: 600;
  margin: 0 0 0.5rem;
}
.receipts-empty-state-hint {
  margin: 0;
  color: var(--text-secondary);
  font-size: 0.875rem;
}
.receipts-empty-state-actions {
  margin-top: 1rem;
}

/* Kategorie-Filter (K2, Spec 20260730_receipt_categories_accounts.md) — ersetzt
   die vormalige Chip-Leiste (6 Kategorien): 40 Einträge passen nicht mehr in
   eine horizontal scrollende Chip-Strip, daher kompaktes gruppiertes Select. */
.receipts-category-filter-row {
  display: flex;
  align-items: center;
  padding: 0.625rem 1rem;
  border-bottom: 0.5px solid var(--border);
}
.receipts-category-filter-select {
  max-width: 280px;
}
@media (max-width: 900px) {
  .receipts-category-filter-select {
    max-width: none;
    width: 100%;
  }
}

/* Thumb in Liste */
.receipts-list-thumb {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  background: var(--bg-secondary);
  display: block;
  flex-shrink: 0;
}
.receipts-list-thumb--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
}

/* Status-Banner oben im Edit-Modus */
.receipts-status-banner {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .625rem .75rem;
  border-radius: var(--radius-sm);
  font-size: .875rem;
  margin-bottom: .75rem;
  line-height: 1.4;
}
.receipts-status-banner--locked {
  background: var(--teal-light);
  color: var(--teal);
}
.receipts-status-banner--ocr-fail {
  background: var(--coral-light);
  color: var(--coral);
}
.receipts-status-banner--ocr-pending {
  background: var(--amber-light);
  color: var(--amber);
}
.receipts-status-banner--ocr-ok {
  background: var(--teal-light);
  color: var(--teal);
}
/* KI-Auslesen-Button rechtsbündig im Banner (ersetzt vormals inline style="margin-left:auto") */
.receipts-status-banner-action {
  margin-left: auto;
  flex-shrink: 0;
}
/* Pulse-Dot für OCR-Pending */
.receipts-pulse-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--amber);
  flex-shrink: 0;
  animation: receipts-pulse 1.4s ease-in-out infinite;
}
@keyframes receipts-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%       { opacity: .45; transform: scale(.75); }
}

/* Edit-Seite Grid: Formular links + Vorschau rechts, 50/50 (Domenico-Entscheidung
   2026-07-31 — Beleg-Auslesung ist fehleranfaellig, Originalbeleg muss direkt neben
   dem Formular sichtbar sein statt hinter einem Klick-Overlay). */
.receipts-edit-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  align-items: start;
}

/* Inline-Vorschau-Box (iframe/img) — Muster identisch zu
   .ds-bookkeeping-split-preview/-frame (bookkeeping.js Positions-Detailseite),
   hier als eigene Klassen-Familie da Receipts-Modul eigene Klassen fuehrt (P-5
   pro Modul, kein Cross-Modul-Klassen-Reuse). P9: iframe/img bekommen eine
   Blob-URL, NIE den API-Pfad direkt (Bearer-Auth fehlt sonst am iframe-src).
   🔒 Muss VOR der @media(max-width:900px)-Regel unten stehen — sonst gewinnt
   bei gleicher Spezifitaet die spaeter im Quellcode stehende unconditional
   34rem-Regel gegen die fruehere 22rem-Mobile-Regel (CSS-Kaskade: gleiche
   Spezifitaet -> Quellcode-Reihenfolge entscheidet, nicht die Media-Query). */
.receipts-preview-frame-box {
  height: 34rem;
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  overflow: hidden;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.receipts-preview-frame {
  width: 100%;
  height: 100%;
  border: none;
  display: block;
}
.receipts-preview-frame--img {
  object-fit: contain;
  background: var(--bg-primary);
}
@media (max-width: 900px) {
  .receipts-edit-grid {
    grid-template-columns: 1fr;
  }
  /* Sticky ist nur als Desktop-2-Spalten-Affordanz gedacht — im Mobile-Stack
     würde die Vorschau sonst permanent oben kleben bleiben und das Formular
     verdrängen (Bug-Report 2026-07-14). */
  .receipts-preview-wrap {
    position: static;
    top: auto;
  }
  .receipts-preview-thumb {
    max-height: 240px;
    width: auto;
    max-width: 100%;
  }
  .receipts-preview-frame-box {
    height: 22rem;
  }
}

/* Vorschau-Bereich */
.receipts-preview-wrap {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
/* Sticky nur auf Desktop (2-Spalten-Grid) — Mobile stackt 1-spaltig,
   dort würde sticky die Vorschau permanent oben kleben lassen. */
@media (min-width: 901px) {
  .receipts-preview-wrap {
    position: sticky;
    top: 1rem;
  }
}
.receipts-preview-thumb {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  display: block;
  cursor: pointer;
  transition: border-color var(--transition);
}
.receipts-preview-thumb:hover {
  border-color: var(--accent);
}

.receipts-preview-placeholder {
  width: 100%;
  aspect-ratio: 3 / 4;
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  color: var(--text-tertiary);
  font-size: .875rem;
  background: var(--bg-secondary);
}
/* PDF-Placeholder: anklickbar → öffnet window.DocPreview (ein <img> kann kein
   PDF rendern, daher eigener Zustand statt des kaputten Bild-Fallbacks). */
.receipts-preview-placeholder--pdf {
  border-style: solid;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.receipts-preview-placeholder--pdf:hover,
.receipts-preview-placeholder--pdf:focus-visible {
  border-color: var(--accent);
  background: var(--bg-tertiary);
}
.receipts-preview-placeholder-pdf-icon {
  color: var(--coral);
  display: flex;
}
.receipts-preview-placeholder-label {
  color: var(--text-secondary);
  font-weight: 500;
  text-align: center;
  padding: 0 .75rem;
}

/* History / Edit-History (GoBD-Audit) */
.receipts-history-details > summary {
  cursor: pointer;
  font-size: .85rem;
  color: var(--text-tertiary);
  padding: .375rem 0;
  user-select: none;
}
.receipts-history-details > summary:hover {
  color: var(--text-secondary);
}
.receipts-history-list {
  margin: .375rem 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
.receipts-history-row {
  font-size: .8125rem;
  color: var(--text-secondary);
  padding: .25rem .5rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  display: flex;
  flex-wrap: wrap;
  gap: .25rem .5rem;
}
.receipts-history-row-time {
  color: var(--text-tertiary);
  font-size: .75rem;
}

/* Verknüpfungs-Sektion */
.receipts-link-section {
  padding-top: .75rem;
  border-top: 1px dashed var(--border);
  font-size: .875rem;
}
.receipts-link-section .form-label {
  font-size: .8125rem;
  margin-bottom: .25rem;
}

/* Empty-State */
.receipts-empty-state {
  text-align: center;
  padding: 3rem 1rem;
  color: var(--text-tertiary);
  font-size: .9375rem;
}
.receipts-empty-state svg {
  margin-bottom: .75rem;
  opacity: .4;
}

/* ── Scanner-Component ─────────────────────────────────────── */
.receipts-scanner-wrap {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: #000;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.receipts-scanner-video {
  flex: 1;
  object-fit: cover;
  width: 100%;
  display: block;
  min-height: 0;
}
.receipts-scanner-canvas {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 5;
}
.receipts-scanner-toolbar {
  background: rgba(0, 0, 0, .65);
  padding: .75rem 1.25rem;
  padding-bottom: calc(.75rem + env(safe-area-inset-bottom, 0px));
  display: flex;
  align-items: center;
  justify-content: space-around;
  gap: 1rem;
  z-index: 6;
}
.receipts-scanner-shutter {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: #fff;
  border: 4px solid rgba(255, 255, 255, .35);
  cursor: pointer;
  flex-shrink: 0;
  box-shadow: 0 0 0 2px rgba(255,255,255,.15);
  transition: transform .1s ease, opacity .1s ease;
}
.receipts-scanner-shutter:active {
  transform: scale(.92);
  opacity: .85;
}
.receipts-scanner-close {
  position: absolute;
  top: 1rem;
  left: 1rem;
  top: calc(1rem + env(safe-area-inset-top, 0px));
  color: #fff;
  background: rgba(0, 0, 0, .5);
  border: none;
  border-radius: 50%;
  width: 40px;
  height: 40px;
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 10;
}
.receipts-scanner-corner-pin {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--accent);
  border: 3px solid #fff;
  cursor: grab;
  touch-action: none;
  position: absolute;
  z-index: 6;
  box-shadow: 0 2px 6px rgba(0,0,0,.4);
  transform: translate(-50%, -50%);
}
.receipts-scanner-corner-pin:active {
  cursor: grabbing;
}
.receipts-scanner-actions {
  display: flex;
  gap: .5rem;
  padding: 1rem;
  background: rgba(0, 0, 0, .7);
  align-items: center;
  justify-content: center;
}
.receipts-scanner-actions button {
  flex: 1;
  max-width: 180px;
  min-height: 44px;
}
.receipts-scanner-loading {
  position: absolute;
  inset: 0;
  z-index: 20;
  background: rgba(0, 0, 0, .65);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .75rem;
  color: #fff;
  font-size: .9375rem;
}
.receipts-scanner-spinner {
  width: 36px;
  height: 36px;
  border: 3px solid rgba(255,255,255,.25);
  border-top-color: #fff;
  border-radius: 50%;
  animation: receipts-spin 0.8s linear infinite;
}
@keyframes receipts-spin {
  to { transform: rotate(360deg); }
}

/* File-Drop-Zone */
.receipts-scanner-drop-zone {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 2rem;
  color: #fff;
  text-align: center;
}
.receipts-scanner-drop-zone.drag-over {
  background: rgba(255,255,255,.08);
}
.receipts-scanner-drop-label {
  font-size: 1.0625rem;
  font-weight: 600;
  opacity: .9;
}
.receipts-scanner-drop-sub {
  font-size: .875rem;
  opacity: .6;
  max-width: 28rem;
}

/* ── Scanner: File-Fallback (kein Kamera-Zugriff/-Berechtigung, Desktop) ──
   Die Live-Kamera- und Review-Zustaende bleiben .receipts-scanner-wrap
   (schwarzes Vollbild, dort erwartet — Kamerabild). Der Fallback zeigt
   dagegen ein simples Upload-Panel ohne Kamerabild → helles, themefaehiges
   Panel statt Schwarz-Vollbild-Optik (Nutzer-Feedback, sah wie ein defektes
   Overlay aus). Modifier ueberschreibt nur die geteilten Klassen, die in
   diesem Zustand vorkommen — .receipts-scanner-close/-drop-zone/-label/
   -sub/-sub--warn bleiben fuer Live/Review unveraendert dunkel. */
.receipts-scanner-wrap--fallback {
  background: var(--bg-primary);
}
.receipts-scanner-wrap--fallback .receipts-scanner-close {
  color: var(--text-secondary);
  background: var(--bg-secondary);
}
.receipts-scanner-wrap--fallback .receipts-scanner-close:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}
.receipts-scanner-wrap--fallback .receipts-scanner-drop-zone {
  color: var(--text-primary);
  margin: 1.5rem;
  border: 1.5px dashed var(--border);
  border-radius: var(--radius-md);
}
.receipts-scanner-wrap--fallback .receipts-scanner-drop-zone.drag-over {
  background: var(--accent-light);
  border-color: var(--accent);
}
.receipts-scanner-wrap--fallback .receipts-scanner-drop-sub--warn {
  color: var(--amber);
  background: var(--amber-light);
}
/* Upload-Icon in der Drop-Zone — gedaempft, folgt Light/Dark automatisch */
.receipts-scanner-drop-icon {
  display: flex;
  color: var(--text-tertiary);
}
/* „Datei auswaehlen"-Button (Span statt Button) — .btn liefert bereits
   display/align/gap/min-height/cursor, hier nur der fehlende Abstand */
.receipts-scanner-fallback-upload-btn {
  margin-top: .5rem;
}

/* Review / Corner-Pin Overlay */
.receipts-scanner-review-wrap {
  position: relative;
  flex: 1;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #111;
}
.receipts-scanner-review-img {
  max-width: 100%;
  max-height: 100%;
  display: block;
}
/* SVG crop-quad overlay in review pane */
.receipts-scanner-review-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 4;
}

/* ── Phase 2: Auto-Capture Toggle (top-right of live view) ── */
.receipts-scanner-toggle {
  position: absolute;
  top: calc(1rem + env(safe-area-inset-top, 0px));
  right: 1rem;
  z-index: 10;
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .3rem .625rem;
  background: rgba(0, 0, 0, .5);
  border: 1.5px solid rgba(255, 255, 255, .25);
  border-radius: 999px;
  color: rgba(255, 255, 255, .6);
  font-size: .75rem;
  font-weight: 500;
  cursor: pointer;
  min-height: 44px;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
  -webkit-tap-highlight-color: transparent;
}
.receipts-scanner-toggle:hover {
  background: rgba(0, 0, 0, .7);
  color: rgba(255, 255, 255, .9);
}
.receipts-scanner-toggle.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.receipts-scanner-toggle-label {
  line-height: 1;
}

/* ── OpenCV loading hint (top-center of live view) ── */
.receipts-scanner-cv-hint {
  position: absolute;
  top: calc(1rem + env(safe-area-inset-top, 0px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  padding: .25rem .625rem;
  background: rgba(0, 0, 0, .55);
  border-radius: 999px;
  color: rgba(255, 255, 255, .7);
  font-size: .75rem;
  white-space: nowrap;
  pointer-events: none;
}

/* ── File-button label in scanner toolbar ── */
.receipts-scanner-file-btn {
  color: #fff;
  font-size: .85rem;
  opacity: .75;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .25rem;
  min-height: 44px;
  min-width: 44px;
  justify-content: center;
}

/* ── Scanner: Multi-Page + Permissions-UX (Phase 2b) ─────────────────────── */

/* Toggle-Gruppe (Auto + Mehrseitig nebeneinander) */
.receipts-scanner-toggles {
  position: absolute;
  top: calc(1rem + env(safe-area-inset-top, 0px));
  right: 1rem;
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: .375rem;
  align-items: flex-end;
}
/* Toggles innerhalb der Gruppe: position static (kein absolute mehr) */
.receipts-scanner-toggles .receipts-scanner-toggle {
  position: static;
  top: auto;
  right: auto;
}

/* Badge-Pille: Seiten-Anzahl rechts am Mehrseitig-Toggle */
.receipts-scanner-multi-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 .3rem;
  border-radius: 999px;
  background: #fff;
  color: var(--accent, #003780);
  font-size: .7rem;
  font-weight: 700;
  line-height: 1;
  margin-left: .1rem;
}

/* Fertig-Button (prominent, rechts in Toolbar) */
.receipts-scanner-fertig-btn {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: 0 .875rem;
  min-height: 44px;
  border-radius: 999px;
  background: var(--accent, #003780);
  color: #fff;
  border: none;
  font-size: .875rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--transition, 150ms ease);
  -webkit-tap-highlight-color: transparent;
}
.receipts-scanner-fertig-btn:hover {
  background: var(--accent-dark, #002456);
}
.receipts-scanner-fertig-btn:disabled {
  opacity: .5;
  cursor: not-allowed;
}

/* Shutter: Cooldown-State nach Multi-Capture */
.receipts-scanner-shutter--cooldown {
  opacity: .4;
  cursor: not-allowed;
}

/* Multi-Review-Header */
.receipts-scanner-multi-header {
  position: absolute;
  top: calc(1rem + env(safe-area-inset-top, 0px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  padding: .25rem .75rem;
  background: rgba(0, 0, 0, .6);
  border-radius: 999px;
  pointer-events: none;
}
.receipts-scanner-multi-header-title {
  color: rgba(255, 255, 255, .9);
  font-size: .8125rem;
  font-weight: 600;
  white-space: nowrap;
}

/* Multi-Review: Seiten-Liste */
.receipts-scanner-review-list {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: .625rem;
  padding: calc(3rem + env(safe-area-inset-top, 0px)) 1rem 1rem;
  width: 100%;
}

/* Multi-Review: Seiten-Card */
.receipts-scanner-review-card {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .625rem .75rem;
  background: rgba(255, 255, 255, .1);
  border: 1.5px solid rgba(255, 255, 255, .2);
  border-radius: var(--radius-md, 10px);
  cursor: grab;
  transition: background .15s ease, border-color .15s ease;
}
.receipts-scanner-review-card:active {
  cursor: grabbing;
}
.receipts-scanner-review-card.drag-over {
  border-color: var(--accent, #003780);
  background: rgba(77, 133, 224, .25);
}

/* Drag-Handle im Review-Card */
.receipts-scanner-review-drag {
  color: rgba(255, 255, 255, .4);
  flex-shrink: 0;
  display: flex;
  align-items: center;
}

/* Seiten-Nummer */
.receipts-scanner-review-num {
  color: rgba(255, 255, 255, .6);
  font-size: .75rem;
  min-width: 3.5rem;
  flex-shrink: 0;
}

/* Thumbnail-Vorschau */
.receipts-scanner-review-thumb {
  width: 80px;
  height: 60px;
  object-fit: cover;
  border-radius: var(--radius-sm, 6px);
  border: 1px solid rgba(255, 255, 255, .15);
  cursor: pointer;
  flex-shrink: 0;
  transition: border-color .15s ease;
}
.receipts-scanner-review-thumb:hover {
  border-color: var(--accent, #003780);
}

/* Löschen-Button in der Card */
.receipts-scanner-review-remove {
  margin-left: auto;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  min-height: 44px;
  min-width: 44px;
  border: none;
  background: transparent;
  color: rgba(255, 255, 255, .5);
  cursor: pointer;
  border-radius: var(--radius-sm, 6px);
  padding: 0;
  transition: color .15s ease, background .15s ease;
}
.receipts-scanner-review-remove:hover {
  color: var(--coral, #D85A30);
  background: rgba(216, 90, 48, .15);
}

/* „+ Weitere Seite"-Button */
.receipts-scanner-review-add {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .75rem 1rem;
  border: 1.5px dashed rgba(255, 255, 255, .25);
  border-radius: var(--radius-md, 10px);
  background: transparent;
  color: rgba(255, 255, 255, .6);
  font-size: .875rem;
  cursor: pointer;
  min-height: 44px;
  transition: border-color .15s ease, color .15s ease;
}
.receipts-scanner-review-add:hover {
  border-color: rgba(255, 255, 255, .5);
  color: #fff;
}

/* F#15: Permission-denied Hinweistext (subtil amber) */
.receipts-scanner-drop-sub--warn {
  color: var(--amber-light, #FAEEDA);
  font-size: .825rem;
  text-align: center;
  max-width: 26rem;
  line-height: 1.45;
  padding: .25rem .5rem;
  border-radius: var(--radius-sm, 6px);
  background: rgba(186, 117, 23, .25);
}

/* Upload-Progress-Overlay (im Belege-Upload-Dialog) */
.receipts-upload-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,.55);
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .75rem;
  color: #fff;
  border-radius: var(--radius-md);
}

/* Beträge-Grid im Edit-Formular (Brutto / Netto / MwSt-Betrag / MwSt-Satz) */
.receipts-amounts-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .75rem;
}
@media (max-width: 900px) {
  /* [HIGH] Beträge-Grid stackt mobil 1-spaltig — verhindert zerquetschte Felder */
  .receipts-amounts-grid {
    grid-template-columns: 1fr;
  }
}

/* ── Belege: Inline-Link-Picker ─────────────────────────────────────────── */
.receipts-link-suggest-wrap {
  position: relative;
}

.receipts-link-selected {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .625rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  min-height: 2.25rem;
}

.receipts-link-selected-label {
  flex: 1;
  min-width: 0;
  font-size: .875rem;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.receipts-link-clear-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: none;
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  padding: 0;
}
.receipts-link-clear-btn:hover {
  background: var(--bg-tertiary);
  color: var(--coral);
}

.receipts-link-suggest-list {
  position: absolute;
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  z-index: 410;
  list-style: none;
  margin: 0;
  padding: .25rem 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  max-height: 240px;
  overflow-y: auto;
}

.receipts-link-suggest-item {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding: .5rem .75rem;
  cursor: pointer;
  min-height: 44px;
  justify-content: center;
}
.receipts-link-suggest-item:hover {
  background: var(--bg-secondary);
}

.receipts-link-suggest-main {
  font-size: .875rem;
  font-weight: 500;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.receipts-link-suggest-sub {
  font-size: .78rem;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Belege: Reverse-Lookup-Sektion ─────────────────────────────────────── */
/* Einsetzbar in invoices.js, driver-log.js, contacts.js */
.receipts-reverse-lookup {
  margin-top: 1rem;
}

.receipts-reverse-item {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .5rem .625rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--text-primary);
  cursor: pointer;
}
.receipts-reverse-item:hover {
  background: var(--bg-secondary);
}

.receipts-reverse-thumb {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  background: var(--bg-secondary);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
}

/* Fallback-Placeholder wenn kein Thumbnail-Bild geladen */
.receipts-reverse-thumb-placeholder {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
}

.receipts-reverse-info {
  flex: 1;
  min-width: 0;
}

.receipts-reverse-vendor {
  font-weight: 500;
  font-size: .875rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.receipts-reverse-meta {
  font-size: .75rem;
  color: var(--text-secondary);
}

.receipts-reverse-cat {
  font-size: .65rem;
  flex-shrink: 0;
}

/* ── Receipts: Sticky Edit-Toolbar (Mobile) ───────────────────────────────── */

/* Mehr-Button: Desktop versteckt, Mobile sichtbar */
.receipts-toolbar-more { display: none; }

/* Mobile: sekundäre Toolbar-Items verstecken */
@media (max-width: 900px) {
  .receipts-toolbar-secondary { display: none; }
  .receipts-toolbar-more { display: inline-flex; }

  /* Sticky-Wrapper: Toolbar klebt oben beim Scrollen */
  .receipts-toolbar-wrap {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--bg-primary);
    border-bottom: 1px solid var(--border);
    padding: .375rem 0;
    margin: -.375rem 0 .75rem;
  }
}

/* ── Belege: Sekundär-Panel Aktions-Zeile (Safe-Area) ─────────────────────── */
/* Formalisiert das Export-Dialog-Buttonzeilen-Pattern (Primär flex:1 + Ghost,
   safe-area-inset-bottom) als wiederverwendbare Klasse — Bank-Import-Panel. */
.receipts-panel-actions {
  display: flex;
  gap: .5rem;
  margin-top: 1rem;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.receipts-panel-actions > .btn:first-child {
  flex: 1;
}

/* ── Belege: Bank-Zuweisung (D5, Spec 20260730_receipt_inbox_media_library.md
   Abschnitt 4) — reine Anzeige "Zugewiesen zu: …" + Sprung zur Positions-
   seite. Der Bank-Abgleich selbst (Vorschlag/Bestätigen) läuft ausschließlich
   auf der Buchhaltungs-Positionsseite — hier wird nichts mehr zugewiesen. ── */
/* DEPRECATED (Ticket 3.154.2) — Bank-Zuweisung ist kein Hinweis-Kasten mehr,
   sondern ein Feld (Label+Wert) am Kopf von .receipts-link-section, s.u.
   Klassen bleiben fuer evtl. Rueckgriffe stehen, werden nicht mehr gerendert. */
.receipts-bank-assign-box {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
  margin-top: 1rem;
}
.receipts-bank-assign-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  margin-top: .125rem;
}
.receipts-bank-assign-body {
  flex: 1;
  min-width: 0;
  font-size: .8125rem;
  color: var(--text-secondary);
}
.receipts-bank-assign-link {
  display: inline-block;
  margin-top: .25rem;
  padding: 0;
  border: none;
  background: none;
  color: var(--accent);
  font-size: .8125rem;
  text-decoration: underline;
  cursor: pointer;
}
.receipts-bank-assign-link:hover {
  color: var(--accent-dark);
}

/* Ticket 3.154.2 (T2): Bank-Zuweisung steht als erstes Feld im
   "Weitere Verknüpfungen"-Abschnitt — derselbe .form-label/.receipts-link-
   selected-Look wie ein bereits gesetztes Rechnung/Fahrt/Deal-Feld (gleiche
   Betonung). Der Trenner grenzt die tatsächlich bestehende Verknüpfung
   optisch von den vier optionalen, meist leeren Feldern darunter ab. */
.receipts-bank-assign-field {
  padding-bottom: .75rem;
  margin-bottom: .75rem;
  border-bottom: 1px dashed var(--border);
}

/* ── Belege: „Beleg hinzufügen"-Auswahl-Panel ─────────────────────────────── */
/* Weißes Sekundär-Panel mit vertikalen Options-Zeilen (Icon-Kreis + Titel +
   Untertitel) — Einstiegspunkt für Mobile-FAB, Desktop-Header + Empty-State.
   Ersetzt den Direkt-Sprung in den schwarzen Vollbild-Scanner. Seit P4
   (Spec 20260730_bookkeeping_ux_rework.md Abschnitt 5.1) gerendert vom
   geteilten Erfassungs-Modul `pages/_receipt-capture.js` — genutzt von
   receipts.js UND bookkeeping.js (P-5, ein Klassensatz statt zweier). */
.receipts-add-options {
  display: flex;
  flex-direction: column;
  gap: .625rem;
}
.receipts-add-option {
  display: flex;
  align-items: center;
  gap: .875rem;
  width: 100%;
  padding: .875rem 1rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  transition: border-color .15s ease, background-color .15s ease;
}
/* Ticket 3.154.3 Nachbesserung (Domenico-Test 2026-08-07): identische
   Hover-/Focus-Reaktion wie .receipts-add-dropzone weiter unten (dieselben
   zwei Deklarationen, absichtlich dupliziert statt in einen Selektor
   zusammengefasst -- .receipts-add-option und .receipts-add-dropzone sind
   zwei unterschiedliche Klassen mit unterschiedlichem Grund-Layout, ein
   gemeinsamer Selektor waere hier weniger lesbar als der Zeilenaufwand
   spart). Vorher: schwacher `color-mix()`-Rand + `--bg-tertiary` -- wirkte
   neben der kraeftigen Akzent-Hervorhebung der Ablageflaeche wie ein
   anderes Bedienelement. Jetzt reagieren alle drei Erfassungs-Optionen auf
   Hover/Fokus identisch -> eine Familie statt drei Stile. */
.receipts-add-option:hover,
.receipts-add-option:focus-visible {
  border-color: var(--accent);
  background: var(--accent-light);
}
.receipts-add-option-icon {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.receipts-add-option-icon svg {
  width: 20px;
  height: 20px;
}
.receipts-add-option-icon--accent {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
}
.receipts-add-option-icon--teal {
  background: var(--teal-light);
  color: var(--teal);
}
.receipts-add-option-icon--amber {
  background: var(--amber-light);
  color: var(--amber);
}
.receipts-add-option-icon--neutral {
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.receipts-add-option-body {
  flex: 1;
  min-width: 0;
}
.receipts-add-option-title {
  display: block;
  font-weight: 600;
  font-size: .9375rem;
  color: var(--text-primary);
}
.receipts-add-option-sub {
  display: block;
  margin-top: .125rem;
  font-size: .8125rem;
  color: var(--text-secondary);
}
/* Versteckte native File-Inputs unter Foto/Datei-Galerie — der sichtbare
   Klick-Bereich ist das umschließende <label>. Ersetzt vormalige
   style="display:none" (frontend.md „Klassen statt Inline-Styles"). */
.receipts-add-option-input { display: none; }

/* ── Ablegefläche „Datei / Galerie" (Ticket 3.154.3/T3) — letzter Eintrag in
   .receipts-add-options, nimmt gezogene Dateien entgegen UND öffnet per
   Klick den Dateidialog (dasselbe <label>+verstecktes <input type=file>
   -Muster wie .receipts-add-option, nur als größere, zentrierte Fläche statt
   einer schmalen Icon-Zeile — Muster angelehnt an .import-dropzone, eigene
   Klasse weil dieses Modul bewusst import-frei von receipts.js/bookkeeping.js
   bleibt, s. Docblock _receipt-capture.js). */
.receipts-add-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .375rem;
  width: 100%;
  padding: 1.5rem 1rem;
  text-align: center;
  border: 2px dashed var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  cursor: pointer;
  font-family: inherit;
  transition: border-color .15s ease, background-color .15s ease;
}
.receipts-add-dropzone:hover,
.receipts-add-dropzone:focus-within,
.receipts-add-dropzone--active {
  border-color: var(--accent);
  background: var(--accent-light);
}
.receipts-add-dropzone-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--teal-light);
  color: var(--teal);
}
.receipts-add-dropzone-icon svg { width: 20px; height: 20px; }
.receipts-add-dropzone-label {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--text-primary);
}
.receipts-add-dropzone-sub {
  font-size: .8125rem;
  color: var(--text-secondary);
}

/* ── Mehrfach-Upload-Fortschritt (P4, _receipt-capture.js renderCaptureProgress) ── */
.receipts-capture-progress {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-height: 22rem;
  overflow-y: auto;
}
.receipts-capture-progress-row {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
  padding: .625rem .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
}
.receipts-capture-progress-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-top: .0625rem;
  color: var(--text-tertiary);
}
.receipts-capture-progress-row--ok .receipts-capture-progress-icon { color: var(--teal); }
.receipts-capture-progress-row--error .receipts-capture-progress-icon { color: var(--coral); }
.receipts-capture-progress-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .125rem;
}
.receipts-capture-progress-name {
  font-size: .875rem;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.receipts-capture-progress-error {
  font-size: .8125rem;
  color: var(--coral);
}

/* Gedämpfter Hinweistext unter einem einzelnen Formularfeld (P4:
   Buchungsmonat-Select im Beleg-Editor) — kein .ds-info-box, das wäre für
   eine einzeilige Feld-Erklärung zu schwer. */
.receipts-field-hint {
  margin: .3125rem 0 0;
  font-size: .75rem;
  color: var(--text-tertiary);
}

/* Ticket 3.154.5 (Nachbesserung): Mini-Formular „Neuen Buchungsmonat anlegen"
   direkt unter dem Buchungsmonat-Select — Monat-Select + Jahr-Input, dieselbe
   Bedienung wie das „Monat anlegen"-Panel der Buchhaltungsseite. Abgesetzter
   Rahmen statt .ds-info-box (das ist für Hinweistexte, nicht für Formularfelder). */
.receipts-new-period-inline {
  margin-top: .5rem;
  padding: .75rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.receipts-new-period-inline .form-row {
  margin-bottom: .75rem;
}

/* ── Beleg-Kategorien-Verwaltung (page-receipt-categories, Spec
   20260802_bookkeeping_postings.md Phase 3 Punkt 3) — Muster analog
   .ds-industries-* (_core.css), hier modul-lokal weil Teil des
   Belege-Erfassungs-Moduls statt eines generischen Admin-Katalogs. ──────── */
.receipts-cat-hint {
  color: var(--text-secondary);
  font-size: .875rem;
  margin: 0 0 .875rem;
}
.receipts-cat-missing-banner {
  display: flex;
  align-items: center;
  gap: .625rem;
  width: 100%;
  text-align: left;
  padding: .625rem .875rem;
  margin: 0 0 .875rem;
  border: 1px solid var(--amber-light);
  border-left: 3px solid var(--amber);
  border-radius: var(--radius-md);
  background: var(--amber-light);
  color: var(--text-primary);
  font-size: .8125rem;
  cursor: pointer;
  transition: background var(--transition);
}
.receipts-cat-missing-banner:hover { background: var(--amber-light); filter: brightness(0.97); }
.receipts-cat-filter { margin: 0 0 .875rem; }
.receipts-cat-label { font-weight: 500; }
.receipts-cat-key {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .72rem;
  color: var(--text-tertiary);
  margin-top: .0625rem;
}
.receipts-cat-account {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .8125rem;
  background: var(--bg-secondary);
  padding: .1rem .375rem;
  border-radius: var(--radius-sm);
}
.receipts-cat-dash { color: var(--text-tertiary); }
.receipts-cat-check {
  display: inline-flex;
  color: var(--teal);
}
.receipts-cat-actions-col { width: 5rem; text-align: right; }
.receipts-cat-row-actions { display: flex; align-items: center; gap: .375rem; justify-content: flex-end; }
.receipts-cat-del-btn { color: var(--coral); }
.receipts-cat-del-btn:hover { background: var(--coral-light); color: var(--coral); }
.receipts-cat-row--inactive { opacity: .6; }
.receipts-cat-panel-actions {
  display: flex;
  gap: .5rem;
  margin-top: 1rem;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.receipts-cat-panel-actions .btn { flex: 1; }
.receipts-cat-panel-danger {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .375rem;
  width: 100%;
  margin-top: .75rem;
  color: var(--coral);
}
.receipts-cat-panel-danger:hover { background: var(--coral-light); color: var(--coral); }
.receipts-cat-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .5rem 0;
}
.receipts-cat-toggle-label {
  font-size: .875rem;
  color: var(--text-primary);
}
.receipts-cat-mobile-accounts {
  font-size: .75rem;
  color: var(--text-tertiary);
  margin-top: .125rem;
}

/* Mobile page-receipts overrides */
@media (max-width: 900px) {
  page-receipts .page-header-h1 { display: none; }
  page-receipts .page-header-actions { display: none; }
  .receipts-edit-footer {
    position: sticky;
    bottom: 0;
    background: var(--bg-primary);
    border-top: 1px solid var(--border);
    padding: .75rem 0;
    padding-bottom: calc(.75rem + env(safe-area-inset-bottom, 0px));
    z-index: 5;
  }
}

/* ── Maintenance-Screen (Vollbild, kein Nav) ───────────────── */
body.maintenance-active {
  overflow: hidden;
}
/* Nav-Elemente ausblenden wenn Wartungsscreen aktiv */
body.maintenance-active ds-app-header,
body.maintenance-active ds-nav-rail,
body.maintenance-active ds-bottom-nav,
body.maintenance-active .ds-nav-panel-backdrop {
  display: none !important;
}

.maintenance-screen {
  position: fixed;
  inset: 0;
  background: var(--bg-primary);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  padding-bottom: calc(2rem + env(safe-area-inset-bottom, 0px));
  padding-top:    calc(2rem + env(safe-area-inset-top, 0px));
}
.maintenance-screen-inner {
  max-width: 480px;
  width: 100%;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}
.maintenance-screen-icon {
  color: var(--amber);
  margin-bottom: .5rem;
}
.maintenance-screen-title {
  font-size: 1.75rem;
  font-weight: 700;
  margin: 0;
  color: var(--text-primary);
  line-height: 1.2;
}
.maintenance-screen-subtitle {
  font-size: 1rem;
  color: var(--text-secondary);
  margin: 0;
}
.maintenance-screen-reason {
  background: var(--amber-light);
  color: var(--amber);
  padding: .75rem 1rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--amber);
  font-size: .95rem;
  max-width: 100%;
  word-break: break-word;
}
.maintenance-screen-countdown {
  padding: 1rem 1.5rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-lg);
  margin-top: .5rem;
}
.maintenance-screen-countdown-label {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  margin-bottom: .25rem;
}
.maintenance-screen-countdown-value {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.maintenance-screen-eta {
  color: var(--text-secondary);
  font-size: .9rem;
}
.maintenance-screen-info {
  color: var(--text-tertiary);
  font-size: .85rem;
  margin: .5rem 0 0;
}
.maintenance-screen-spinner {
  width: 32px;
  height: 32px;
  border: 3px solid var(--bg-secondary);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: maintenance-spin 1s linear infinite;
  margin-top: .25rem;
  flex-shrink: 0;
}
@keyframes maintenance-spin {
  to { transform: rotate(360deg); }
}
@media (max-width: 600px) {
  .maintenance-screen { padding: 1.5rem 1rem; }
  .maintenance-screen-title { font-size: 1.375rem; }
  .maintenance-screen-countdown-value { font-size: 1.25rem; }
  .maintenance-screen-inner { gap: .75rem; }
}

/* ── Maintenance-Vorab-Ankündigungs-Banner ─────────────────── */
.maintenance-banner {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem 1rem;
  background: var(--amber-light);
  color: var(--amber);
  border-bottom: 1px solid var(--amber);
  font-size: .875rem;
  font-weight: 500;
  flex-shrink: 0;
}
.maintenance-banner-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
}
.maintenance-banner-text {
  flex: 1;
  min-width: 0;
}
.maintenance-banner-countdown {
  font-variant-numeric: tabular-nums;
}
@media (max-width: 600px) {
  .maintenance-banner {
    flex-wrap: wrap;
    font-size: .8rem;
    padding: .5rem .75rem;
  }
  .maintenance-banner-text { flex: 1 1 100%; }
}

/* ── Datenqualität-Overlay z-index-Fix (Punkt 4) ────────────────────────────
 * .detail-panel hat overflow:hidden (_core.css Z.1213) — clippt .quality-popover.
 * Im Firmen-Detail-View: Override auf visible damit das Popover vollständig sichtbar ist.
 * Ursache: absolute-positioniertes .quality-popover (z-index:200) liegt innerhalb eines
 * overflow:hidden Vorfahren → wird abgeschnitten. Fix: overflow:visible am Firmen-Detail-Panel.
 */
.grid-sidebar .detail-panel {
  overflow: visible;
}

/* ── Breadcrumb-Zeile mit Actions (Punkt 2) ─────────────────────────────── */
.company-detail-header-bar {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-bottom: .75rem;
  flex-wrap: wrap;
}

.company-detail-header-bar .breadcrumb {
  flex: 1;
  min-width: 0;
}

.company-detail-header-bar .detail-actions {
  flex-shrink: 0;
}

@media (max-width: 900px) {
  .company-detail-header-bar {
    gap: .375rem;
  }
  .company-detail-header-bar .detail-actions {
    flex-wrap: wrap;
    overflow-x: auto;
    max-width: 100%;
  }
}

/* ── Stammdaten-Card: kompaktes Label-Wert-Grid (Punkt 1) ───────────────── */
.company-stammdaten-grid {
  display: flex;
  flex-direction: column;
  padding: 0;
}

.company-sd-row {
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  align-items: baseline;
  gap: .25rem .75rem;
  padding: .5rem 1.25rem;
  border-bottom: 1px solid var(--border);
  min-height: 2.5rem;
}

.company-sd-row:last-child {
  border-bottom: none;
}

/* Adress-Rows: Mehrzeiler, baseline-Ausrichtung bleibt, pre-line im Value */
.company-sd-row--addr {
  align-items: flex-start;
  padding-top: .5625rem;
}

/* Vollbreite-Rows (z. B. Notizen) */
.company-sd-row--full {
  grid-template-columns: 7.5rem 1fr;
  align-items: flex-start;
  padding-top: .5625rem;
}

.company-sd-label {
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  white-space: nowrap;
  padding-top: .1rem;
}

.company-sd-value {
  font-size: .9rem;
  color: var(--text-primary);
  min-width: 0;
  overflow: hidden;
}

.company-sd-value a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.company-sd-value a:hover {
  color: var(--accent-dark);
}

@media (max-width: 600px) {
  .company-sd-row {
    grid-template-columns: 1fr;
    gap: .1rem;
    padding: .5rem 1rem;
  }
  .company-sd-label {
    font-size: .6875rem;
  }
}

/* ── Company Detail Tab-Navigation (Tab-Nav im Detail-View) ─────────────── */
/*
 * Neu in companies.js _renderDetailTabNav: 7-Tab-Leiste unterhalb des Detail-Headers.
 * Reused .tab-filter + .tab-filter-btn (components.css:827) — kein eigenes Tab-Styling.
 * .company-detail-tab-nav: flush-Positionierung, kein extra margin-top (Detail-Panel hat
 * bereits border-bottom), leicht angehoben (negative margin) um optisch am Card anzudocken.
 */
.company-detail-tab-nav {
  margin-top: -.25rem;
  margin-bottom: .125rem;
}

/* Mobile: Tab-Leiste horizontal scrollbar (analog .tab-filter Mobile-Regel, design-system.md Z.1453) */
@media (max-width: 900px) {
  .company-detail-tab-nav {
    margin-top: 0;
  }
}

/* ── Companies: Finanz-Konfiguration ──────────────────────── */
.companies-skonto-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .5rem;
}
/* .companies-skonto-grid single-column: jetzt im 900px-Block weiter unten */

/* ── Company Needs ──────────────────────────────────────────── */
.company-needs-tab-body {
  padding: .75rem 0 0;
}
.company-needs-subfilter {
  margin-bottom: .75rem;
  flex-wrap: wrap;
  gap: .375rem;
}
.company-needs-project-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: .25rem;
  vertical-align: middle;
  flex-shrink: 0;
}
.company-needs-add {
  margin-bottom: .875rem;
}
.company-needs-add .select {
  width: 100%;
}
.company-need-item {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .75rem;
  margin-bottom: .5rem;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.company-need-item-header {
  display: flex;
  align-items: center;
  gap: .75rem;
}
.company-need-skill-block {
  flex: 1;
  min-width: 0;
}
.company-need-skill {
  font-weight: 500;
  font-size: .9375rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.company-need-category {
  font-size: .75rem;
  color: var(--text-tertiary);
}
.company-need-priority {
  width: 7rem;
  flex-shrink: 0;
}
.company-need-priority--low    { color: var(--text-tertiary); }
.company-need-priority--medium { color: var(--amber); }
.company-need-priority--high   { color: var(--coral); }
.company-need-notes {
  min-height: 3rem;
  font-size: .875rem;
  resize: vertical;
}
.company-need-add-note {
  align-self: flex-start;
  font-size: .8125rem;
  color: var(--text-tertiary);
  padding: .2rem .5rem;
}
.company-need-add-note:hover {
  color: var(--accent);
  background: var(--accent-light);
}
.company-need-empty {
  text-align: center;
  padding: 2rem 1rem;
  color: var(--text-tertiary);
  font-size: .875rem;
}

/* ── Company Needs: Arbeitsliste (page-company-needs, Ticket 3.120 Paket 1b) ──── */
.company-needs-worklist-intro {
  color: var(--text-secondary);
  font-size: .875rem;
  margin: -.5rem 0 1rem;
}
.company-needs-worklist-company-link {
  color: var(--accent);
  cursor: pointer;
}
.company-needs-worklist-company-link:hover {
  text-decoration: underline;
}
.company-needs-worklist-note {
  color: var(--text-secondary);
  font-size: .8125rem;
  max-width: 16rem;
}
.company-needs-worklist-note span {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.company-needs-status-select {
  min-width: 9.5rem;
  font-weight: 500;
}
.company-needs-status-select--open       { color: var(--text-secondary); }
.company-needs-status-select--clarifying { color: var(--amber); }
.company-needs-status-select--assigned   { color: var(--teal); }
.company-needs-status-select--dismissed  { color: var(--coral); }
.company-needs-worklist-native-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .375rem;
  flex-shrink: 0;
}
.company-needs-worklist-native-right .company-needs-status-select {
  min-width: 8.5rem;
}
.company-needs-actions-col {
  width: 3rem;
  text-align: right;
}

/* ── Company Needs: Mobile-Stacking (≤900px = App-Mobile-Breakpoint) ──── */
@media (max-width: 900px) {
  /* Needs-Body: kein horizontaler Überlauf */
  .company-needs-tab-body {
    max-width: 100%;
    overflow-x: hidden;
  }

  /* Need-Item: Flex-Kind braucht min-width:0 damit Ellipsis greift */
  .company-need-item {
    max-width: 100%;
    min-width: 0;
  }

  /* Header-Row: Skill-Block + Priority + Trash umbrechen */
  .company-need-item-header {
    flex-wrap: wrap;
  }

  /* Priority-Select wird voll breit (kein 7rem-Fix neben Skill) */
  .company-need-priority {
    width: 100%;
  }

  /* Sub-Filter-Leiste: horizontal scrollbar, kein Umbrechen bei vielen Projekten */
  .company-needs-subfilter {
    overflow-x: auto;
    flex-wrap: nowrap;
    padding-bottom: .25rem;
    /* Scrollbar-Spur nicht anzeigen (Webkit) */
    -webkit-overflow-scrolling: touch;
  }

  /* Skill-Suggest-Input voll breit */
  .company-needs-add {
    max-width: 100%;
  }

  /* Skill-Suggest-Dropdown kann nicht über Viewport-Rand hinaus */
  .ds-skill-suggest-list {
    max-width: 100%;
  }

  /* Skonto-Grid: 1 Spalte auf Mobile */
  .companies-skonto-grid {
    grid-template-columns: 1fr;
  }
}

/* ── Company Needs: Skill-Suggest-Dropdown ──────────────────────────────── */
/* Bug-Fix 17.05: Card hat overflow:hidden — überschreiben wenn Bedarf-Tab aktiv */
.card:has(.company-needs-tab-wrapper) {
  overflow: visible;
}
.company-needs-tab-wrapper {
  position: relative;
}
.ds-skill-suggest-list {
  position: absolute;
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  max-height: 320px;
  overflow-y: auto;
  z-index: 1000;
}
.ds-skill-suggest-item {
  padding: .5rem .75rem;
  cursor: pointer;
  min-height: 44px;
  display: flex;
  flex-direction: column;
  gap: .125rem;
  border-bottom: 1px solid var(--border);
}
.ds-skill-suggest-item:hover,
.ds-skill-suggest-item.is-active {
  background: var(--accent-light);
}
.ds-skill-suggest-name { font-weight: 500; }
.ds-skill-suggest-category { font-size: 0.75rem; color: var(--text-tertiary); }
.ds-skill-suggest-empty {
  padding: .75rem;
  color: var(--text-tertiary);
  text-align: center;
  font-size: .875rem;
}

/* ── Company: Kundennummer-Zeile mit Lock + Generate (C1) ───── */
.company-cn-locked {
  flex: 1;
  background: var(--bg-secondary);
  color: var(--text-secondary);
  cursor: default;
  pointer-events: none;
  opacity: .8;
}

.company-cn-lock-icon {
  flex-shrink: 0;
  color: var(--text-tertiary);
  opacity: .7;
}

.company-cn-generate {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  background: var(--accent-light);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}

.company-cn-generate:hover:not(:disabled) {
  background: var(--accent);
  color: #fff;
}

.company-cn-generate:disabled {
  opacity: .4;
  cursor: not-allowed;
}

@media (max-width: 600px) {
  .contact-customer-number-row {
    flex-wrap: wrap;
  }
  .contact-customer-number-profile {
    flex-basis: 100%;
    min-width: unset;
  }
  .company-cn-locked,
  .contact-customer-number-row .input {
    flex: 1;
    min-width: 0;
  }
}

/* ── Kundennummern im Detail-Header (top-right) ─────────────── */
.company-cn-header-block {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  align-items: flex-end;
  flex-shrink: 0;
  margin-right: .25rem;
}
.company-cn-header-item {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}
.company-cn-header-label {
  font-size: 0.6875rem;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
  line-height: 1.2;
}
.company-cn-header-value {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 600px) {
  .company-cn-header-block {
    display: none;
  }
}

/* ── Kundenpreise-Sektion (F4, Paket C) ───────────────────── */
.company-cp-spinner {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: 1rem 0;
  color: var(--text-tertiary);
  font-size: .875rem;
}

.company-cp-empty {
  color: var(--text-tertiary);
  font-size: .875rem;
  margin: .25rem 0 .75rem;
}

/* Liste der vorhandenen Kundenpreise */
.company-cp-list {
  display: flex;
  flex-direction: column;
  gap: .375rem;
  margin-bottom: 1rem;
}

.company-cp-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: .5rem;
  padding: .5rem .625rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color var(--transition);
}

.company-cp-row--editing {
  border-color: var(--accent);
  background: var(--accent-light);
  grid-template-columns: minmax(0, 1fr);
}

.company-cp-row-name {
  display: flex;
  flex-direction: column;
  gap: .125rem;
  min-width: 0;
}

.company-cp-product-name {
  font-weight: 500;
  font-size: .875rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.company-cp-override-name {
  font-size: .75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.company-cp-row-values {
  display: flex;
  align-items: center;
  gap: .75rem;
  font-size: .875rem;
  flex-shrink: 0;
}

.company-cp-price {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}

.company-cp-unit {
  color: var(--text-secondary);
  min-width: 3rem;
}

.company-cp-tax {
  color: var(--text-tertiary);
  font-size: .8125rem;
  min-width: 3.5rem;
}

.company-cp-row-actions {
  display: flex;
  gap: .25rem;
  flex-shrink: 0;
}

/* Inline-Bearbeiten-Felder */
.company-cp-edit-fields {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: .5rem;
  padding: .25rem 0;
}

.company-cp-edit-field {
  display: flex;
  flex-direction: column;
  gap: .25rem;
}

.company-cp-edit-actions {
  display: flex;
  gap: .25rem;
  align-items: flex-end;
  padding-bottom: .125rem;
}

/* Vorhandenes Produkt hinzufügen */
.company-cp-add-section {
  margin-top: .75rem;
  padding-top: .75rem;
  border-top: 1px dashed var(--border);
}

.company-cp-add-label {
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  margin-bottom: .5rem;
}

.company-cp-add-row {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: .5rem;
}

.company-cp-add-picker {
  flex: 1;
  min-width: 10rem;
}

/* Neues Produkt anlegen */
.company-cp-new-section {
  margin-top: .75rem;
  padding-top: .625rem;
  border-top: 1px dashed var(--border);
}

.company-cp-new-toggle {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  background: none;
  border: none;
  padding: .25rem 0;
  font-size: .875rem;
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--transition);
}

.company-cp-new-toggle:hover {
  color: var(--accent-dark);
}

.company-cp-new-form {
  margin-top: .75rem;
  padding: .875rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  display: flex;
  flex-direction: column;
  gap: .75rem;
}

.company-cp-new-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .625rem .75rem;
}

.company-cp-new-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .5rem;
}

/* Mobile */
@media (max-width: 600px) {
  .company-cp-row {
    grid-template-columns: 1fr;
    gap: .375rem;
  }
  .company-cp-row-values {
    justify-content: flex-start;
  }
  .company-cp-row-actions {
    justify-content: flex-end;
  }
  .company-cp-add-row {
    flex-direction: column;
    align-items: stretch;
  }
  .company-cp-add-picker {
    flex: unset;
    width: 100%;
  }
  .company-cp-edit-fields {
    flex-direction: column;
    align-items: stretch;
  }
  .company-cp-new-grid {
    grid-template-columns: 1fr;
  }
  .company-cp-new-actions {
    flex-direction: column;
    align-items: stretch;
  }
}

/* ── Company Rollup / Pipeline-KPI-Zeile (P7) ──────────────── */
.company-rollup-bar {
  display: flex;
  gap: .625rem;
  flex-wrap: wrap;
  margin-bottom: .125rem;
}

.company-rollup-item {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  padding: .375rem .75rem;
  min-width: 96px;
  flex-shrink: 0;
  cursor: default;
  transition: background var(--transition);
}

.company-rollup-item--clickable {
  cursor: pointer;
}

.company-rollup-item--clickable:hover {
  background: var(--accent-light);
}

.company-rollup-label {
  font-size: .68rem;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
  white-space: nowrap;
}

.company-rollup-value {
  font-size: .9rem;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
}

.company-rollup-sub {
  font-size: .7rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* Mobile: horizontal scroll wenn kein Platz */
@media (max-width: 900px) {
  .company-rollup-bar {
    flex-wrap: nowrap;
    overflow-x: auto;
    padding-bottom: .125rem;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .company-rollup-bar::-webkit-scrollbar {
    display: none;
  }
}

/* ── Firmen-Hierarchie / Org-Tree (P10) ─────────────────────── */

/* Card-Body Wrapper */
.company-hierarchy-body {
  padding: .875rem 1.25rem 1rem;
  display: flex;
  flex-direction: column;
  gap: .875rem;
}

/* Breadcrumb: Wurzel › … › Parent › Aktuelle Firma */
.company-hierarchy-breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .25rem .1rem;
  font-size: .875rem;
  line-height: 1.4;
}

.company-hierarchy-breadcrumb-hint {
  font-size: .8125rem;
  color: var(--text-tertiary);
  font-style: italic;
}

.company-hierarchy-crumb-item {
  background: none;
  border: none;
  padding: .125rem .375rem;
  font-size: .875rem;
  color: var(--accent);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background var(--transition), color var(--transition);
  min-height: 28px;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.company-hierarchy-crumb-item:hover {
  background: var(--accent-light);
  color: var(--accent-dark);
  text-decoration: none;
}

.company-hierarchy-crumb-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.company-hierarchy-crumb-sep {
  color: var(--text-tertiary);
  font-size: .875rem;
  padding: 0 .1rem;
  user-select: none;
}

.company-hierarchy-crumb-current {
  font-weight: 600;
  color: var(--text-primary);
  padding: .125rem .375rem;
  font-size: .875rem;
}

/* Section-Trennlabel */
.company-hierarchy-section-label {
  font-size: .6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-tertiary);
  margin-bottom: -.25rem;
}

/* CSS Indent-Tree (VS-Code style — border-left als Verbindungslinie) */
.company-tree {
  display: flex;
  flex-direction: column;
  gap: 0;
  border-left: 2px solid var(--border);
  margin-left: .625rem;
  padding-left: 0;
}

.company-tree-node {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .3rem .625rem .3rem 1rem;
  position: relative;
  min-height: 44px;
  border-bottom: 1px solid var(--border);
  transition: background var(--transition);
}

.company-tree-node:last-child {
  border-bottom: none;
}

/* Horizontaler Ast-Strich */
.company-tree-node::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  width: .875rem;
  height: 0;
  border-top: 2px solid var(--border);
  transform: translateY(-50%);
}

.company-tree-node:hover {
  background: var(--bg-secondary);
}

.company-tree-node-name {
  background: none;
  border: none;
  padding: 0;
  font-size: .9rem;
  font-weight: 500;
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
  flex: 1;
  min-width: 0;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color var(--transition);
  min-height: 30px;
  display: flex;
  align-items: center;
}

.company-tree-node-name:hover {
  color: var(--accent-dark);
  text-decoration: none;
}

.company-tree-node-name:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.company-tree-node-meta {
  display: flex;
  align-items: center;
  gap: .375rem;
  flex-shrink: 0;
}

.company-tree-node-count {
  font-size: .75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* Empty + Siblings */
.company-hierarchy-empty-wrap {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
}

.company-hierarchy-empty {
  margin: 0;
  font-size: .875rem;
  color: var(--text-tertiary);
  font-style: italic;
}

.company-hierarchy-siblings {
  margin: 0;
  font-size: .8125rem;
  color: var(--text-tertiary);
  padding-top: .25rem;
  border-top: 1px dashed var(--border);
}

/* Mobile */
@media (max-width: 900px) {
  .company-hierarchy-body {
    padding: .75rem 1rem .875rem;
  }
  .company-tree-node {
    flex-wrap: wrap;
    gap: .25rem .5rem;
  }
  .company-tree-node-meta {
    flex-wrap: wrap;
  }
}

/* ── Mobile: Firmen-Detail Karten niemals breiter als Viewport ──────────────
   Alle Cards + Flex-Kinder in .grid-sidebar bekommen min-width:0 damit
   kein horizontaler Overflow entsteht (Ergänzung zu layout.css:380 die
   bereits 1-Spalten-Stack erzwingt, aber min-width bei Flex-Kindern nicht
   setzt). Lange URLs/Strings umbrechen via overflow-wrap:anywhere.
   .company-detail-tab-nav bleibt horizontal scrollbar (kein overflow-clip). */
@media (max-width: 900px) {
  /* Stammdaten-Grid: Label-Spalte auf schmalem Viewport schmäler */
  .company-sd-row {
    grid-template-columns: 6rem 1fr;
  }
  /* Detail-Tab-Leiste horizontal scrollbar (Tab-Texte nicht abschneiden) */
  .company-detail-tab-nav {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    flex-wrap: nowrap;
  }
  .company-detail-tab-nav::-webkit-scrollbar { display: none; }
  /* Detail-Tab-Leiste Buttons nicht quetschen */
  .company-detail-tab-nav .tab-filter-btn {
    flex-shrink: 0;
  }
}

/* ── NDA-Sektion (Dokumente-Tab) ─────────────────────────────────────────── */

/* Button-Reihe unter der NDA-Karte */
.nda-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .625rem;
  align-items: center;
}

/* Platzhalter-Referenz-Chips im Editor-Panel */
.nda-placeholder-hints {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .625rem .875rem;
}

.nda-placeholder-chip {
  display: inline-block;
  font-family: var(--font-mono, monospace);
  font-size: .75rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-xs, 3px);
  padding: .1em .4em;
  color: var(--text-secondary);
  white-space: nowrap;
}

/* Hinweis-Banner im Editor-Panel (kein Profil) */
.nda-notice {
  padding: .625rem .875rem;
  border-radius: var(--radius-sm);
  font-size: .875rem;
}

.nda-notice--warn {
  background: color-mix(in srgb, var(--amber) 12%, var(--bg-primary));
  border: 1px solid color-mix(in srgb, var(--amber) 35%, var(--border));
  color: var(--text-primary);
}

/* Spinner-Keyframe (falls nicht global definiert) */
@keyframes spin {
  to { transform: rotate(360deg); }
}

@media (max-width: 900px) {
  .nda-actions {
    flex-direction: column;
    align-items: stretch;
  }
  .nda-actions .btn,
  .nda-actions label.btn {
    width: 100%;
    text-align: center;
    justify-content: center;
  }
}

/* ── Firmen — F1 Inline-Style-Ablösung (2026-07-07) ────────────────────────── */

/* Modifier: Mehrzeiliger Stammdaten-Wert (Adressen, Notizen) — Basis .company-sd-value oben */
.company-sd-value--pre { white-space: pre-line; }

/* Klickbare Listen-Zeile (Deals/Angebote/Rechnungen im Firmen-Detail) */
.co-list-row-clickable {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 1.25rem;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.co-list-row-body  { padding: 0.25rem 0; }
.co-list-row-value { font-weight: 600; }

/* Kundenpreis-Editier-Felder (Basis + Neu-Zeile) — Breiten-Cap für Zahlen/kurzen Text */
.co-cp-edit-w8 { max-width: 8rem; }
.co-cp-edit-w7 { max-width: 7rem; }
.co-cp-edit-w6 { max-width: 6rem; }

/* Avatar-Fallback-Chip (Accent statt zufälliger Farbe) im Firmen-Detail-Header */
.co-avatar-accent {
  background: var(--accent-light);
  color: var(--accent);
  border-radius: var(--radius-md);
}

/* Parent-/Child-Picker: Speichern-Zeile rechtsbündig */
.co-picker-actions {
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
  padding-top: 0.5rem;
}

/* Mobile: In-Page-H1 redundant — App-Shell-Kopfleiste zeigt den Modulnamen bereits (P3 design-system.md).
   Ganze .page-header ausblenden statt nur h1: .page-header-actions ist auf Mobile ohnehin global
   versteckt (layout.css) — ohne diesen Fix bleibt eine leere .page-header-Box mit margin-bottom stehen
   (sichtbarer Leerraum ueber der Suche). */
@media (max-width: 900px) {
  page-companies .page-header { display: none; }
}

/* ── Partner-Selbstauskunft (Spec 20260720_partner_self_disclosure.md, Phase 6b) ──
   Link-Erzeugen-Panel + Review-Split-Screen. Neu, da hejdesk kein bestehendes
   "Feld-Diff mit Übernahme-Toggle"-Pattern hat (design-system.md nachgetragen). */

/* Link-Erzeugen-Panel */
.disclosure-link-result { display: flex; flex-direction: column; gap: 0.5rem; }
.disclosure-link-row { display: flex; gap: 0.5rem; align-items: center; }
.disclosure-link-row .input { flex: 1; font-family: monospace; font-size: 0.8125rem; }
.disclosure-hint { font-size: 0.8125rem; color: var(--text-secondary); margin: 0.25rem 0 0; }
.disclosure-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-height: 2.25rem;
}
.disclosure-toggle-label { font-size: 0.875rem; color: var(--text-primary); }
.disclosure-checkbox-row { display: flex; align-items: center; gap: 0.625rem; margin-top: 0.5rem; }

.disclosure-links-section { display: flex; flex-direction: column; gap: 0.625rem; }
.disclosure-links-heading {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
}
.disclosure-link-item {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.625rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}
.disclosure-link-item-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.disclosure-link-item-contact { font-size: 0.875rem; font-weight: 500; }
.disclosure-link-item-meta { font-size: 0.8125rem; color: var(--text-secondary); }
.disclosure-link-item-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* Review-Split-Screen */
.disclosure-review { display: flex; flex-direction: column; gap: 1rem; }
.disclosure-review-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.disclosure-review-meta { font-size: 0.8125rem; color: var(--text-tertiary); }

.disclosure-field-row {
  border-bottom: 1px solid var(--border);
  padding: 0.5rem 0;
}
.disclosure-field-row:last-child { border-bottom: none; }
.disclosure-field-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}
.disclosure-field-label { font-size: 0.875rem; font-weight: 500; color: var(--text-primary); }
.disclosure-field-row-body {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-top: 0.375rem;
}
.disclosure-field-current,
.disclosure-field-new {
  flex: 1;
  min-width: 9rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}
.disclosure-field-new { color: var(--text-primary); }
.disclosure-field-arrow { color: var(--text-tertiary); flex-shrink: 0; }
.disclosure-field-tag {
  display: block;
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
}

.disclosure-image-row { border-bottom: 1px solid var(--border); padding: 0.5rem 0; }
.disclosure-image-row:last-child { border-bottom: none; }
.disclosure-image-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
}
.disclosure-image-preview {
  width: 100%;
  max-width: 12rem;
  height: 8rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  overflow: hidden;
}
.disclosure-image-preview img { max-width: 100%; max-height: 100%; object-fit: contain; }

.disclosure-skill-chip-list { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-top: 0.375rem; }
/* #9 (2026-07-21): Katalog-Skills sind jetzt einzeln (nicht mehr alles-oder-nichts)
   uebernehmbar — der Chip selbst ist der Toggle (Button statt Span), Vorbild
   .pd-skill-chip/.is-selected im oeffentlichen Formular (p/assets/partner-disclosure.css). */
.disclosure-skill-chip {
  display: inline-flex;
  align-items: center;
  padding: 0.1875rem 0.625rem;
  border-radius: 999px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  font-size: 0.8125rem;
  font-family: inherit;
  color: var(--text-primary);
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.disclosure-skill-chip:hover { border-color: var(--accent); }
.disclosure-skill-chip.is-accepted {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.disclosure-message-box {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.625rem 0.75rem;
  font-size: 0.875rem;
  color: var(--text-primary);
  white-space: pre-wrap;
}

@media (max-width: 900px) {
  .disclosure-field-current,
  .disclosure-field-new {
    min-width: 100%;
  }
  .disclosure-field-arrow { display: none; }
}

/* ── Firmen-Detail: read-only Partner-Tab (G7, 2026-07-21) ──────────────────
   Zeigt die aus einer Selbstauskunft/Katalog uebernommenen Skills + die
   Stundensatz-Range in der Detail-Ansicht (nicht nur im Edit-Formular). */
.company-detail-partner-loading {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 0;
  color: var(--text-secondary);
  font-size: 0.875rem;
}
.company-detail-rate-stack {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

/* ── Bestellnummer (BT-13, B61) — Finanzen-Tab, "Verlangt Bestellnummer"-Zeile ── */
.companies-po-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.companies-po-toggle-row .form-label {
  margin: 0;
}

/* ── "Anbieter & Anfragen"-Panel (Ticket 3.120, Paket 3) ──────────────────
   Geteilt zwischen page-company-needs (Arbeitsliste) und companies.js
   (firmenscoped Bedarf-Tab) — s. pages/_need-request-panel.js. */
.company-need-requests-context {
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 1rem;
}
.company-need-requests-section {
  margin-bottom: 1.5rem;
}
.company-need-requests-section:last-child {
  margin-bottom: 0;
}
.company-need-requests-section-title {
  font-size: .6875rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  font-weight: 600;
  margin-bottom: .5rem;
}
.company-need-requests-empty {
  color: var(--text-tertiary);
  font-size: .8125rem;
  padding: .375rem 0;
}
.company-need-provider-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--border);
}
.company-need-provider-row:last-child {
  border-bottom: none;
}
/* Ticket 3.120 Rückläufer (3.): Body-Wrapper für Main-Zeile + Skill-Zeile,
   damit der „Anfragen"-Button am Zeilenende bleibt, waehrend der linke
   Bereich auf zwei Zeilen wachsen kann. */
.company-need-provider-body {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  min-width: 0;
  flex: 1 1 auto;
}
.company-need-provider-main {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
  min-width: 0;
}
/* Domenico-Rückläufer (22.08.2026, Ticket 3.120): Der Name war unter den
   umliegenden gefüllten Badges (Typ, "Bereits angefragt") kaum lesbar —
   deshalb jetzt der visuelle Anker der Zeile: font-weight/-size auf
   .native-row-title-Niveau (0.9375rem/600, s. frontend.md-Listen-Skala)
   statt der bisherigen 500/.875rem. Typ- und "Bereits angefragt"-Hinweis
   sind im Gegenzug auf dezente Icon+Text-Muster umgestellt (s.u.). */
.company-need-provider-name {
  font-weight: 600;
  font-size: .9375rem;
}
.company-need-provider-rate {
  font-size: .75rem;
  color: var(--text-tertiary);
}
/* Typ-Kennzeichnung (Firma/Kontakt) — dezentes 14px-Icon mit Tooltip statt
   gefüllter Badge (ersetzt .badge.badge-neutral/.badge-purple in der
   Anbieter-Zeile; die Anfragen-Liste darunter behält ihre Badges
   unverändert, s. _renderRequestRow). */
.company-need-provider-type-icon {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  color: var(--text-tertiary);
}
/* "Bereits angefragt"-Hinweis — Statusinfo, kein Alarm: gedämpfter Text
   statt gefüllter Amber-Badge, Haken in --teal (Konvention "erledigt/
   positiv", analog .ds-bookkeeping-tx-state--assigned). */
.company-need-provider-asked-hint {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}
.company-need-provider-asked-hint svg {
  color: var(--teal);
  flex-shrink: 0;
}
/* Ticket 3.120 Rückläufer (3.): Skill-Zeile je Treffer — Ein-Zeiler mit
   Ausklapp-Toggle ab MAX_INLINE_SKILLS (s. _need-request-panel.js). */
.company-need-provider-skills {
  display: flex;
  align-items: center;
  gap: .3125rem;
  flex-wrap: nowrap;
  overflow: hidden;
  /* Flex-Item in einer Column (.company-need-provider-body) mit nowrap-Kindern:
     ohne min-width:0 verweigert das Element das Schrumpfen unter die
     Content-Breite seiner Chips — die Zeile läuft dann über den Kartenrand
     hinaus statt zu clippen (Mobile-Bug, per Puppeteer nachgewiesen). */
  min-width: 0;
}
.company-need-provider-skills.is-expanded {
  flex-wrap: wrap;
}
.company-need-provider-skill-chip {
  /* Domenico-Rückläufer (22.08.2026): ruhiger Outline-Chip statt gefülltem
     .badge.badge-purple — max. 3 sichtbar (s. MAX_INLINE_SKILLS), Chips
     sollen nicht mehr Gewicht ziehen als der Anbieter-Name. */
  display: inline-flex;
  align-items: center;
  padding: .0625rem .5rem;
  border-radius: 99px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  font-size: .6875rem;
  font-weight: 500;
  /* Schrumpft (statt fix zu bleiben) + ellipsized einzeln — garantiert, dass
     der Ausklapp-Toggle (flex-shrink:0) auf JEDER Breite sichtbar bleibt,
     statt auf schmalen Mobile-Viewports aus der Zeile gedrängt zu werden
     (Bug per Puppeteer nachgewiesen, s. company-need-provider-skills). */
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.company-need-provider-skills.is-expanded .company-need-provider-skill-chip {
  flex-shrink: 0;
}
.company-need-provider-skills-toggle {
  background: none;
  border: none;
  padding: 0;
  font-size: .6875rem;
  font-weight: 600;
  color: var(--text-tertiary);
  cursor: pointer;
  flex-shrink: 0;
  white-space: nowrap;
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--transition);
}
.company-need-provider-skills-toggle:hover {
  color: var(--accent);
}
.company-need-provider-skills-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: 2px;
}
.company-need-request-row {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .625rem .75rem;
  margin-bottom: .5rem;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.company-need-request-row:last-child {
  margin-bottom: 0;
}
.company-need-request-row-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
}
.company-need-request-provider-name {
  font-weight: 500;
  font-size: .875rem;
}
.company-need-request-timestamp {
  margin-left: auto;
  font-size: .75rem;
  color: var(--text-tertiary);
}
.company-need-request-row-body {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}
.company-need-request-result-select {
  min-width: 8rem;
  font-weight: 500;
}
.company-need-request-result-select--open      { color: var(--text-secondary); }
.company-need-request-result-select--accepted  { color: var(--teal); }
.company-need-request-result-select--declined  { color: var(--coral); }
.company-need-request-rate-input {
  width: 6.5rem;
  flex-shrink: 0;
}
.company-need-request-notes-input {
  flex: 1 1 12rem;
  min-width: 0;
}

/* ── "Anbieter & Anfragen"-Panel: Mobile-Stacking (≤900px) ───────────────── */
@media (max-width: 900px) {
  .company-need-provider-row {
    flex-wrap: wrap;
  }
  .company-need-request-rate-input,
  .company-need-request-notes-input {
    width: 100%;
    flex-basis: 100%;
  }
}

/* ── Partner-Tab: Gegenrichtung "Passende offene Bedarfe" (Ticket 3.120, Paket 4) ── */
.company-detail-matches-list {
  display: flex;
  flex-direction: column;
}
.company-detail-matches-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .625rem 0;
  border-bottom: 1px solid var(--border);
}
.company-detail-matches-row:last-child {
  border-bottom: none;
}
.company-detail-matches-main {
  display: flex;
  flex-direction: column;
  gap: .1875rem;
  min-width: 0;
}
.company-detail-matches-actions {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-shrink: 0;
}

@media (max-width: 900px) {
  .company-detail-matches-row {
    flex-wrap: wrap;
  }
}


/* ── Kontakte — F1 Inline-Style-Ablösung (2026-07-07) ───────────────────────── */

/* Notizen-/Belege-Karten-Header: oberer/unterer Padding-Split (statt einem Block) */
.ct-panel-header-top  { padding: 0.75rem 1.25rem 0.5rem; }
.ct-panel-header-body { padding: 0 1.25rem 0.75rem; }

/* Skeleton-Bar-Breiten (Basisklasse .skeleton-bar) für Notizen-/Belege-Ladezustand */
.ct-skeleton-w80 { width: 80%; height: 0.875rem; margin: 0.25rem 0; }
.ct-skeleton-w60 { width: 60%; height: 0.875rem; margin: 0.25rem 0; }

/* Visitenkarte-Vorschau (Vorder-/Rückseite) */
.ct-businesscard-img {
  width: 100%;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  cursor: zoom-in;
  object-fit: contain;
  max-height: 180px;
}
.ct-businesscard-label {
  font-size: 0.75rem;
  color: var(--text-secondary);
  margin-bottom: 0.4rem;
}
.ct-businesscard-col { flex: 1; min-width: 140px; }

/* Mobile: In-Page-H1 redundant — App-Shell-Kopfleiste zeigt den Modulnamen bereits (P3 design-system.md).
   Ganze .page-header ausblenden statt nur h1: .page-header-actions ist auf Mobile ohnehin global
   versteckt (layout.css) — ohne diesen Fix bleibt eine leere .page-header-Box mit margin-bottom stehen
   (sichtbarer Leerraum ueber der Suche). */
@media (max-width: 900px) {
  page-contacts .page-header { display: none; }
}
/* ── Time-Tracking ──────────────────────────────────────────────────────── */

/* Mobile Trigger-Pill (hidden on Desktop) ---------------------------------- */
.ds-time-quick-bar-trigger {
  display: none; /* sichtbar nur auf Mobile via Media-Query */
}

/* Bottom-Sheet (hidden on Desktop) ---------------------------------------- */
.ds-time-quick-bar-sheet {
  display: none; /* sichtbar nur auf Mobile via Media-Query */
}

/* Quick-Bar ---------------------------------------------------------------- */
.ds-time-quick-bar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .375rem;
  display: flex;
  flex-direction: column;
  gap: .35rem;
  width: 100%;
  max-width: 100%;
  margin-bottom: 1rem;
}

.ds-time-quick-input-wrap {
  display: flex;
  align-items: flex-start; /* Textarea wächst nach unten: Buttons oben ausrichten */
  gap: .375rem;
}

/* Inner wrapper — position:relative so .ds-time-quick-input-clear anchors
   to the textarea area rather than the outer flex-wrap (Fix 2026-06-10) */
.ds-time-quick-input-field {
  position: relative;
  flex: 1;
  min-width: 0;
}

/* Textarea-Variante (Session B 1.1): auto-growing, min 36px, max 40vh dann scrollbar */
.ds-time-quick-input {
  flex: 1;
  width: 100%; /* fills .ds-time-quick-input-field */
  min-height: 36px;
  max-height: 40vh;
  padding: .4375rem 2.25rem .4375rem .75rem; /* vertikal zentriert bei 1 Zeile ≈ 36px */
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: .875rem;
  font-family: inherit;
  line-height: 1.45;
  resize: none;                     /* kein manuelles Resize-Handle */
  overflow-y: hidden;               /* Default kein Balken; JS (_autoResizeTextarea) schaltet bei Überlauf > 40vh auf auto — verhindert Hairline-Scrollbar bei 1 Zeile */
  transition: border-color var(--transition), box-shadow var(--transition);
  outline: none;
  min-width: 0;
  box-sizing: border-box;
  display: block;
}
.ds-time-quick-input::placeholder { color: var(--text-tertiary); }
.ds-time-quick-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(0,55,128,.12);
  background: var(--bg-primary);
}
:root[data-theme="dark"] .ds-time-quick-input:focus {
  box-shadow: 0 0 0 3px rgba(77,133,224,.18);
}

/* X-Button: top-right, bleibt oben als Textarea wächst (Session B 1.7) */
.ds-time-quick-input-clear {
  position: absolute;
  right: .375rem;
  top: 0.25rem;        /* (36px minHeight − 28px btnHeight) / 2 = 4px — zentriert bei 1 Zeile; bleibt oben bei mehreren Zeilen */
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--text-tertiary);
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
}
.ds-time-quick-input-clear:hover {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}
/* Send-Button: align-self:flex-start weil wrap-align ist flex-start (Textarea) */
.ds-time-quick-input-send {
  flex-shrink: 0;
  white-space: nowrap;
  height: 32px;
  min-height: 32px;
  align-self: flex-start;
}

@media (max-width: 900px) {
  .ds-time-quick-input-send {
    height: 40px;
    min-height: 40px;
  }
}

/* Preview-Pill — absolute unter .ds-time-quick-input-wrap (kein Layout-Shift)
   Session B 1.5: Multi-Line-Support — eine Zeile pro Input-Zeile */
.ds-time-quick-preview {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 20;
  margin-top: .375rem;
  display: flex;
  align-items: flex-start;
  gap: .375rem;
  padding: .375rem .625rem;
  background: var(--accent-light);
  color: var(--accent);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
  font-weight: 500;
}

/* Container für Zeilen-Liste */
.ds-time-quick-preview-lines {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .25rem;
}

/* Einzelne Preview-Zeile */
.ds-time-quick-preview-line {
  display: flex;
  align-items: center;
  gap: .375rem;
  line-height: 1.35;
}
.ds-time-quick-preview-line > span {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Fehlerhafte Zeile: dezenter coral Hinweis */
.ds-time-quick-preview-line--error {
  color: var(--coral);
  opacity: .85;
  font-style: italic;
}
.ds-time-quick-preview-line--error > span {
  white-space: normal;
  word-break: break-word;
}

/* Inline-Validation-Hint (Pille analog Preview, aber Coral für Fehler) */
.ds-time-quick-error {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 21;                /* über Preview */
  margin-top: .375rem;
  display: flex;
  align-items: center;
  gap: .375rem;
  padding: .35rem .625rem;
  background: var(--coral-light);
  color: var(--coral);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
  font-weight: 500;
  line-height: 1.3;
}
.ds-time-quick-error-text {
  flex: 1;
  min-width: 0;
}
.ds-time-quick-preview--loading {
  background: var(--bg-secondary);
  color: var(--text-tertiary);
  font-weight: 400;
}
.ds-time-quick-preview-text {
  flex: 1;
  min-width: 0;
  overflow: visible;
  white-space: normal;
  word-break: break-word;
}
.ds-time-quick-preview-clear {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--accent);
  border-radius: 4px;
  padding: 0;
  transition: background var(--transition);
}
.ds-time-quick-preview-clear:hover { background: rgba(0,55,128,.15); }

/* Timer-Widget — DEPRECATED: timer removed 2026-05-20, kept for CSS-Compat */
.ds-time-quick-timer {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .2rem 0;
}
.ds-time-quick-timer--idle { }
.ds-time-quick-timer--active {
  color: var(--coral);
}
.ds-time-quick-timer-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--coral);
  flex-shrink: 0;
  animation: tt-pulse 1.4s ease-in-out infinite;
}
.ds-time-quick-timer-counter {
  font-size: .9375rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
}
.ds-time-quick-stop-btn {
  color: var(--coral) !important;
  border-color: var(--coral) !important;
}
.ds-time-quick-stop-btn:hover {
  background: var(--coral-light) !important;
}
.ds-time-quick-start-btn {
  color: var(--text-secondary);
}

/* B3: Profil-Select in Quick-Bar — DEPRECATED: replaced by .ds-time-quick-pickers-select (2026-05-20) */
.ds-time-quick-bar-profile-select {
  flex-shrink: 0;
  max-width: 13rem;
  font-size: .8125rem;
}

/* Picker-Defaults-Row (Profil + Firma + Projekt, 2026-05-20) */
.ds-time-quick-pickers {
  display: flex;
  align-items: center;
  gap: .375rem;
  flex-wrap: wrap;
  padding: .25rem 0;
}
/* <ds-company-picker> Wrapper im Quick-Bar — kompaktes Pill-Styling */
.ds-time-quick-pickers-picker {
  flex: 1 1 12rem;
  min-width: 10rem;
  max-width: 18rem;
}
/* Req 4: gleiche Höhe 36px wie Smart-Parse-Input */
.ds-time-quick-pickers-picker .ds-cp-wrap { height: 36px; }
.ds-time-quick-pickers-picker .ds-cp-input,
.ds-time-quick-pickers-picker .ds-cp-selected {
  height: 36px;
  min-height: 36px;
}
/* Req 2: nur Firmenname zeigen, keine Sub-Zeile (E-Mail / Kundennr.) */
.ds-time-quick-pickers-picker .ds-cp-selected-email,
.ds-time-quick-pickers-picker .ds-cp-detail-link {
  display: none !important;
}
/* Profil-Select + Projekt-Select im Quick-Bar — auf Smart-Input-Höhe (36px) */
.ds-time-quick-pickers-select,
.ds-time-quick-pickers .select.ds-time-quick-pickers-select {
  flex: 0 1 10rem;
  min-width: 8rem;
  font-size: .8125rem;
  height: 36px;
  min-height: 36px;       /* override globale .select min-height:44px */
  padding: 0 1.75rem 0 .75rem;
  line-height: 1;
  box-sizing: border-box;
}

/* @-Mention Dropdown — absolut unter .ds-time-quick-input-wrap (Req 3, 2026-05-20) */
.ds-time-mention-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 220;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  max-height: 280px;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: .25rem 0;
}
/* Reuse .ds-picker-top-* und .ds-cp-item vom company-picker — gleiche Optik */
.ds-time-mention-dropdown .ds-cp-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .75rem;
  min-height: 36px;
  cursor: pointer;
  font-size: .875rem;
  color: var(--text-primary);
}
.ds-time-mention-dropdown .ds-cp-item.is-active,
.ds-time-mention-dropdown .ds-cp-item:hover {
  background: var(--accent-light);
  color: var(--accent);
}
.ds-time-mention-dropdown .ds-cp-item-name { font-weight: 500; }
.ds-time-mention-dropdown .ds-cp-item-sub  { font-size: .8rem; color: var(--text-tertiary); }

/* #-Mention Projekt-Dropdown — absolut unter .ds-time-quick-input-wrap (Req 1, 2026-05-20) */
.ds-time-proj-mention-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 220;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  max-height: 280px;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: .25rem 0;
}
.ds-time-mention-item {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: .125rem;
  padding: .5rem .75rem;
  min-height: 36px;
  cursor: pointer;
  font-size: .875rem;
  color: var(--text-primary);
  transition: background var(--transition), color var(--transition);
}
.ds-time-mention-item.is-active,
.ds-time-mention-item:hover {
  background: var(--accent-light);
  color: var(--accent);
}
.ds-time-mention-item.is-active .ds-time-mention-item-sub,
.ds-time-mention-item:hover .ds-time-mention-item-sub {
  color: var(--accent);
  opacity: .75;
}
.ds-time-mention-item-name {
  font-weight: 500;
  line-height: 1.2;
}
.ds-time-mention-item-sub {
  font-size: .775rem;
  color: var(--text-tertiary);
  line-height: 1.2;
}

/* ── Quick-Bar Projekt-Such-Combobox ──────────────────────────────────────── */
.ds-time-quick-proj-combo {
  position: relative;
  flex: 0 1 10rem;
  min-width: 8rem;
  display: flex;
}
.ds-time-quick-proj-combo-input {
  width: 100%;
  height: 36px;
  min-height: 36px;
  font-size: .8125rem;
  padding-right: 1.75rem;   /* Platz für X-Button */
  box-sizing: border-box;
}
.ds-time-quick-proj-combo-clear {
  position: absolute;
  right: .375rem;
  top: 50%;
  transform: translateY(-50%);
  border: none;
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: .125rem;
  border-radius: var(--radius-sm);
  transition: color var(--transition);
}
.ds-time-quick-proj-combo-clear:hover { color: var(--coral); }
.ds-time-quick-proj-combo-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 220;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  max-height: 260px;
  overflow-y: auto;
  list-style: none;
  padding: .25rem 0;
  margin: 0;
}
@media (max-width: 900px) {
  .ds-time-quick-proj-combo {
    flex: 1 1 100%;
    max-width: 100%;
  }
  .ds-time-quick-proj-combo-input {
    min-height: 44px;
    height: auto;
  }
}

/* Desktop: Input-Wrap + Pickers nebeneinander in einer Reihe */
@media (min-width: 901px) {
  .ds-time-quick-bar {
    flex-direction: row;
    align-items: center;
    gap: .375rem;
    flex-wrap: wrap;
    width: 100%;
    max-width: 100%;
  }
  /* Input-Wrap fuellt die gesamte verbleibende Breite (Picker behalten ihre natuerliche) */
  .ds-time-quick-input-wrap {
    flex: 1 1 0;
    min-width: 220px;
  }
  .ds-time-quick-pickers {
    flex: 0 0 auto;          /* nicht wachsen — nur so breit wie Inhalt */
    padding: 0;
    flex-wrap: nowrap;
  }
  .ds-time-quick-pickers-picker {
    flex: 0 0 13rem;          /* feste Breite — Lueckenfuellung übernimmt der Input */
  }
  /* Preview ist absolute positioniert — keine Flex-Overrides noetig */
  /* DEPRECATED timer position — kept for CSS-Compat */
  .ds-time-quick-timer {
    margin-left: auto;
    flex-shrink: 0;
  }
  .ds-time-quick-bar-profile-select {
    order: -1;
  }
}

/* Mobile: Pickers stapeln vertikal, volle Breite */
@media (max-width: 900px) {
  .ds-time-quick-bar {
    width: 100%;
  }
  .ds-time-quick-bar-profile-select {
    max-width: 100%;
    width: 100%;
  }
  .ds-time-quick-pickers {
    width: 100%;
  }
  .ds-time-quick-pickers-picker {
    flex: 0 0 auto;   /* Fix: in flex-column NICHT vertikal wachsen (war 1 1 100% -> riesige Box) */
    max-width: 100%;
  }
  .ds-time-quick-pickers-select {
    flex: 0 0 auto;   /* Fix: dito */
    min-width: 0;
  }
}

/* Pulse-Animation */
@keyframes tt-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%       { opacity: .5; transform: scale(1.25); }
}

/* Date-Navigation --------------------------------------------------------- */
.tt-date-nav {
  display: flex;
  align-items: center;
  gap: .25rem;
  padding: .25rem;
  background: var(--bg-tertiary);
  border-radius: var(--radius-md);
  margin: 0 0 .5rem;
  position: relative; /* Anker für cal-dp-dropdown */
  flex-wrap: wrap;
}
/* .tt-date-nav-label — durch cal-toolbar-date-btn ersetzt (Req 3 2026-05-20) */
.tt-date-nav-label {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--text-primary);
  flex: 1;
  text-align: center;
}

/* Suggestions-Zeile ------------------------------------------------------- */
.tt-suggestions-row {
  display: flex;
  align-items: center;
  gap: .375rem;
  padding: .375rem .75rem;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
}
.tt-suggestions-label {
  font-size: .75rem;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
  font-weight: 500;
  flex-shrink: 0;
}
.tt-suggestion-chip {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .2rem .625rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: .8125rem;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition), color var(--transition);
}
.tt-suggestion-chip:hover {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
}

/* Day-View Timeline ------------------------------------------------------- */
/* C1: Day-View Card-Wrap -------------------------------------------------- */
.tt-day-card {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: .75rem;
}

.tt-day-wrap {
  display: flex;
  gap: 0;
  padding: .5rem .75rem;
  overflow-x: hidden;
}

.tt-day-hours {
  position: relative;
  width: 44px;
  flex-shrink: 0;
  /* höhe durch TIMELINE_H_PX-Kinder impliziert */
}

.tt-day-hour-label {
  position: absolute;
  top: var(--tt-h-offset, 0);
  left: 0;
  width: 44px;
  font-size: .72rem;
  color: var(--text-tertiary);
  line-height: 1;
  transform: translateY(-50%);
  text-align: right;
  padding-right: .375rem;
  user-select: none;
}

.tt-day-grid {
  flex: 1;
  position: relative;
  min-width: 0;
  margin-left: .25rem;
}

.tt-day-gridline {
  position: absolute;
  top: var(--tt-top, 0);
  left: 0;
  right: 0;
  height: 1px;
  background: var(--border);
  pointer-events: none;
}

/* Timeline-Blöcke --------------------------------------------------------- */
/* Dezenter Block-Look (2026-05-20): Light-BG mit Akzent-Border-Left.
 * --tt-color       = volle Firmen-Farbe (Border + Text)
 * --tt-color-light = light variant (BG, dezente Tönung) */
.tt-block {
  position: absolute;
  top: var(--tt-top, 0);
  left: var(--tt-left, 1%);
  right: auto;
  width: var(--tt-w, calc(100% - 2%));
  height: var(--tt-h, 40px);
  background: var(--tt-color-light, var(--accent-light));
  border-left: 3px solid var(--tt-color, var(--accent));
  color: var(--tt-color, var(--accent));
  border-radius: var(--radius-sm);
  cursor: pointer;
  overflow: hidden;
  transition: background var(--transition), box-shadow var(--transition);
}
.tt-block:hover {
  box-shadow: var(--shadow-sm);
  z-index: 2;
  filter: brightness(0.98);
}
.tt-block--break {
  background: var(--bg-secondary) !important;
  color: var(--text-tertiary) !important;
  border-left: 3px dashed var(--border) !important;
}

/* C2: Block-Edge-Handles für Resize ---------------------------------------- */
.tt-block-resize-top,
.tt-block-resize-bot {
  position: absolute;
  left: 0;
  right: 0;
  height: 6px;
  cursor: ns-resize;
  z-index: 3;
  /* visueller Handle-Indikator */
}
.tt-block-resize-top { top: 0; }
.tt-block-resize-bot { bottom: 0; }

/* Handle-Strich (nur sichtbar bei Hover auf den Edge) */
.tt-block-resize-top::after,
.tt-block-resize-bot::after {
  content: '';
  display: block;
  width: 24px;
  height: 2px;
  background: rgba(255,255,255,.5);
  border-radius: 999px;
  margin: 1px auto 0;
}
.tt-block--break .tt-block-resize-top::after,
.tt-block--break .tt-block-resize-bot::after {
  background: var(--text-tertiary);
}

/* C2: Drag-Ghost-Block ------------------------------------------------------ */
.tt-drag-ghost {
  position: absolute;
  left: 2px;
  right: 2px;
  background: var(--accent);
  opacity: .35;
  border-radius: var(--radius-sm);
  border: 2px dashed var(--accent);
  pointer-events: none;
  z-index: 10;
  top: var(--tt-top, 0);
  height: var(--tt-h, 0);
}

/* C2: Drag-Cursor auf Grid -------------------------------------------------- */
.tt-day-grid--dragging {
  cursor: crosshair;
  user-select: none;
}

/* Block während Move — halbtransparent + kein Click durchleiten */
.tt-block.is-moving {
  opacity: .35 !important;
  transform: scale(1.02);
  box-shadow: var(--shadow-md);
  pointer-events: none;
  z-index: 5;
}

.tt-block-inner {
  display: flex;
  flex-direction: column;
  padding: .2rem .5rem;
  height: 100%;
  overflow: hidden;
  color: var(--text-primary);
  font-size: .75rem;
  line-height: 1.3;
  gap: .1rem;
}
.tt-block--break .tt-block-inner { color: var(--text-secondary); }

.tt-block-contact {
  font-weight: 600;
  font-size: .8rem;
  color: var(--tt-color, var(--text-primary));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tt-block-desc {
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tt-block-dur {
  margin-top: auto;
  font-size: .7rem;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}
.tt-block-pause {
  display: flex;
  align-items: center;
  color: var(--text-tertiary);
}

/* Lücken-Blöcke ---------------------------------------------------------- */
.tt-gap {
  position: absolute;
  top: var(--tt-top, 0);
  left: 2px;
  right: 2px;
  height: var(--tt-h, 30px);
  border: 1.5px dashed var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  background: transparent;
  transition: background var(--transition), border-color var(--transition);
  overflow: hidden;
}
.tt-gap:hover {
  background: var(--accent-light);
  border-color: var(--accent);
  color: var(--accent);
}
.tt-gap-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

/* Datepicker-Anker-Wrap (Teil 3 — fix positioning) ----------------------- */
/* Positionierungs-Wrapper: umschließt nur cal-toolbar-date-btn + Dropdown.  */
/* position:relative hier (statt auf .tt-date-nav) → Dropdown ankert korrekt*/
.tt-dp-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-width: 0; /* erlaubt Schrumpfen im 1-Zeilen-Kompakt-Layout Mobile (s.u.) */
}

/* Datum-Label kann schrumpfen + ellipsen statt Zeilenumbruch (Mobile-Kompakt-Layout) */
.tt-date-nav .cal-toolbar-date-btn {
  min-width: 0;
  max-width: 100%;
  flex: 1 1 auto;
}
.tt-date-nav .cal-toolbar-date-btn svg { flex-shrink: 0; }
.tt-date-nav-datelabel {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Generische Listen-View (Week/Month/Custom) ------------------------------ */
.tt-list-header {
  display: flex;
  align-items: center;
  justify-content: space-between; /* toggle links, total rechts */
  padding: .5rem .75rem;
  border-bottom: 1px solid var(--border);
}
.tt-list-total {
  font-size: .9rem;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

/* View-Toggle (Karten ↔ Liste) — Teil 5 ---------------------------------- */
.tt-view-toggle {
  display: inline-flex;
  align-items: center;
  gap: .125rem;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .125rem;
}
.tt-view-toggle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  background: transparent;
  border-radius: calc(var(--radius-sm) - 2px);
  color: var(--text-tertiary);
  cursor: pointer;
  transition: color var(--transition), background var(--transition);
  flex-shrink: 0;
}
.tt-view-toggle-btn:hover {
  color: var(--text-primary);
  background: var(--bg-secondary);
}
.tt-view-toggle-btn.is-active {
  color: var(--accent);
  background: var(--accent-light);
}
.tt-view-toggle-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
@media (max-width: 900px) {
  .tt-view-toggle-btn {
    width: 36px;
    height: 36px;
  }
}

/* Listen-Modus: kompakte Tages-Zeile ------------------------------------- */
/* Accordion: Chevron + Datum-Label (flex:1) + Gesamt-Dauer rechts          */
.tt-list-day-row {
  display: flex;
  align-items: center;
  gap: .375rem;
  padding: .5rem .75rem;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background var(--transition);
  font-size: .9rem;
}
.tt-list-day-row:hover {
  background: var(--accent-light);
}
.tt-list-day-row:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.tt-list-day-row-date {
  font-weight: 600;
  color: var(--text-primary);
}
.tt-list-day-row-total {
  font-size: .875rem;
  font-weight: 500;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 900px) {
  .tt-list-day-row {
    min-height: 44px; /* Touch-Target ≥ 44px */
  }
}

.tt-day-group {
  margin-bottom: .75rem;
}
.tt-day-group-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .5rem .75rem .25rem;
  font-size: .875rem;
  font-weight: 600;
  color: var(--text-primary);
  border-bottom: 1px solid var(--border);
}
.tt-day-group-total {
  font-size: .8125rem;
  font-weight: 500;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

/* Tages-Gruppen-Header: Datum + Sort-Toggle -------------------------------- */
.tt-day-group-date {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
}

/* Klickbares Datum-Label (4.1–4.3): setzt Datum in Schnell-Erfassung-Bar */
.tt-day-date-label {
  border: none;
  background: transparent;
  cursor: pointer;
  color: inherit;
  font-size: inherit;
  font-weight: inherit;
  padding: 0 .1875rem;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
  line-height: inherit;
}
.tt-day-date-label:hover {
  color: var(--accent);
  background: var(--accent-light);
}
.tt-day-date-label:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
@media (max-width: 900px) {
  .tt-day-date-label {
    min-height: 28px;
    display: inline-flex;
    align-items: center;
  }
}

/* Sort-Toggle-Button rechts neben dem Datums-Label ------------------------- */
.tt-day-sort-btn {
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--text-tertiary);
  padding: .125rem;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  min-height: 24px;
  transition: color var(--transition), background var(--transition);
  flex-shrink: 0;
}
.tt-day-sort-btn:hover {
  color: var(--accent);
  background: var(--accent-light);
}
.tt-day-sort-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
/* asc = Pfeil zeigt nach oben (Chevron um 180° rotiert) */
.tt-day-sort-btn.is-asc svg {
  transform: rotate(180deg);
}
/* desc = Pfeil zeigt nach unten (Standard-Chevron-Richtung) */
.tt-day-sort-btn.is-desc svg {
  transform: rotate(0deg);
}
.tt-day-sort-btn svg {
  transition: transform var(--transition);
  display: block;
}

/* Mobile: etwas größeres Touch-Target */
@media (max-width: 900px) {
  .tt-day-sort-btn {
    min-width: 28px;
    min-height: 28px;
  }
}

/* Empty-State ------------------------------------------------------------- */
.tt-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 3rem 1.5rem;
  text-align: center;
  color: var(--text-secondary);
  gap: .75rem;
  font-size: .9rem;
}
.tt-empty-state p { margin: 0; }

/* Mobile ------------------------------------------------------------------ */
@media (max-width: 900px) {
  page-time-tracking .page-header-h1 { display: none; }
  page-time-tracking .page-header-actions { display: none; }

  .tt-day-hours { width: 36px; }
  .tt-day-hour-label {
    font-size: .65rem;
    padding-right: .25rem;
  }

  .tt-date-nav-label { font-size: .875rem; }

  /* Kompakt-1-Zeilen-Layout Tag/Woche/Monat: links Datums-Navi (~halbe Breite,       */
  /* Label ellipst), rechts Icon-Gruppe (Heute/Rechnung/Nur Externe/Kalender).        */
  /* Custom-View (zwei Date-Inputs) bleibt unverändert im alten Wrap-Layout.          */
  .tt-date-nav--single-line {
    flex-wrap: nowrap;
  }
  .tt-date-nav--single-line .tt-dp-wrap {
    flex: 1 1 auto;
  }
  .tt-date-nav--single-line .cal-toolbar-date-btn {
    font-size: 0.875rem;   /* 14px — Label jetzt kompakt (KW29 13.07-19.07), lesbarer als 12px */
    font-weight: 500;
  }

  .ds-time-quick-bar {
    /* Desktop Sticky-Bar bleibt sichtbar auf Mobile (jetzt als Basis für Sheet-Inhalt) */
    display: none; /* auf Mobile durch Trigger-Pill + Sheet ersetzt */
  }

  /* ── Mobile Trigger-Pill ─────────────────────────────── */
  .ds-time-quick-bar-trigger {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    position: sticky;
    top: 0;
    z-index: 10;
    width: 100%;
    background: var(--bg-primary);
    border: none;
    border-bottom: 1px solid var(--border);
    padding: .625rem .75rem;
    font-size: .875rem;
    color: var(--text-primary);
    font-weight: 500;
    cursor: pointer;
    transition: background var(--transition);
    text-align: left;
  }
  .ds-time-quick-bar-trigger:hover { background: var(--bg-secondary); }
  .ds-time-quick-bar-trigger--active { color: var(--coral); }

  .ds-time-quick-bar-trigger-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--border);
    flex-shrink: 0;
    transition: background var(--transition);
  }
  .ds-time-quick-bar-trigger-dot--active {
    background: var(--coral);
    animation: tt-pulse 1.2s ease-in-out infinite;
  }

  .ds-time-quick-bar-trigger-label {
    flex: 1;
    font-variant-numeric: tabular-nums;
  }

  /* ── Bottom-Sheet ────────────────────────────────────── */
  .ds-time-quick-bar-sheet {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 450;
    pointer-events: none;
  }
  .ds-time-quick-bar-sheet.is-open { pointer-events: all; }

  .ds-time-quick-bar-sheet-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, .45);
    opacity: 0;
    transition: opacity 200ms ease;
  }
  .ds-time-quick-bar-sheet.is-open .ds-time-quick-bar-sheet-backdrop {
    opacity: 1;
  }

  .ds-time-quick-bar-sheet-panel {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--bg-primary);
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    border-top: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    transform: translateY(100%);
    transition: transform 220ms ease;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    display: flex;
    flex-direction: column;
    max-height: 80vh;
  }
  .ds-time-quick-bar-sheet.is-open .ds-time-quick-bar-sheet-panel {
    transform: translateY(0);
    animation: tt-sheet-slide-up 220ms ease both;
  }

  .ds-time-quick-bar-sheet-handle {
    width: 40px;
    height: 4px;
    border-radius: 999px;
    background: var(--border);
    margin: .625rem auto .25rem;
    flex-shrink: 0;
  }

  .ds-time-quick-bar-sheet-header {
    display: flex;
    align-items: center;
    padding: .375rem .75rem .625rem;
    flex-shrink: 0;
  }
  .ds-time-quick-bar-sheet-title {
    flex: 1;
    font-weight: 600;
    font-size: .9375rem;
    color: var(--text-primary);
  }
  .ds-time-quick-bar-sheet-close {
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
  }

  .ds-time-quick-bar-sheet-body {
    padding: .25rem .75rem .75rem;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    display: flex;
    flex-direction: column;
    flex: 1;         /* Fix: Body muss im Flex-Panel (Header fix) wachsen duerfen ... */
    min-height: 0;   /* ... UND min-height:0 tragen, sonst scrollt ein Flex-Child nie */
    gap: .5rem;
  }
  /* Im Sheet: Input-wrap nimmt volle Breite, Timer darunter */
  .ds-time-quick-bar-sheet-body .ds-time-quick-input-wrap { flex: 1; }
  .ds-time-quick-bar-sheet-body .ds-time-quick-bar {
    display: flex;
    flex-direction: column;
    position: static;
    border: none;
    padding: 0;
    background: transparent;
    gap: .5rem;
  }
  /* Input in Sheet: Mobile min-height für Touch */
  .ds-time-quick-bar-sheet-body .ds-time-quick-input {
    min-height: 44px;
    font-size: 1rem;
  }
  /* Timer im Sheet: Buttons min-height 44px — DEPRECATED: timer removed 2026-05-20 */
  .ds-time-quick-bar-sheet-body .ds-time-quick-stop-btn,
  .ds-time-quick-bar-sheet-body .ds-time-quick-start-btn {
    min-height: 44px;
  }
  /* Pickers im Sheet: volle Breite, Touch-Target */
  .ds-time-quick-bar-sheet-body .ds-time-quick-pickers {
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    flex: 0 0 auto;
  }
  .ds-time-quick-bar-sheet-body .ds-time-quick-pickers-picker,
  .ds-time-quick-bar-sheet-body .ds-time-quick-proj-combo {
    width: 100%;
    max-width: 100%;
    min-height: 44px;
    flex: 0 0 auto;   /* Fix: war 1 1 100% -> wuchs in der Spalte vertikal (~300px riesig) */
  }
  /* 🔒 Profil-Select braucht einen mind. gleich-spezifischen Selektor: die Basisregel
     `.ds-time-quick-pickers .select.ds-time-quick-pickers-select` (3 Klassen, s.o. Z.297)
     setzt `flex:0 1 10rem` — im Sheet ist die Hauptachse SPALTE (vertikal), die Flex-Basis
     wirkt dort also auf die HOEHE (nicht Breite wie im Desktop-Zeilen-Layout) und blaeht
     das native <select> auf ~10rem/160px auf. Spezifitaet schlaegt Quellreihenfolge — ein
     2-Klassen-Override (wie zuvor) reicht hier NICHT, es braucht mind. 3 Klassen. */
  .ds-time-quick-bar-sheet-body .ds-time-quick-pickers-select,
  .ds-time-quick-bar-sheet-body .ds-time-quick-pickers .select.ds-time-quick-pickers-select {
    width: 100%;
    max-width: 100%;
    height: 44px;
    min-height: 44px;
    flex: 0 0 auto;
    box-sizing: border-box;
  }

  /* C2: Resize-Handles größer auf Touch (6px → 16px) */
  .tt-block-resize-top,
  .tt-block-resize-bot {
    height: 16px;
  }

  /* C2: Pull-to-Refresh während Drag blockieren */
  .tt-day-grid--dragging {
    touch-action: none;
  }
}

@keyframes tt-sheet-slide-up {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

@media (max-width: 600px) {
  .tt-suggestions-row { overflow-x: auto; flex-wrap: nowrap; }
}

/* Dark-Mode: Light-BG via Variablen-Mapping bereits dark-angepasst — keine extra opacity nötig.
 * Inner-Text-Farben (--text-primary, --text-secondary, --text-tertiary) automatisch korrekt. */

/* ── Time-Tracking: Auswertung (Stats) ─────────────────────────────────── */

/* Sub-Tab-Leiste im Auswertung-Tab — DEPRECATED (Req 6, 2026-05-20): durch .tab-filter ersetzt. Klasse bleibt für Rückwärts-Compat. */
.tt-stats-subtabs {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .625rem .75rem .375rem;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}

/* Summary-Kacheln oben */
.tt-stats-summary {
  display: flex;
  gap: .625rem;
  padding: .75rem .75rem .375rem;
  flex-wrap: wrap;
}
.tt-stats-kpi {
  flex: 1 1 140px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .625rem .875rem;
  display: flex;
  flex-direction: column;
  gap: .15rem;
}
.tt-stats-kpi-label {
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-tertiary);
  font-weight: 500;
}
.tt-stats-kpi-value {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.tt-stats-kpi-hint {
  font-size: .75rem;
  color: var(--text-tertiary);
}

/* Kunden-Ebene: Card-Grid */
.tt-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: .75rem;
  padding: .75rem .75rem;
}
.tt-stats-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .875rem 1rem;
  background: var(--bg-primary);
  display: flex;
  flex-direction: column;
  gap: .375rem;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.tt-stats-card:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-sm);
}
.tt-stats-card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: .5rem;
}
.tt-stats-card-title {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--text-primary);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}
.tt-stats-card-total {
  font-weight: 700;
  font-size: .9375rem;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex-shrink: 0;
}
.tt-stats-card-meta {
  font-size: .78rem;
  color: var(--text-tertiary);
  display: flex;
  gap: .75rem;
  flex-wrap: wrap;
}
.tt-stats-card-expand {
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
  color: var(--text-tertiary);
  font-size: .78rem;
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  transition: color var(--transition);
  margin-top: .125rem;
}
.tt-stats-card-expand:hover { color: var(--accent); }

/* Sub-Liste pro Projekt innerhalb einer Kunden-Card */
.tt-stats-card-sub {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  margin-top: .25rem;
  padding-top: .375rem;
  border-top: 1px solid var(--border);
}
.tt-stats-card-sub-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: .8125rem;
  color: var(--text-secondary);
  gap: .5rem;
}
.tt-stats-card-sub-row-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tt-stats-card-sub-row-val {
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  color: var(--text-primary);
  flex-shrink: 0;
}

/* Horizontale Bar-Visualisierung (Meine Ebene) */
.tt-stats-bar-wrap {
  margin-top: .25rem;
}
.tt-stats-bar {
  display: flex;
  height: 8px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  gap: 1px;
  background: var(--bg-tertiary);
}
.tt-stats-bar-segment {
  height: 100%;
  background: var(--tt-stats-color, var(--accent));
  transition: flex var(--transition-slow);
  min-width: 2px;
}
.tt-stats-bar-legend {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem .625rem;
  margin-top: .375rem;
}
.tt-stats-bar-legend-item {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .72rem;
  color: var(--text-secondary);
}
.tt-stats-bar-legend-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--tt-stats-color, var(--accent));
}

/* Meine Ebene: Tages-/Perioden-Liste */
.tt-stats-self-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .75rem .75rem;
}
.tt-stats-self-row {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .75rem .875rem;
  background: var(--bg-primary);
  display: flex;
  flex-direction: column;
  gap: .375rem;
}
.tt-stats-self-row-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
}
.tt-stats-self-row-date {
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-primary);
}
.tt-stats-self-row-total {
  font-weight: 700;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  font-size: .875rem;
  flex-shrink: 0;
}
.tt-stats-self-row-breaks {
  font-size: .75rem;
  color: var(--text-tertiary);
}
.tt-stats-self-row-dist {
  font-size: .78rem;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Empty-State Auswertung */
.tt-stats-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 3rem 1.5rem;
  text-align: center;
  color: var(--text-secondary);
  gap: .5rem;
  font-size: .9rem;
}
.tt-stats-empty p { margin: 0; }

/* ── Time-Tracking: Auswertung — Zeitraum-Werkzeugleiste + Verlaufsdiagramm ──
   Ticket 3.93, Ebenen-Umschaltung links (.tab-filter). Ticket 3.381.1:
   die frueheren 7/30/90-Tage-Presets rechts (.contact-status-segment)
   sind entfallen – an ihrer Stelle sitzt seither der freie Zeitraum
   (.tt-stats-range-row, s.u.) als zweites Flex-Kind. justify-content:
   space-between haelt beide auseinander, flex-wrap laesst die Zeile auf
   schmalen Screens umbrechen (Mobile – s. .tt-stats-range-row). */
.tt-stats-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .5rem;
  padding: .625rem .75rem .375rem;
  border-bottom: 1px solid var(--border);
}
.tt-stats-history {
  padding: .75rem .75rem 0;
}
.tt-stats-history-title {
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-primary);
  margin-bottom: .5rem;
}
.tt-stats-history-chart-wrap {
  overflow-x: auto;
  margin-top: .5rem;
  margin-bottom: .625rem;
}
.tt-stats-history-svg {
  display: block;
  max-width: 100%;
  height: auto;
}
.tt-stats-history-table-wrap.table-wrap {
  margin: 0 0 .75rem;
}
.tt-stats-history-table-wrap .table {
  font-size: .78rem;
}
.tt-stats-history-table-wrap .table th,
.tt-stats-history-table-wrap .table td {
  padding: .4rem .625rem;
}

/* Freier Zeitraum in der Auswertung (Ticket 3.381) – reused .tt-date-nav
   (Pill-Look) + .tt-date-nav .tt-filter-date (Z. 2895) fuer die Von/Bis-
   Eingabe, dieselbe Bedienlogik wie "Eigener Zeitraum" (_view==='custom').
   Seit 3.381.1 Flex-Kind INNERHALB von .tt-stats-toolbar (an Stelle der
   frueheren Tages-Presets) statt eigener Zeile darunter – kein eigener
   Aussenabstand mehr noetig (die Basisregel .tt-date-nav bringt "margin:
   0 0 .5rem" mit, hier auf 0 zurueckgesetzt: die Umgebung ist bereits
   .tt-stats-toolbar mit eigenem padding+gap). Kein ".is-active"-Zustand
   mehr – es gibt keinen zweiten Modus, von dem sich die Zeile abheben
   muesste. */
.tt-stats-range-row {
  margin: 0;
}
.tt-stats-range-sep {
  color: var(--text-tertiary);
  font-size: .875rem;
  padding: 0 .125rem;
}

/* ── Time-Tracking: Export-Panel ────────────────────────────────────────── */

.tt-export-panel-body {
  padding: .75rem;
  display: flex;
  flex-direction: column;
  gap: 1.125rem;
}

.tt-export-section {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.tt-export-section-label {
  font-weight: 600;
  font-size: .8125rem;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
}

/* Schnell-Range-Chips */
.tt-export-range-chips {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
}
.tt-export-range-chip {
  display: inline-flex;
  align-items: center;
  padding: .3rem .7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: .8125rem;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition), color var(--transition);
  min-height: 32px;
}
.tt-export-range-chip:hover {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
}
.tt-export-range-chip.is-active {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 500;
}

/* Custom-Datumsfelder */
.tt-export-date-range {
  display: flex;
  align-items: center;
  gap: .375rem;
  margin-top: .25rem;
}
.tt-export-date-range .input { flex: 1; }

/* Format-Radio-Gruppe */
.tt-export-format-radios {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
}
.tt-export-format-radio {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .375rem .75rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  font-size: .875rem;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  transition: border-color var(--transition), color var(--transition), background var(--transition);
  min-height: 38px;
  user-select: none;
}
.tt-export-format-radio input[type="radio"] {
  accent-color: var(--accent);
}
.tt-export-format-radio:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 500;
}

/* Pause-Toggle-Zeile */
.tt-export-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .25rem 0;
}
.tt-export-toggle-label {
  font-size: .875rem;
  color: var(--text-secondary);
}

/* Trennlinie */
.tt-export-sep {
  height: 1px;
  background: var(--border);
  margin: -.25rem 0;
}

/* Footer: Download-Button */
.tt-export-footer {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding-top: .25rem;
}

/* ── Time-Tracking: Zeitnachweis-Anhang-Panel ── */

/* Lock-Banner im Zeit-Eintrag-Editor */
.tt-lock-banner {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
  padding: .625rem .875rem;
  background: var(--amber-light);
  border: 1px solid var(--amber);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
  color: var(--amber);
  margin-bottom: .75rem;
}
.tt-lock-banner--invoiced {
  background: var(--teal-light);
  border-color: var(--teal);
  color: var(--teal);
}
.tt-lock-banner--locked {
  background: var(--bg-secondary);
  border-color: var(--border);
  color: var(--text-secondary);
}
.tt-lock-banner-icon {
  flex-shrink: 0;
  margin-top: .0625rem;
}
.tt-lock-banner-text {
  flex: 1;
  min-width: 0;
  line-height: 1.4;
}
/* Lock-Icon in Timeline-Blöcken */
.tt-block-lock-icon {
  flex-shrink: 0;
  color: var(--text-tertiary);
  opacity: .7;
}
.tt-block.is-invoiced .tt-block-lock-icon,
.tt-block.is-attached .tt-block-lock-icon {
  color: var(--amber);
}
.tt-block.is-locked .tt-block-lock-icon {
  color: var(--teal);
}

/* ── Time-Tracking: Externe Zeiteinträge (Partner-Import, Spec 20260708) ── */
/* Liste (Desktop-Tabellenzelle + Mobile native-row): Person/Partner-Sekundärzeile */
.tt-external-info {
  display: flex;
  align-items: center;
  gap: .25rem;
  margin-top: .125rem;
  font-size: .75rem;
  color: var(--text-tertiary);
  flex-wrap: wrap;
}
.tt-external-info--mobile {
  margin-top: .0625rem;
}
.tt-external-badge {
  font-size: .65rem;
  padding: .0625rem .375rem;
}
.tt-external-person {
  color: var(--text-secondary);
}
.tt-external-partner {
  color: var(--text-tertiary);
}

/* Editor-Panel: read-only Info-Banner für externe Einträge */
.tt-external-banner {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
  padding: .625rem .875rem;
  background: var(--amber-light);
  border: 1px solid var(--amber);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
  color: var(--amber);
  margin-bottom: .75rem;
}
.tt-external-banner-icon {
  flex-shrink: 0;
  margin-top: .0625rem;
}
.tt-external-banner-text {
  flex: 1;
  min-width: 0;
  line-height: 1.4;
}

/* Eintrags-Liste im Anhang-Panel */
.tt-attach-entries-list {
  display: flex;
  flex-direction: column;
  gap: .375rem;
  max-height: 50vh;
  overflow-y: auto;
  margin-bottom: .5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .25rem;
}
.tt-attach-entry-row {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
  padding: .5rem .625rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition);
}
.tt-attach-entry-row:hover {
  background: var(--bg-secondary);
}
.tt-attach-entry-row.is-selected {
  background: var(--accent-light);
}
.tt-attach-entry-check {
  flex-shrink: 0;
  margin-top: .125rem;
  accent-color: var(--accent);
  width: 15px;
  height: 15px;
  cursor: pointer;
}
.tt-attach-entry-info {
  flex: 1;
  min-width: 0;
}
.tt-attach-entry-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .3rem .5rem;
  font-size: .8125rem;
}
.tt-attach-entry-date {
  font-weight: 600;
  color: var(--text-primary);
}
.tt-attach-entry-time {
  color: var(--text-secondary);
  font-size: .75rem;
}
.tt-attach-entry-name {
  color: var(--accent);
  font-size: .75rem;
  max-width: 10rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tt-attach-entry-dur {
  margin-left: auto;
  font-weight: 500;
  color: var(--text-primary);
  font-size: .8125rem;
  font-variant-numeric: tabular-nums;
}
.tt-attach-entry-desc {
  font-size: .75rem;
  color: var(--text-tertiary);
  margin-top: .125rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Gesamt-Zeile im Anhang-Panel */
.tt-attach-total {
  font-size: .8125rem;
  color: var(--text-secondary);
  padding: .375rem .25rem;
  text-align: right;
  border-top: 1px solid var(--border);
  margin-top: .125rem;
}

/* Mobile Anpassungen */
@media (max-width: 600px) {
  .tt-stats-grid {
    grid-template-columns: 1fr;
  }
  .tt-stats-summary {
    gap: .5rem;
  }
  .tt-stats-kpi-value {
    font-size: 1.25rem;
  }
  .tt-export-format-radios {
    gap: .375rem;
  }
  .tt-export-range-chips {
    gap: .3rem;
  }
}

/* ── Time-Tracking: Filter-Bar — Tab-Filter-Pill-Pattern (2026-05-20 Final) ── */
/* Look & Feel: identisch zu .tab-filter (driver-log).
 * Container: bg-tertiary (#EEEDE8), radius-md, kein Border, kein Wrap, 1-zeilig.
 * Controls: transparent default → bg-primary + shadow-sm wenn Filter aktiv (.is-active),
 *           exakt wie .tab-filter-btn.active. */

.tt-filter-bar {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.25rem;
  background: var(--bg-tertiary);
  border-radius: var(--radius-md);
  margin: 0 0 1rem;
  width: 100%;
  max-width: 100%;
  flex-wrap: wrap;
  row-gap: 0.25rem;
}

/* Req 5 — „Filter:"-Label als erstes Kind des Filter-Bars (2026-05-20) */
.tt-filter-bar-label {
  font-size: .75rem;
  font-weight: 500;
  color: var(--text-tertiary);
  white-space: nowrap;
  padding: 0 .25rem 0 .125rem;
  align-self: center;
  flex-shrink: 0;
}
@media (max-width: 600px) {
  .tt-filter-bar-label { display: none; }
}

/* Generischer Reset für alle Filter-Controls — überschreibt .select / .input / picker-internals.
 * Default-State = aktiver Pill-Look (bg-primary + shadow-sm) für klaren Kontrast zum
 * hellbeigen Container-Hintergrund. Identisch mit .tab-filter-btn.active. */
.tt-filter-bar .tt-filter-control,
.tt-filter-bar .tt-filter-control.select,
.tt-filter-bar .tt-filter-control.input {
  background-color: var(--bg-primary);
  background-image: none;
  border: none;
  outline: none;
  box-shadow: var(--shadow-sm);
  border-radius: var(--radius-sm);
  padding: 0 0.875rem;
  width: auto;
  height: 32px;
  min-height: 32px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-primary);
  cursor: pointer;
  flex: 0 0 auto;
  box-sizing: border-box;
  line-height: 1;
  font-family: inherit;
  transition: background 120ms ease, color 120ms ease, box-shadow 120ms ease;
}
.tt-filter-bar .tt-filter-control:hover {
  color: var(--text-primary);
}
/* Aktiv-State (Filter gesetzt) — etwas stärkere Schatten-Akzentuierung, optional */
.tt-filter-bar .tt-filter-control.is-active {
  background: var(--bg-primary);
  color: var(--text-primary);
  box-shadow: var(--shadow-sm);
}
/* Focus (Keyboard) */
.tt-filter-bar .tt-filter-control:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Native-Select: eigener Chevron-Pfeil (transparent BG override) */
.tt-filter-bar .tt-filter-control.select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.5rem center;
  padding-right: 1.75rem;
  min-width: 9rem;
}

/* Date-Input: native Picker-Indikator dezent ausblenden + gleiche Höhe */
.tt-filter-bar .tt-filter-control.tt-filter-date {
  min-width: 8.5rem;
  padding: 0 0.875rem;
}
.tt-filter-bar .tt-filter-control.tt-filter-date::-webkit-calendar-picker-indicator {
  opacity: 0.4;
  cursor: pointer;
}

/* ds-company-picker: Custom-Element-Wrapper trägt den Pill-Look,
 * interne Inputs/Selected-Box transparent (erben den weißen Pill-Background) */
.tt-filter-bar .tt-filter-picker {
  display: inline-flex;
  align-items: center;
  flex: 0 1 14rem;
  min-width: 11rem;
  padding: 0;             /* Padding sitzt am internen .ds-cp-input/.ds-cp-selected */
  height: 32px;
  background: var(--bg-primary);
  box-shadow: var(--shadow-sm);
  border-radius: var(--radius-sm);
}
.tt-filter-bar .tt-filter-picker .ds-cp-wrap { width: 100%; }
.tt-filter-bar .tt-filter-picker .ds-cp-input {
  border: none;
  background: transparent;
  box-shadow: none;
  outline: none;
  height: 32px;
  padding: 0 0.875rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
  width: 100%;
  border-radius: var(--radius-sm);
}
.tt-filter-bar .tt-filter-picker .ds-cp-input { color: var(--text-primary); }
.tt-filter-bar .tt-filter-picker .ds-cp-input::placeholder {
  color: var(--text-secondary);
  opacity: 1;
}
.tt-filter-bar .tt-filter-picker .ds-cp-selected {
  border: none;
  background: transparent;
  height: 32px;
  min-height: 32px;
  align-items: center;                  /* Override global align-items:baseline */
  padding: 0 1.75rem 0 0.875rem;        /* Platz für Clear-Button rechts */
  border-radius: var(--radius-sm);
  line-height: 1;
}
.tt-filter-bar .tt-filter-picker .ds-cp-selected-name {
  line-height: 1;
}
/* Clear-Button vertikal zentriert auf 32px-Höhe */
.tt-filter-bar .tt-filter-picker .ds-cp-clear {
  top: 50%;
  transform: translateY(-50%);
  right: 0.375rem;
}
.tt-filter-bar .tt-filter-picker .ds-cp-selected-name {
  font-size: 0.8125rem;
  font-weight: 500;
}
.tt-filter-bar .tt-filter-picker .ds-cp-selected-email,
.tt-filter-bar .tt-filter-picker .ds-cp-detail-link {
  display: none;          /* Sub-Info im Filter-Kontext nicht nötig */
}
/* Aktiv-State: Picker-Wrapper bekommt Pill-Look wenn Firma gewählt */
.tt-filter-bar .tt-filter-picker.is-active {
  background: var(--bg-primary);
  box-shadow: var(--shadow-sm);
}
.tt-filter-bar .tt-filter-picker.is-active .ds-cp-input,
.tt-filter-bar .tt-filter-picker.is-active .ds-cp-selected,
.tt-filter-bar .tt-filter-picker.is-active .ds-cp-selected-name {
  color: var(--text-primary);
}

/* Vertikaler Separator zwischen Slots (dezent, optional) */
.tt-filter-sep {
  display: inline-block;
  width: 1px;
  height: 18px;
  background: var(--border);
  flex-shrink: 0;
  align-self: center;
  opacity: 0.6;
}

@media (max-width: 600px) {
  .tt-filter-sep { display: none; }
}

/* A4: Hover-Affordance für Listen-Zeilen ------------------------------------ */
.tt-entry-row:hover {
  background: var(--bg-secondary);
}

/* A5: Bulk-Aktion-Toolbar --------------------------------------------------- */
.tt-bulk-toolbar {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  padding: .5rem .75rem;
  background: var(--accent-light);
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
  margin-bottom: .75rem;
}

.tt-bulk-toolbar-count {
  font-size: .875rem;
  font-weight: 500;
  color: var(--accent);
  flex: 1;
}

/* ── Time-Tracking: Editor-Grids (Firma+Projekt / Datum+Start+End, 2026-05-20) ── */
.tt-form-grid-2,
.tt-form-grid-3 {
  display: grid;
  gap: .625rem;
}
.tt-form-grid-2 { grid-template-columns: 1fr 1fr; }
.tt-form-grid-3 { grid-template-columns: 1fr 1fr 1fr; }

@media (max-width: 900px) {
  .tt-form-grid-2,
  .tt-form-grid-3 { grid-template-columns: 1fr; }
}

/* ── Time-Tracking: Import-Panel (2026-06-05) ── */

/* Verstecktes File-Input + Label-Button als Trigger (SR-only pattern) */
.tt-import-file-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
  opacity: 0;
}

.tt-import-file-label {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  cursor: pointer;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tt-import-file-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}

/* Loading skeleton row */
.tt-import-loading {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .25rem 0;
}

/* Summary pills */
.tt-import-summary {
  display: flex;
  flex-wrap: wrap;
  gap: .375rem;
}

.tt-import-summary-chip {
  display: inline-flex;
  align-items: center;
  padding: .25rem .625rem;
  border-radius: var(--radius-sm);
  font-size: .8125rem;
  font-weight: 500;
  border: 1px solid transparent;
}

.tt-import-summary-chip--teal {
  background: var(--teal-light);
  color: var(--teal);
  border-color: var(--teal-light);
}

.tt-import-summary-chip--amber {
  background: var(--amber-light);
  color: var(--amber);
  border-color: var(--amber-light);
}

.tt-import-summary-chip--coral {
  background: var(--coral-light);
  color: var(--coral);
  border-color: var(--coral-light);
}

/* Mapping-Liste (Firmen + Projekte) */
.tt-import-mapping-list {
  display: flex;
  flex-direction: column;
  gap: .625rem;
}

.tt-import-mapping-row {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  flex-wrap: wrap;
}

.tt-import-mapping-csv-name {
  font-size: .875rem;
  font-weight: 500;
  color: var(--text-primary);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .25rem .5rem;
  white-space: nowrap;
  flex-shrink: 0;
  align-self: center;
  max-width: 10rem;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Feste Ziel-Label-Pille für GENERIC_TARGET_KEYS (Spalten-Zuordnung-Sektion) —
   im Gegensatz zu .tt-import-mapping-csv-name (variable CSV-Fremdwerte, auto-width
   + Ellipsis) sind das unsere eigenen, festen Feld-Labels. Feste width statt
   max-width richtet Pfeil + Dropdown aller Zeilen auf einer X-Position aus.
   Breite an "Dauer (falls kein Ende)" (längstes Label) kalibriert. */
.tt-import-target-label {
  font-size: .875rem;
  font-weight: 500;
  color: var(--text-primary);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .25rem .5rem;
  white-space: nowrap;
  flex-shrink: 0;
  align-self: center;
  width: 12rem;
  text-align: left;
}

.tt-import-mapping-arrow {
  font-size: .875rem;
  color: var(--text-tertiary);
  align-self: center;
  flex-shrink: 0;
  padding: .25rem 0;
}

.tt-import-mapping-picker {
  flex: 1;
  min-width: 12rem;
  display: flex;
  flex-direction: column;
  gap: .25rem;
}

.tt-import-mapping-unmatched {
  font-size: .75rem;
  color: var(--amber);
  opacity: .85;
}

/* Werte-Vorschau: Beispielwert unter dem Mapping-Select (Domenico-Feedback 2026-07-09) */
.tt-import-mapping-sample {
  font-size: .75rem;
  color: var(--text-tertiary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Mini-Vorschautabelle der Rohdatei — kompakte Variante von .table */
.tt-import-sample-table {
  font-size: .8125rem;
}

.tt-import-sample-table th,
.tt-import-sample-table td {
  padding: .375rem .625rem;
  max-width: 10rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tt-import-sample-table tbody tr {
  cursor: default;
}

.tt-import-sample-table tbody tr:hover {
  background: transparent;
}

/* Fehler-Details */
.tt-import-errors-details {
  border: 1px solid var(--coral-light);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.tt-import-errors-summary {
  padding: .5rem .75rem;
  font-size: .875rem;
  font-weight: 500;
  color: var(--coral);
  background: var(--coral-light);
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.tt-import-errors-summary::-webkit-details-marker { display: none; }

.tt-import-errors-list {
  list-style: none;
  padding: .375rem .75rem;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .25rem;
  max-height: 12rem;
  overflow-y: auto;
}

.tt-import-error-item {
  font-size: .8125rem;
  color: var(--text-secondary);
  line-height: 1.5;
}

.tt-import-error-row {
  font-weight: 600;
  color: var(--coral);
  margin-right: .25rem;
}

/* Partner-Import (Spec 20260708): Mapping-Vorlage speichern — Name-Input + Button nebeneinander */
.tt-import-template-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}

.tt-import-template-row .input {
  flex: 1;
  min-width: 12rem;
  width: auto;
}

/* Mobile: Mapping-Zeilen stapeln */
@media (max-width: 600px) {
  .tt-import-mapping-row {
    flex-direction: column;
    align-items: stretch;
    gap: .375rem;
  }

  .tt-import-mapping-arrow {
    display: none;
  }

  .tt-import-mapping-csv-name {
    max-width: 100%;
  }

  .tt-import-target-label {
    width: 100%;
  }

  .tt-import-mapping-picker {
    min-width: 0;
  }

  .tt-import-file-label {
    width: 100%;
    justify-content: center;
  }
}

/* ── tt-list-table: Fixed Spaltenbreiten für Woche/Monat/Custom Listen ─────── */
/* table-layout:fixed + width:100% erzwingt identische Spaltenbreiten über alle
   Tages-Gruppen hinweg. Beschreibungs-Spalte nimmt den verbleibenden Rest. */
.tt-list-table {
  table-layout: fixed;
  width: 100%;
}

/* Checkbox */
.tt-list-table th:nth-child(1),
.tt-list-table td:nth-child(1) {
  width: 36px;
}

/* Zeit (Von–Bis) */
.tt-list-table th:nth-child(2),
.tt-list-table td:nth-child(2) {
  width: 110px;
}

/* Kontakt / Firma */
.tt-list-table th:nth-child(3),
.tt-list-table td:nth-child(3) {
  width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Projekt */
.tt-list-table th:nth-child(4),
.tt-list-table td:nth-child(4) {
  width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Beschreibung — nimmt den Rest (kein width → auto) */
.tt-list-table th:nth-child(5),
.tt-list-table td:nth-child(5) {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Dauer */
.tt-list-table th:nth-child(6),
.tt-list-table td:nth-child(6) {
  width: 80px;
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Typ (Extern/Intern) */
.tt-list-table th:nth-child(7),
.tt-list-table td:nth-child(7) {
  width: 76px;
}

/* Status */
.tt-list-table th:nth-child(8),
.tt-list-table td:nth-child(8) {
  width: 120px;
}

/* ── Zeitnachweis-Sektion im Rechnungs-Draft-Editor (2026-06-06) ──────────────────────────── */
/*
 * Neue Klassen-Familie: .tt-ts-* (Timesheet-Section im Invoicing-Editor).
 * Platzierung: nach _renderItemsSection, vor _renderAttachmentsSection.
 * Nur im Draft-Modus + wenn Einträge vorhanden.
 * Light/Dark: ausschließlich via CSS-Variablen.
 */

.tt-timesheet-section {
  margin-top: .75rem;
}

/* Header-Zeile: Überschrift + Gesamtstunden + ggf. Hinweis */
.tt-ts-header {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: .5rem;
  flex-wrap: wrap;
}

.tt-ts-title {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--text-primary);
  flex: 1;
  display: flex;
  align-items: center;
  gap: .375rem;
}

.tt-ts-title-icon {
  color: var(--accent);
  flex-shrink: 0;
}

.tt-ts-total {
  font-size: .8125rem;
  font-weight: 700;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .2rem .625rem;
}

/* Tabellen-ähnliche Eintragsliste */
.tt-ts-list {
  display: flex;
  flex-direction: column;
  gap: .375rem;
}

/* Einzelner Eintrag */
.tt-ts-entry {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .625rem .75rem;
  transition: border-color var(--transition);
}

.tt-ts-entry:focus-within {
  border-color: var(--accent);
}

.tt-ts-entry.is-readonly {
  opacity: .75;
}

/* Obere Zeile: Datum + Firma/Projekt (read-only) + Dauer */
.tt-ts-entry-top {
  display: flex;
  align-items: center;
  gap: .5rem .75rem;
  flex-wrap: wrap;
  margin-bottom: .5rem;
}

.tt-ts-entry-date {
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-primary);
  white-space: nowrap;
}

.tt-ts-entry-context {
  font-size: .8125rem;
  color: var(--accent);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tt-ts-entry-dur {
  font-size: .875rem;
  font-weight: 500;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  margin-left: auto;
}

/* Untere Zeile: editierbare Felder */
.tt-ts-entry-fields {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  gap: .375rem .5rem;
  align-items: center;
}

.tt-ts-time-label {
  font-size: .75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

.tt-ts-time-input {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-primary);
  font-size: .8125rem;
  padding: .25rem .5rem;
  height: 32px;
  min-width: 7rem;
  transition: border-color var(--transition), box-shadow var(--transition);
}

.tt-ts-time-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(77, 133, 224, .15);
}

.tt-ts-desc-input {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-primary);
  font-size: .8125rem;
  padding: .25rem .5rem;
  height: 32px;
  min-width: 0;
  width: 100%;
  transition: border-color var(--transition), box-shadow var(--transition);
}

.tt-ts-desc-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(77, 133, 224, .15);
}

.tt-ts-rate-input {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-primary);
  font-size: .8125rem;
  padding: .25rem .5rem;
  height: 32px;
  width: 6rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
  transition: border-color var(--transition), box-shadow var(--transition);
}

.tt-ts-rate-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(77, 133, 224, .15);
}

/* Detach-Button (Mülleimer / X) */
.tt-ts-detach-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  min-width: 44px; /* Touch-Target via padding extension */
  min-height: 44px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-tertiary);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: color var(--transition), background var(--transition);
  flex-shrink: 0;
}

.tt-ts-detach-btn:hover {
  color: var(--coral);
  background: var(--coral-light);
}

.tt-ts-detach-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Readonly-Hinweis für attachment-mode Einträge */
.tt-ts-readonly-badge {
  font-size: .7rem;
  color: var(--text-tertiary);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: .125rem .5rem;
  margin-left: auto;
  white-space: nowrap;
}

/* Gesamtzeile unten */
.tt-ts-footer {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: .5rem;
  padding: .375rem .25rem 0;
  border-top: 1px solid var(--border);
  margin-top: .375rem;
  font-size: .8125rem;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

.tt-ts-footer-label {
  color: var(--text-tertiary);
}

.tt-ts-footer-value {
  font-weight: 600;
  color: var(--text-primary);
}

/* Mobile */
@media (max-width: 600px) {
  .tt-ts-entry-fields {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto auto;
  }

  .tt-ts-time-input {
    width: 100%;
    min-width: 0;
    min-height: 44px;
    height: 44px;
  }

  .tt-ts-desc-input {
    grid-column: 1 / -1;
    min-height: 44px;
    height: 44px;
  }

  .tt-ts-detach-btn {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
  }

  .tt-ts-rate-input {
    width: 100%;
    min-height: 44px;
    height: 44px;
  }
}

/* ── Zeitnachweis-Tabellen-Layout im Invoicing-Editor (2026-06-06) ──────────────────────── */
/*
 * .tt-ts-table: kompakte Inputs in Tabellen-Zellen.
 * Horizontaler Scroll via .table-wrap — kein Page-Scroll.
 * Light/Dark: ausschließlich via CSS-Variablen.
 */

/* Kompakte Inputs in der Tabelle */
.tt-ts-table .input,
.tt-ts-table input[type="time"],
.tt-ts-table input[type="number"],
.tt-ts-table input[type="text"] {
  height: 32px;
  padding-top: .25rem;
  padding-bottom: .25rem;
  font-size: .875rem;
}

/* Start/Ende-Spalte: schmal halten */
.tt-ts-input-time {
  min-width: 7rem;
  width: 7rem;
}

/* Stundensatz-Spalte: schmal */
.tt-ts-input-rate {
  min-width: 5.5rem;
  width: 5.5rem;
  text-align: right;
}

/* Beschreibungs-Spalte: breit */
.tt-ts-input-desc {
  min-width: 10rem;
  width: 100%;
}

/* Dauer: rechtsbündig, tabular-nums */
.tt-ts-col-dur,
.tt-ts-cell-dur {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Aktion-Spalte: schmal, zentriert */
.tt-ts-col-action,
.tt-ts-cell-action {
  width: 2.5rem;
  text-align: center;
  white-space: nowrap;
}

/* Datum-Zelle: nowrap */
.tt-ts-cell-date {
  white-space: nowrap;
  font-weight: 600;
}

/* Firma/Projekt: ellipsis bei langen Namen */
.tt-ts-cell-context {
  max-width: 14rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Dezente Markierung für externe (Partner-Import) Zeiteinträge — Zeitnachweis-Sektion (Rechnung, Draft-Editor) */
.tt-ts-external-badge {
  display: inline-block;
  font-size: .65rem;
  font-weight: 500;
  padding: .0625rem .375rem;
  border-radius: 999px;
  background: var(--bg-tertiary);
  color: var(--text-tertiary);
  border: 1px solid var(--border);
  margin-left: .375rem;
  vertical-align: middle;
  white-space: nowrap;
}

/* Readonly-Zeile: gedimmt */
.tt-ts-row-readonly {
  opacity: .75;
}

/* ── Tageweise alternierende Zeilenfarbe (ZIEL 1, 2026-06-06) ───────────── */
/* Standardzeile: explizit weiß/heller BG damit --alt-Kontrast zuverlässig sichtbar ist */
.tt-ts-table tbody tr.tt-ts-row {
  background: var(--bg-primary);
}

/* Ungerade Tages-Index (1, 3, 5, …) → grauer Hintergrund */
.tt-ts-table tbody tr.tt-ts-row--alt {
  background: var(--bg-secondary);
}

/* Inputs auf grauen Zeilen: BG auf --bg-primary setzen, damit sie nicht verschwimmen */
.tt-ts-table tbody tr.tt-ts-row--alt .input {
  background: var(--bg-primary);
}

/* Kombinierbar mit --alt: Readonly-Zeilen bleiben gedimmt, BG-Ebene darunter */
.tt-ts-table tbody tr.tt-ts-row.tt-ts-row--alt.tt-ts-row-readonly {
  opacity: .75;
}

/* ── Datums-Header: klickbar (ZIEL 2, 2026-06-06) ───────────────────────── */
.tt-ts-col-sortable {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

.tt-ts-col-sortable:hover {
  color: var(--accent);
  background: var(--accent-light);
}

.tt-ts-th-sort-inner {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
}

.tt-ts-sort-icon {
  display: inline-flex;
  align-items: center;
  color: var(--accent);
  opacity: .8;
  flex-shrink: 0;
}

/* tfoot-Zellen */
.tt-ts-tfoot-label {
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-secondary);
  padding-top: .5rem;
  border-top: 1px solid var(--border);
}

.tt-ts-tfoot-total {
  text-align: right;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  padding-top: .5rem;
  border-top: 1px solid var(--border);
}

/* Rate-Spalte-Header: Text-Ausrichtung */
.tt-ts-col-rate {
  text-align: right;
}

.tt-ts-cell-rate {
  text-align: right;
}

.tt-ts-cell-time {
  white-space: nowrap;
}

/* Mobile (≤600px): horizontaler Scroll via .table-wrap — kein Umbau des Grids */
@media (max-width: 600px) {
  .tt-ts-table .input,
  .tt-ts-table input[type="time"],
  .tt-ts-table input[type="number"],
  .tt-ts-table input[type="text"] {
    height: 44px;
    min-height: 44px;
  }
}

/* ── Rechner-erstellen + Kalender-Toggle als rechtsbündige Gruppe (Fix 6 2026-06-10) ─── */
.tt-date-nav-right {
  margin-left: auto;   /* schiebt Gruppe ganz nach rechts */
  display: flex;
  align-items: center;
  gap: .375rem;
  flex-shrink: 0;
}

/* ── Rechnung-erstellen-Button in .tt-date-nav (innerhalb .tt-date-nav-right) ─────────── */
.tt-date-nav-action {
  flex-shrink: 0;
}

@media (max-width: 600px) {
  .tt-date-nav-right {
    margin-left: 0;
    width: 100%;
    justify-content: flex-end;
  }
  .tt-date-nav-action {
    flex: 1;
    justify-content: center;
  }

  /* Kompakt-1-Zeilen-Layout (Tag/Woche/Monat, s. @900px oben): Icon-Gruppe bleibt   */
  /* rechtsbündig INNERHALB der einen Zeile statt eigene volle Zeile zu beanspruchen */
  /* (der obige width:100%-Zweig war für das alte Mehrzeilen-Wrap-Layout gedacht).   */
  .tt-date-nav--single-line .tt-date-nav-right {
    margin-left: auto;
    width: auto;
    justify-content: flex-end;
  }
}

/* ── Custom-View Datum-Inputs in .tt-date-nav (seit 2026-06-06, vorher in .tt-filter-bar) ── */
.tt-date-nav .tt-filter-date {
  width: auto;
  min-width: 7rem;
  flex-shrink: 1;
  height: 32px;
  padding: 0 .625rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  font-size: .875rem;
  color: var(--text-primary);
}
.tt-date-nav .tt-filter-date::-webkit-calendar-picker-indicator {
  opacity: 0.4;
  cursor: pointer;
}

@media (max-width: 900px) {
  .tt-date-nav .tt-filter-date {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
  }
}

/* ── Split-Kalender Panel (Steps 7.3–7.7, 2026-06-09) ──────────────────────── */

/* 7.4: Kalender-Toggle-Button in .tt-date-nav */
.tt-cal-toggle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.tt-cal-toggle-btn:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.tt-cal-toggle-btn.is-active {
  background: var(--accent-light);
  color: var(--accent);
  border-color: var(--accent);
}
.tt-cal-toggle-btn.is-active:hover {
  background: var(--accent-light);
  color: var(--accent-dark);
}

/* Mobile: größerer Touch-Target */
@media (max-width: 900px) {
  .tt-cal-toggle-btn {
    width: 40px;
    height: 40px;
  }
}

/* 7.4: Desktop-Split-Layout */
.tt-split {
  display: block; /* kein Layout-Effekt wenn Panel geschlossen */
}

@media (min-width: 901px) {
  .tt-split--open {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
  }
  .tt-split--open .tt-split-main {
    flex: 1 1 50%;
    min-width: 0;
  }
  .tt-split-cal {
    flex: 1 1 50%;
    min-width: 0;
    position: sticky;
    top: 0;
    /* Fix 4: Höhen-Kette — Container hat feste Höhe + overflow:hidden,
       damit die innere .cal-time-scroll der echte Scroller wird.
       max-height + overflow-y:auto auf dem äußeren Container ließ
       firstUpdated()-scrollTop auf .cal-time-scroll wirkungslos. */
    height: calc(100vh - 180px);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-primary);
  }
}

/* Fix 4: Vollständige Höhen-Kette für ds-cal-week-view im Split-Kontext.
   page-calendar hat eigene Scoped-Regeln; hier equivalente Regeln für .tt-split-cal.
   Jede Ebene braucht flex:1 + min-height:0 damit .cal-time-scroll intern scrollt. */
@media (min-width: 901px) {
  .tt-split-cal ds-cal-week-view,
  .tt-split-cal .ds-cal-week-view {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
  }
  .tt-split-cal .cal-time-grid-wrap {
    flex: 1;
    min-height: 0;
  }
  .tt-split-cal .cal-time-scroll {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
  }
}

/* Fix 4 Mobile: Overlay-Body ist der Scroller (flex:1; overflow-y:auto).
   .cal-time-scroll darf keine eigene Höhe/Scroll haben — overflow:visible
   damit der Content fließt und firstUpdated() auf scrollEl den overlay-body scrollt. */
@media (max-width: 900px) {
  .tt-cal-overlay-body ds-cal-week-view { display: block; } /* Host-Tag nicht inline auf Mobile */
  .tt-cal-overlay-body .cal-time-grid-wrap {
    display: block; /* kein Flex-Constraint; Content fließt durch zum Overlay-Body */
  }
  .tt-cal-overlay-body .cal-time-scroll {
    overflow: visible; /* Overlay-Body scrollt; .cal-time-scroll ist kein Scroller */
    height: auto;
  }
}

/* Mobile: Desktop-Split-Cal verstecken (Overlay übernimmt) */
@media (max-width: 900px) {
  .tt-split-cal {
    display: none;
  }
}

/* 7.5: Mobile-Vollbild-Overlay */
.tt-cal-overlay {
  display: none; /* Default: nur auf Mobile via Media-Query sichtbar */
}

@media (max-width: 900px) {
  .tt-cal-overlay {
    display: flex;
    flex-direction: column;
    position: fixed;
    inset: 0;
    z-index: 460; /* über tt-quick-bar-sheet (z-index:450), unter ds-cal-panel (z-index:401 aufwärts) — passt weil Panel zu ist */
    background: var(--bg-primary);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .tt-cal-overlay-header {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
    background: var(--bg-primary);
  }
  .tt-cal-overlay-title {
    flex: 1;
    font-weight: 600;
    font-size: .9375rem;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .tt-cal-overlay-close {
    flex-shrink: 0;
    min-width: 44px;
    min-height: 44px;
  }
  .tt-cal-overlay-body {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
  }
}

/* ── Listen-Modus Accordion + Datum-Klick + „Eintrag hinzufügen" ─────────
   (Entscheidungs-Revision 2026-06-10)
   Klassen: .tt-list-day-chevron, .tt-list-day-expand,
            .tt-list-add-entry-row, .tt-list-add-entry-btn               */

/* Chevron-Indikator links in der Tages-Zeile */
.tt-list-day-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  color: var(--text-tertiary);
  transition: transform var(--transition), color var(--transition);
}
.tt-list-day-chevron.is-open {
  transform: rotate(180deg);
  color: var(--accent);
}

/* Datum-Label in Tages-Zeile: klickbar → Datum in Quick-Bar */
.tt-list-day-row .tt-list-day-row-date {
  cursor: pointer;
  border-radius: var(--radius-sm);
  padding: .0625rem .1875rem;
  transition: color var(--transition), background var(--transition);
  /* Flex füllt restliche Breite zwischen Chevron und Total */
  flex: 1;
  min-width: 0;
  text-align: left;
}
.tt-list-day-row .tt-list-day-row-date:hover {
  color: var(--accent);
  background: var(--accent-light);
}
.tt-list-day-row .tt-list-day-row-date:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Tages-Zeile im offenen Zustand */
.tt-list-day-row.is-open {
  background: var(--accent-light);
  border-bottom-color: var(--accent);
}
.tt-list-day-row.is-open .tt-list-day-row-date {
  font-weight: 700;
}

/* Aufgeklappter Bereich mit Eintrags-Tabelle */
.tt-list-day-expand {
  margin-bottom: .375rem;
  border-left: 3px solid var(--accent-light);
}

/* „Eintrag hinzufügen"-Zeile unter jeder Tages-Zeile */
.tt-list-add-entry-row {
  display: flex;
  justify-content: flex-end;   /* Fix 5: Button rechtsbündig */
  padding: .125rem .75rem .375rem;
  border-bottom: 1px solid var(--border);
}
.tt-list-add-entry-btn {
  display: inline-flex;
  align-items: center;
  gap: .3125rem;
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--text-tertiary);
  font-size: .8125rem;
  padding: .25rem .375rem;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
  line-height: 1;
}
.tt-list-add-entry-btn:hover {
  color: var(--accent);
  background: var(--accent-light);
}
.tt-list-add-entry-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

@media (max-width: 900px) {
  .tt-list-day-chevron {
    width: 24px;
    height: 24px;
  }
  .tt-list-day-row {
    /* chevron + flex-label: ensure min touch-target via existing 44px rule */
    gap: .25rem;
  }
  .tt-list-add-entry-btn {
    min-height: 36px; /* comfortable touch without full 44px — this is a subtle action */
    font-size: .875rem;
  }
}

/* ── Split-Kalender Wochennavigator (⑥c) ── */

.tt-cal-weeknav {
  display: flex;
  align-items: center;
  gap: .375rem;
  padding: .375rem .5rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
  flex-shrink: 0; /* in der Flex-Höhenkette nicht schrumpfen, damit cal-time-scroll den Rest bekommt */
}

.tt-cal-weeknav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-secondary);
  cursor: pointer;
  flex-shrink: 0;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.tt-cal-weeknav-btn:hover {
  background: var(--accent-light);
  color: var(--accent);
  border-color: var(--accent);
}

.tt-cal-weeknav-label {
  flex: 1;
  text-align: center;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (max-width: 600px) {
  .tt-cal-weeknav-btn { width: 36px; height: 36px; } /* Touch-Target im Mobile-Overlay */
}

/* ── Split-Kalender Wochen-/Arbeitswochen-Toggle ── */
.tt-cal-modetoggle {
  display: inline-flex;
  align-self: flex-start;
  margin: .5rem .5rem 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  flex-shrink: 0; /* Flex-Höhenkette des Split-Scrollers nicht brechen */
  background: var(--bg-secondary);
}

.tt-cal-modetoggle-btn {
  border: none;
  background: transparent;
  color: var(--text-secondary);
  font-size: .75rem;
  font-weight: 500;
  padding: .3125rem .625rem;
  min-height: 28px;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}

.tt-cal-modetoggle-btn + .tt-cal-modetoggle-btn {
  border-left: 1px solid var(--border);
}

.tt-cal-modetoggle-btn:hover {
  background: var(--bg-primary);
  color: var(--text-primary);
}

.tt-cal-modetoggle-btn.is-active {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
}

@media (max-width: 600px) {
  .tt-cal-modetoggle-btn {
    min-height: 36px;
    padding: .375rem .75rem; /* Touch-Target im Mobile-Overlay */
  }
}

/* ── Cal-Event-Block: Klickbar im TT-Split-Kalender (cal-event-click) ── */
/* Überschreibt _calendar.css .ds-cal-week-view .dcw-event-block { pointer-events:none }
   ausschließlich im Time-Tracking-Kontext — kein globaler Impact. */
.tt-split-cal .dcw-event-block,
.tt-cal-overlay-body .dcw-event-block {
  pointer-events: auto;
  cursor: pointer;
}

/* ── Cal-Event-Detail-Bubble (.tt-cal-event-bubble) ─────────────────── */
/* Inhalt des Dropdown.open-Popovers. Layout/Position liefert Dropdown — */
/* hier nur inneres Styling. Kein Shadow-DOM — alle Variablen aus base.css. */
.tt-cal-event-bubble {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .75rem;
  min-width: 240px;
  max-width: 320px;
  font-size: .8125rem;
  line-height: 1.45;
}

.tt-cal-event-bubble-header {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  flex-wrap: wrap;
}

.tt-cal-event-bubble-title {
  font-weight: 600;
  font-size: .9375rem;
  flex: 1;
  min-width: 0;
  word-break: break-word;
  color: var(--text-primary);
}

.tt-cal-event-bubble-meta {
  display: flex;
  gap: .375rem;
  align-items: center;
}

.tt-cal-event-bubble-type {
  font-size: .75rem;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: .04em;
}

/* Daten-Zeile: Icon + Text */
.tt-cal-event-bubble-row {
  display: flex;
  align-items: flex-start;
  gap: .4375rem;
  color: var(--text-secondary);
  font-size: .8125rem;
}

.tt-cal-event-bubble-icon {
  flex-shrink: 0;
  margin-top: .125rem;
  color: var(--text-tertiary);
}

/* Kurz-Notiz (max. 120 Zeichen) */
.tt-cal-event-bubble-notes {
  font-size: .8125rem;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  padding: .375rem .5rem;
  white-space: pre-wrap;
  word-break: break-word;
}

/* Footer: „Im Kalender öffnen"-Link */
.tt-cal-event-bubble-footer {
  border-top: 1px solid var(--border);
  padding-top: .5rem;
  margin-top: .125rem;
}

.tt-cal-event-bubble-link {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  font-size: .8125rem;
  color: var(--accent);
  padding: .25rem .375rem;
}

.tt-cal-event-bubble-link:hover {
  background: var(--accent-light);
  border-radius: var(--radius-sm);
}

/* ── Mobile Entry-List: native-row Modifier für Zeiterfassung ── */
/* Schmalere Datums-/Zeit-Spalte links — fixed width damit Mitte mehr Platz hat */
.tt-mobile-entry-left {
  min-width: 3.75rem;
  max-width: 3.75rem;
  text-align: center;
}

/* Dauer + Status-Badge oben-unten gestapelt rechts */
.tt-mobile-entry-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .25rem;
  min-width: 4rem;
}

/* ── Import-Vorlagen-Verwaltung (page-settings-import-mappings) ──
   Settings-Screen (#/settings/import-mappings), Gear-Icon im Time-Tracking-L3-Menü. */
.tt-imap-actions-col {
  width: 1%;
  white-space: nowrap;
}

.tt-imap-danger-icon {
  color: var(--coral);
  display: inline-flex;
}

.tt-imap-panel-footer {
  display: flex;
  gap: .5rem;
  margin-top: 1rem;
}

.tt-imap-panel-footer .btn {
  flex: 1;
}

.tt-imap-toggle-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: .75rem;
}

/* ── Dashboard (Spec 20260710_dashboard_foundation) ────────── */

/* Hej-Header — fix, nicht Teil des Widget-Rasters */
.ds-dashboard-hej-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.ds-dashboard-hej-text { min-width: 0; }

.ds-dashboard-hej-title { margin: 0; }

.ds-dashboard-hej-sub {
  margin-top: 0.25rem;
  color: var(--text-secondary);
  font-size: 0.9375rem;
}

/* Skeleton-Zustand des Hej-Headers (pages/dashboard.js, während api.users.me() lädt) */
.ds-dashboard-hej-skeleton-title { height: 1.75rem; }
.ds-dashboard-hej-skeleton-sub { margin-top: 0.5rem; }

.ds-dashboard-quick-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  flex-shrink: 0;
}

.ds-dashboard-quick-action {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.5rem 0.875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: 0.8125rem;
  font-weight: 500;
  cursor: pointer;
  min-height: 40px;
  white-space: nowrap;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.ds-dashboard-quick-action svg { width: 16px; height: 16px; flex-shrink: 0; }
.ds-dashboard-quick-action:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-light);
}
.ds-dashboard-quick-action:active { transform: scale(0.97); }

/* Anpassen-Modus (Session D2, konfigurierbare Schnell-Buttons): Navigate-Klick
   deaktiviert (das ×-Entfernen bleibt aktiv) — kein Hover-Feedback dafür. */
.ds-dashboard-quick-action:disabled { cursor: default; }
.ds-dashboard-quick-action:disabled:hover {
  border-color: var(--border);
  color: var(--text-primary);
  background: var(--bg-primary);
}

/* Wrapper pro Button im Anpassen-Modus — trägt das ×-Entfernen-Badge relativ positioniert */
.ds-dashboard-quick-action-wrap { position: relative; display: inline-flex; }

/* Quick-Action-Reorder (Drag&Drop) – eigenstaendiger DnD-Kreis (Pillen-Liste,
   kein Grid-Raster), Nachbar-Hervorhebung bleibt hier bewusst bestehen (kein
   Bezug zu ds-dashboard-tile). Grab-Cursor + touch-action:none auf dem Wrap
   allein reicht nicht, weil .ds-dashboard-quick-action selbst cursor:pointer
   setzt – deshalb der Button-Override darunter. */
.ds-dashboard-quick-action-wrap.is-editing { cursor: grab; touch-action: none; }
.ds-dashboard-quick-action-wrap.is-editing:active { cursor: grabbing; }
.ds-dashboard-quick-action-wrap.is-editing .ds-dashboard-quick-action { cursor: grab; }
.ds-dashboard-quick-action-wrap.is-editing:active .ds-dashboard-quick-action { cursor: grabbing; }
.ds-dashboard-quick-action-wrap.is-dragging { opacity: 0.5; }
.ds-dashboard-quick-action-wrap.is-drop-target {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-pill);
}

.ds-dashboard-quick-action-remove {
  position: absolute;
  top: -7px;
  right: -7px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--bg-primary);
  color: var(--text-tertiary);
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: color var(--transition), border-color var(--transition), background var(--transition);
}
.ds-dashboard-quick-action-remove svg { width: 9px; height: 9px; }
.ds-dashboard-quick-action-remove:hover { color: var(--danger); border-color: var(--danger); background: var(--danger-light); }

/* "+ Button"-Trigger — dezente gestrichelte Variante der Quick-Action-Pille */
.ds-dashboard-quick-action-add { border-style: dashed; color: var(--text-secondary); }
.ds-dashboard-quick-action-add:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-light);
}
.ds-dashboard-quick-action-add:disabled { opacity: 0.4; cursor: not-allowed; }

.ds-dashboard-quick-actions-empty-hint {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
  padding: 0.5rem 0;
}

/* 4-Spalten-Raster */
.ds-dashboard-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}

.ds-dashboard-tile {
  grid-column: span var(--dashboard-tile-span, 4);
  /* Hoehen-Stufe (Ticket 3.383.3) -- Default 1 = unveraendertes Verhalten
     (eine einzelne Zeilen-Spur, exakt wie vor der Funktion, AC3). Ab Stufe 2
     spannt die Kachel mehrere auto-Zeilen-Spuren -- Nachbar-Kacheln in der
     jeweils GLEICHEN Zeilen-Spur bleiben dadurch eigenstaendig hoch statt
     durch das Grid-eigene align-items:stretch auf die volle Kachelhoehe
     mitgezogen zu werden (s. dashboard.md "Hoehen-Stufen"). */
  grid-row: span var(--dashboard-tile-rowspan, 1);
  min-width: 0;
}

/* Rasterspalten-Lineal im Anpassen-Modus (Ticket 3.420) -- s. den
   ausfuehrlichen Kommentar bei _renderDragGridGuides() (_dashboard-grid-dnd.js)
   fuer die Begruendung: eine Linie HINTER den Kacheln waere in vollstaendig
   gefuellten Reihen (der Regelfall) komplett unsichtbar. Das Lineal belegt
   stattdessen explizit die erste Grid-Zeile -- immer sichtbar, unabhaengig
   von der Kachel-Belegung. Auf Mobile per Media-Query unten ausgeblendet
   (1-spaltig, ein Spalten-Lineal ergibt dort keinen Sinn). */
.ds-dashboard-grid-ruler {
  grid-column: 1 / -1;
  grid-row: 1;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
  pointer-events: none;
}
.ds-dashboard-grid-ruler-col {
  height: 3px;
  border-radius: var(--radius-pill);
  background: var(--border);
}

/* Einfuegemarke waehrend eines aktiven Zugs (Ticket 3.420) -- ersetzt den
   Inhalt der gezogenen Kachel an ihrem kuenftigen Platz (s.
   _renderDragInsertGhost); nutzt dieselbe Span-/Zeilenhoehe-Grid-Platzierung
   wie .ds-dashboard-tile (Klasse bleibt zusaetzlich gesetzt), zeigt aber
   bewusst KEINEN Karteninhalt -- Optik wie ein Ablage-Platzhalter. */
.ds-dashboard-tile-drop-ghost {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 64px;
  border: 2px dashed var(--accent);
  border-radius: var(--radius-lg);
  background: var(--accent-light);
  pointer-events: none;
}
.ds-dashboard-tile-drop-ghost-label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--accent);
}

/* Modul-Icon vor dem Kachel-Titel im .card-header — normalisiert die
   unterschiedlichen ICONS-SVG-Größen (16/20/24) auf 18px, gedämpfte Farbe
   damit das Icon den Titel nicht überstrahlt. */
.ds-dashboard-tile-title { display: flex; align-items: center; gap: 0.5rem; }
.ds-dashboard-tile-title-icon { display: inline-flex; align-items: center; flex-shrink: 0; color: var(--text-tertiary); }
.ds-dashboard-tile-title-icon svg { width: 18px; height: 18px; }

/* Lade-Platzhalter-Kacheln (pages/dashboard.js, vor dem 1. api.users.me()-Resultat) —
   feste 2-spaltige Breite, kein dynamisches --dashboard-tile-span nötig. */
.ds-dashboard-tile-loading { grid-column: span 2; min-width: 0; }

.ds-dashboard-tile-skeleton {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.25rem 0;
}

.ds-dashboard-tile-error {
  color: var(--text-tertiary);
  font-size: 0.8125rem;
  padding: 0.5rem 0;
}

/* 🔒 Bewusst zwei Leerzustands-Formen, unterschiedlicher Zweck (Ticket
   3.400.1 Teil 2, AK4): .ds-dashboard-empty-hint bleibt ein reiner Text OHNE
   Icon -- fuer TEILWEISE leere Abschnitte innerhalb einer sonst gefuellten
   Kachel (z.B. "Offene Posten": keine Forderungen, aber weiterhin eine Zeile
   "Offene Verbindlichkeiten" sichtbar). .ds-dashboard-tile-empty (unten) ist
   der neue, einheitliche GANZE-Kachel-Leerzustand mit Symbol -- s.
   pages/dashboard/_tile-empty.js renderTileEmpty(). Ersetzt zwei bisher
   nebeneinander stehende Formen (den reinen Text hier UND das von
   .empty-state/.empty-state--compact (_core.css) geliehene 80px-Icon, das
   fuer eine bei Stufe 1 auf 150px gedeckelte Kachel zu gross war). */
.ds-dashboard-empty-hint {
  font-size: 0.875rem;
  color: var(--text-secondary);
  padding: 0.5rem 0;
}

/* Einheitlicher GANZE-Kachel-Leerzustand: Symbol + ein Satz (+ optionaler
   Button) -- renderTileEmpty() in _tile-empty.js. Icon deutlich kleiner als
   der Seiten-Leerzustand (.empty-state svg: 80px, _core.css) -- passend fuer
   eine max. 150px hohe Stufe-1-Kachel (_tile-height.js TILE_HEIGHT_PX[1]). */
.ds-dashboard-tile-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 1rem 0.5rem;
  text-align: center;
}
.ds-dashboard-tile-empty-icon {
  display: inline-flex;
  color: var(--text-tertiary);
  opacity: 0.6;
}
.ds-dashboard-tile-empty-icon svg { width: 28px; height: 28px; }
.ds-dashboard-tile-empty-text {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  max-width: 22rem;
}

/* Farbiger Status-Punkt vor einer Kennzahl (Ticket 3.400.1 Teil 2, AK3) --
   ersetzt eine reine Zahl durch eine sofort erkennbare Zustands-Farbe (z.B.
   "braucht eine Antwort" bei offenen Terminanfragen, .ds-dashboard-stat-line
   in _dashboard-widgets-limitable.js). align-self statt der geerbten
   align-items:baseline des Eltern-Flex (.ds-dashboard-stat-line) -- ein Punkt
   hat keine Grundlinie, würde sonst optisch nach unten verrutschen. */
.ds-dashboard-status-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  align-self: center;
  flex-shrink: 0;
}
.ds-dashboard-status-dot--amber  { background: var(--amber); }
.ds-dashboard-status-dot--coral  { background: var(--coral); }
.ds-dashboard-status-dot--accent { background: var(--accent); }
.ds-dashboard-status-dot--teal   { background: var(--teal); }

/* Abstand zwischen dem KPI-Wert (bzw. der Stage-Liste) und dem optionalen
   Anteilsbalken darunter/darüber (renderShareBar(), _charts.js) -- Ticket
   3.400.1 Teil 2 (AK3), genutzt von invoices_open + deals_by_stage
   (dashboard-widgets.js). .ds-share-bar bringt selbst kein Außenabstand mit
   (lebt auch verschachtelt in .ds-dashboard-throughput, wo der Flex-Gap des
   Elternteils reicht) -- dieser schmale Wrapper ergänzt ihn nur dort, wo kein
   Flex-Elternteil existiert. */
.ds-dashboard-tile-statusbar { margin-top: 0.5rem; margin-bottom: 0.625rem; }

/* Widget: Wiedervorlagen – heute fällig */
.ds-dashboard-followup-list { display: flex; flex-direction: column; }

.ds-dashboard-followup-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background var(--transition);
}
.ds-dashboard-followup-row:last-child { border-bottom: none; }
.ds-dashboard-followup-row:hover { background: var(--bg-secondary); }
.ds-dashboard-followup-row .followup-date { min-width: 100px; font-size: 0.8125rem; }
.ds-dashboard-followup-row .followup-priority { font-size: 0.75rem; }

.ds-dashboard-followup-title {
  flex: 1;
  min-width: 0;
  font-size: 0.875rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Anpassen-Modus (Session 1b) ─────────────────────────────── */
.ds-dashboard-edit-bar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.75rem;
  margin-top: 0.75rem;
}

.ds-dashboard-edit-bar.is-editing {
  justify-content: space-between;
  flex-wrap: wrap;
  padding: 0.625rem 0.875rem;
  background: var(--accent-light);
  border: 1px dashed var(--accent);
  border-radius: var(--radius-md);
}

.ds-dashboard-edit-bar-hint {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.ds-dashboard-edit-bar-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

.ds-dashboard-edit-toggle svg,
.ds-dashboard-edit-bar-actions svg { width: 15px; height: 15px; flex-shrink: 0; }

/* Kachel im Anpassen-Modus: dezenter gestrichelter Rahmen, Inhalt inaktiv/gedimmt
   (verhindert Fehlklicks in Widget-Inhalten während des Umsortierens). */
.ds-dashboard-tile--editing { outline: 1px dashed var(--border); outline-offset: -1px; }
.ds-dashboard-tile--editing .card-body { opacity: 0.72; pointer-events: none; }
/* is-drop-target entfiel mit Ticket 3.420 -- der Zielplatz wird seither
   durch die Live-Einfuegevorschau (.ds-dashboard-tile-drop-ghost, s. oben)
   gezeigt statt durch eine markierte Nachbar-Kachel. */
.ds-dashboard-tile.is-dragging { opacity: 0.5; }

.ds-dashboard-tile-edit-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.875rem;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}

.ds-dashboard-tile-drag-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  cursor: grab;
  touch-action: none;
  transition: background var(--transition), color var(--transition);
}
.ds-dashboard-tile-drag-handle:hover { color: var(--text-primary); background: var(--bg-tertiary); }
.ds-dashboard-tile-drag-handle:active { cursor: grabbing; }

/* Mobile-Reorder-Pfeile — ersetzen den Drag-Griff auf Touch (≤900px, s. Media-Query unten) */
.ds-dashboard-tile-move-buttons { display: none; align-items: center; gap: 0.25rem; flex-shrink: 0; }
.ds-dashboard-tile-move-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.ds-dashboard-tile-move-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.ds-dashboard-tile-move-btn:disabled { opacity: 0.35; cursor: not-allowed; }

/* Icon-Kennzeichnung je Editbar-Gruppe (Ticket 3.383.3, Feinschliff) – macht
   Breite/Höhe/Anzahl-Umschalter auf einen Blick unterscheidbar, vorher drei
   optisch identische Zahlenreihen ohne Beschriftung nebeneinander. Gedämpfte
   Farbe wie .ds-dashboard-tile-title-icon (Icon soll die Zahlen nicht
   überstrahlen), erstes Kind der jeweiligen -switch-Gruppe – der bestehende
   gap der Gruppe reicht als Abstand zum ersten Knopf. */
.ds-dashboard-editbar-group-icon { display: inline-flex; align-items: center; justify-content: center; margin-left: 0.125rem; color: var(--text-tertiary); flex-shrink: 0; }
.ds-dashboard-editbar-group-icon svg { display: block; width: 13px; height: 13px; }

/* Breiten-Umschalter 1·2·3·4 — nur die in widget.spans erlaubten Werte sind aktiv/klickbar */
.ds-dashboard-span-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.125rem;
  padding: 0.1875rem;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}
.ds-dashboard-span-btn {
  min-width: 26px;
  height: 24px;
  padding: 0 0.25rem;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.ds-dashboard-span-btn:hover:not(:disabled) { color: var(--text-primary); }
.ds-dashboard-span-btn.active { background: var(--bg-primary); color: var(--accent); box-shadow: var(--shadow-sm); }
.ds-dashboard-span-btn:disabled { opacity: 0.3; cursor: not-allowed; }

/* Eintrags-Grenze 5·10·20·Alle (Ticket 3.383) – Optik-Zwilling zum Breiten-
   Umschalter oben, nur bei widget.supportsLimit gerendert. */
.ds-dashboard-limit-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.125rem;
  padding: 0.1875rem;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}
.ds-dashboard-limit-btn {
  min-width: 26px;
  height: 24px;
  padding: 0 0.375rem;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.ds-dashboard-limit-btn:hover { color: var(--text-primary); }
.ds-dashboard-limit-btn.active { background: var(--bg-primary); color: var(--accent); box-shadow: var(--shadow-sm); }

/* Hoehen-Stufe 1·2·3 (Ticket 3.383.3) – Optik-Zwilling zum Breiten-Umschalter
   oben, fuer JEDES Widget verfuegbar (reine Layout-Eigenschaft, keine
   Widget-Typ-Einschraenkung wie beim Eintrags-Grenze-Umschalter). */
.ds-dashboard-height-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.125rem;
  padding: 0.1875rem;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}
.ds-dashboard-height-btn {
  min-width: 26px;
  height: 24px;
  padding: 0 0.25rem;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.ds-dashboard-height-btn:hover { color: var(--text-primary); }
.ds-dashboard-height-btn.active { background: var(--bg-primary); color: var(--accent); box-shadow: var(--shadow-sm); }

.ds-dashboard-tile-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  margin-left: auto;
  flex-shrink: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.ds-dashboard-tile-remove:hover:not(:disabled) { color: var(--danger); background: var(--danger-light); }
.ds-dashboard-tile-remove:disabled { opacity: 0.3; cursor: not-allowed; }

/* ── Widget-Katalog (Slide-In-Panel via <ds-cal-panel>) ─────────── */
.ds-dashboard-catalog { display: flex; flex-direction: column; gap: 1.25rem; }
.ds-dashboard-catalog-group { display: flex; flex-direction: column; gap: 0.375rem; }
.ds-dashboard-catalog-group-label {
  padding: 0 0.125rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.ds-dashboard-catalog-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.75rem 0.875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: 0.875rem;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.ds-dashboard-catalog-item:hover { border-color: var(--accent); background: var(--accent-light); }
.ds-dashboard-catalog-item-add {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--accent-light);
  color: var(--accent);
}
.ds-dashboard-catalog-item-add svg { width: 13px; height: 13px; }

/* ── Config-Picker (Session C, parametrisierte Multi-Instanz-Widgets) ────────
   Katalog-Zwischenschritt beim Hinzufügen eines configSchema-Widgets
   (_renderConfigureContent()) — Scope-Auswahl + optionales Ziel-<select>. */
.ds-dashboard-config-picker {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.ds-dashboard-config-back,
.ds-dashboard-config-confirm { align-self: flex-start; }

.ds-dashboard-config-scope-group {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.ds-dashboard-config-scope-btn {
  padding: 0.5rem 0.875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-size: 0.8125rem;
  font-weight: 500;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition), color var(--transition);
}
.ds-dashboard-config-scope-btn:hover { border-color: var(--accent); color: var(--accent); }
.ds-dashboard-config-scope-btn.active {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
}

.ds-dashboard-config-id-field {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}
.ds-dashboard-config-id-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-secondary);
}
.ds-dashboard-config-id-empty {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--text-tertiary);
}

/* Kachel-interner Scope-/Ziel-Umschalter (Anpassen-Modus, s. _renderTileEditBar) */
.ds-dashboard-tile-config-switch {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  flex-wrap: wrap;
}
.ds-dashboard-tile-config-switch .select {
  width: auto;
  min-width: 6.5rem;
  max-width: 11rem;
}
@media (max-width: 900px) {
  .ds-dashboard-tile-config-switch .select { min-width: 0; max-width: none; flex: 1 1 8rem; }
}

/* Widget: Deals nach Stage */
.ds-dashboard-stage-list { display: flex; flex-direction: column; }

.ds-dashboard-stage-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.625rem 0;
  border-bottom: 1px solid var(--border);
}
.ds-dashboard-stage-row:last-child { border-bottom: none; }

.ds-dashboard-stage-left {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  min-width: 0;
}

.ds-dashboard-stage-badge { min-width: 100px; justify-content: center; }

.ds-dashboard-stage-count { font-size: 0.875rem; color: var(--text-secondary); white-space: nowrap; }

.ds-dashboard-stage-value { font-size: 0.875rem; font-weight: 500; white-space: nowrap; }

/* ── Widgets Schritt 1 (Spec 20260710_dashboard_widgets_step1) ──────────── */

/* KPI-Kachel: Offene Rechnungen, Umsatz Monat */
.ds-dashboard-kpi {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  margin: -0.25rem;
  padding: 0.25rem;
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background var(--transition);
}
.ds-dashboard-kpi:hover { background: var(--bg-secondary); }

.ds-dashboard-kpi-value {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.15;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
/* Ticket 3.400.5 ("Gewinn-Übersicht"): negativer Gewinn (Ausgaben > Einnahmen
   im Zeitraum) in Rot statt der Standardfarbe. */
.ds-dashboard-kpi-value.is-negative { color: var(--coral); }

.ds-dashboard-kpi-sub {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.ds-dashboard-kpi-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.0625rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.ds-dashboard-kpi-badge--danger { background: var(--danger-light); color: var(--danger); }

.ds-dashboard-kpi-trend {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.8125rem;
  font-weight: 600;
}
.ds-dashboard-kpi-trend svg { flex-shrink: 0; }
.ds-dashboard-kpi-trend.is-up   { color: var(--teal); }
.ds-dashboard-kpi-trend.is-down { color: var(--coral); }

/* Ticket 3.400.3 ("Aufgaben-Durchsatz"): is-up/is-down oben bedeuten bei
   einem Umsatz-Trend "mehr = gut" (teal). Beim Aufgaben-Saldo (Zugang minus
   Abgang) ist mehr = schlechter (waechsender Rueckstand) -- eigene Modifier,
   damit die Farbe die tatsaechliche Bedeutung traegt statt nur die Zahlen-
   Richtung. */
.ds-dashboard-kpi-trend.is-worse  { color: var(--coral); }
.ds-dashboard-kpi-trend.is-better { color: var(--teal); }

/* Mini-Sparkline (Umsatz Monat) — einfache CSS-Bar-Reihe statt Chart-Library */
.ds-dashboard-sparkline {
  display: flex;
  align-items: flex-end;
  gap: 0.1875rem;
  height: 32px;
  margin-top: 0.25rem;
}
.ds-dashboard-sparkline-bar {
  flex: 1 1 0;
  height: var(--bar-h, 6%);
  min-height: 3px;
  border-radius: 2px 2px 0 0;
  background: var(--accent-light);
}
.ds-dashboard-sparkline-bar.is-current { background: var(--accent); }

/* Generische Zeilen-Liste: Termine, Einladungen, Buchungen, Mail, Aufgaben */
.ds-dashboard-list { display: flex; flex-direction: column; }

.ds-dashboard-list-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background var(--transition);
}
.ds-dashboard-list-row:last-child { border-bottom: none; }
.ds-dashboard-list-row:hover { background: var(--bg-secondary); }
.ds-dashboard-list-row.is-unread .ds-dashboard-list-row-title { font-weight: 600; }

.ds-dashboard-list-row-time {
  flex-shrink: 0;
  min-width: 52px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
}

.ds-dashboard-list-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.0625rem;
}

.ds-dashboard-list-row-title {
  font-size: 0.875rem;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ds-dashboard-list-row-sub {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ds-dashboard-list-row-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-sm);
  color: var(--accent);
  transition: background var(--transition);
}
.ds-dashboard-list-row-icon:hover { background: var(--accent-light); }

/* Fusszeile "N von M – Alle anzeigen" (Ticket 3.383) – nur wenn eine Kachel
   weniger Eintraege zeigt als tatsaechlich vorhanden sind (renderTileFooter()
   in _tile-limit.js entscheidet, ob sie ueberhaupt gerendert wird). Ersetzt
   das frühere, widget-eigene ".ds-dashboard-list-more" ("und N weitere"). */
.ds-dashboard-tile-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.5rem 0 0;
  margin-top: 0.25rem;
  border-top: 1px solid var(--border);
  font-size: 0.8125rem;
  color: var(--text-tertiary);
}
.ds-dashboard-tile-footer-link {
  flex-shrink: 0;
  border: none;
  background: transparent;
  color: var(--accent);
  font-size: 0.8125rem;
  font-weight: 500;
  cursor: pointer;
  padding: 0;
}
.ds-dashboard-tile-footer-link:hover { text-decoration: underline; }

/* "Alle" gewaehlt (Ticket 3.383): urspruenglich eine eigene, feste Bildlauf-
   leiste (420px/mobil 320px) fuer Widgets ohne gesetzte Hoehen-Stufe. Seit
   Ticket 3.383.5 hat JEDE Hoehen-Stufe (auch Normal) eine feste Body-Hoehe
   ueber .ds-dashboard-tile-body-height-capped unten -- diese Klasse wird von
   _renderTile() dadurch nicht mehr vergeben (Vorrang-Regel), bleibt aber
   definiert falls ein kuenftiges Widget ohne Hoehen-Stufen-Konzept sie direkt
   braucht. */
.ds-dashboard-tile-body-scroll-all {
  max-height: 420px;
  overflow-y: auto;
}
@media (max-width: 900px) {
  .ds-dashboard-tile-body-scroll-all { max-height: 320px; }
}

/* Hoehen-Stufe 2/3 "Hoch"/"Doppelt hoch" (Ticket 3.383.3): ECHTE feste
   Body-Hoehe (--dashboard-tile-height, s. _tile-height.js) -- bewusst
   `height`, NICHT `max-height`: der Zweck dieser Stufen ist, eine HOEHERE
   Grid-Zeilen-Spur zu ERZWINGEN (grid-row:span N auf .ds-dashboard-tile), und
   das kann `max-height` nicht -- eine Kachel mit wenig eigenem Inhalt bekommt
   sonst optisch KEINE hoehere Zeilen-Spur, weil `max-height` bei kurzem
   Inhalt keine Wirkung entfaltet (gemessen Ticket 3.383.3 AK1: mit nur 2
   Nachbar-Kacheln blieb die Reihe unveraendert flach). `height` liefert damit
   dem Grid-Sizing-Algorithmus einen DETERMINISTISCHEN Beitrag fuer
   grid-row:span, unabhaengig davon ob genug Nachbar-Inhalt existiert.
   overflow-y:auto faengt zu langen Inhalt ab. */
.ds-dashboard-tile-body-height-capped {
  height: var(--dashboard-tile-height, 600px);
  overflow-y: auto;
}

/* Hoehen-Stufe 1 "Normal" (Ticket 3.383.5, Korrektur nach Rueckmeldung
   Domenico 29.08.2026): bewusst `max-height`, NICHT `height` -- anders als
   Stufe 2/3 (oben) spannt Stufe 1 genau EINE Grid-Zeilen-Spur und muss nichts
   erzwingen, der Grund fuer `height` oben traegt hier also nicht. Domenico
   woertlich: "Wenn ein Widget auf 1 ist, sollte er auch nur klein angezeigt
   werden. Ist der Inhalt groesser, muesste er scrollbar sein." -- das
   beschreibt eine OBERGRENZE (kurzer Inhalt -> kurze Kachel, langer Inhalt ->
   gedeckelt mit Bildlaufleiste), keine feste Groesse. Die erste Fassung
   dieses Tickets setzte hier `height` (wie Stufe 2/3) und zwang dadurch JEDE
   Stufe-1-Kachel auf 300px, auch eine Kennzahl-Kachel mit 66px Inhalt (234px
   Leerraum, gemessen + per Screenshot belegt) -- das Gegenteil von "nur klein
   angezeigt". `max-height` + `overflow-y:auto` liefert exakt das geforderte
   Verhalten: kurzer Inhalt bleibt kurz, langer Inhalt scrollt ab dem
   Deckel. Deckel seit Ticket 3.383.7 auf 150px halbiert (Domenico
   29.08.2026: Stufe 1 war "noch zu hoch"), Fallback-Wert unten haelt sich
   bewusst an TILE_HEIGHT_PX[1] in _tile-height.js -- ein Auseinanderlaufen
   waere hier ein reiner Spiegelfehler (P-5). */
.ds-dashboard-tile-body-maxheight-capped {
  max-height: var(--dashboard-tile-height, 150px);
  overflow-y: auto;
}

/* Kompakte Kennzahl-Zeile: Posteingang (ungelesen), Buchungen & Anfragen (offene Anfragen) */
.ds-dashboard-stat-line {
  display: flex;
  align-items: baseline;
  gap: 0.375rem;
  padding: 0.125rem 0 0.5rem;
  cursor: pointer;
}
.ds-dashboard-stat-line:hover .ds-dashboard-stat-line-value { color: var(--accent); }

.ds-dashboard-stat-line-value {
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  transition: color var(--transition);
}

.ds-dashboard-stat-line-label { font-size: 0.8125rem; color: var(--text-secondary); }

/* ── Dashboard-Kachel-Titel-Badge ──────────────────────────────────────────
   Inline-Zähler direkt im Kachel-Titel (z.B. Posteingang-Ungelesen-Zahl) —
   analog .ds-notif-badge (nav.css), aber inline statt position:absolute.
   Hinweis: fachlich gehört das zu _dashboard.css (alle .ds-dashboard-*-
   Klassen leben dort) — diese Session war per Auftrag auf _core.css
   beschränkt, siehe Erfolgsreport. */
.ds-dashboard-title-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.375rem;
  margin-left: 0.5rem;
  flex-shrink: 0;
  border-radius: 999px;
  background: var(--coral);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1;
}

/* ── Widgets: Aufgaben-Durchsatz + Aufgaben-Verteilung (Ticket 3.400.3 +
   3.400.4, Frontend app/assets/js/pages/dashboard/_widgets-todo-charts.js)
   Fachlich gehören beide Widgets hierher (_dashboard.css) -- die Delegation
   dieser Session war auf _core.css beschränkt (analog dem Präzedenzfall bei
   .ds-dashboard-title-badge oben), s. Erfolgsreport. Beide Kacheln nutzen
   den geteilten Diagramm-Baustein pages/dashboard/_charts.js (Ticket
   3.400.1) -- renderGroupedBars() bringt seine SVG-/Balken-Geometrie über
   die bereits bestehenden .report-history-*-Klassen (_todos.css) selbst
   mit. Hier fehlten bislang NUR: die Segmentbalken-Klassen .ds-share-bar*
   (renderShareBar() hatte seit 3.400.1 noch keinen Aufrufer, s.
   design-system.md "Geteilter Diagramm-Baustein") sowie schmale
   Layout-Wrapper für diese beiden Kacheln. ─────────────────────────────── */

.ds-dashboard-throughput { display: flex; flex-direction: column; gap: 0.625rem; }
.ds-dashboard-throughput-legend { margin-bottom: 0; }

.ds-dashboard-chart-footnote {
  margin: 0.25rem 0 0;
  font-size: 0.75rem;
  color: var(--text-tertiary);
  font-style: italic;
}

/* Anteilsbalken "Aufgaben-Verteilung": EIN waagerechter Balken aus Segmenten
   + Legende darunter (renderShareBar(), _charts.js) -- kompakter als die
   Zeilen-Form (.report-breakdown-list, _todos.css) für schmale Kacheln. */
.ds-share-bar { display: flex; flex-direction: column; gap: 0.625rem; }

.ds-share-bar-track {
  display: flex;
  height: 10px;
  border-radius: 5px;
  overflow: hidden;
  background: var(--bg-tertiary);
}

.ds-share-bar-seg {
  display: block;
  height: 100%;
  min-width: 2px;
  transition: width 0.25s ease;
}

.ds-share-bar-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.875rem;
}

.ds-share-bar-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.78rem;
  color: var(--text-secondary);
}

.ds-share-bar-legend-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
}

.ds-share-bar-legend-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 11rem;
}

.ds-share-bar-legend-pct {
  font-size: 0.72rem;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}

/* Widget "Offene Posten" (Ticket 3.400.6): Verbindlichkeiten-Zeile unter der
   Forderungen-Anteilsbalken -- eigene, klickbare Reihe (navigiert zu den
   Belegen), separat vom .ds-dashboard-kpi-Pattern gehalten, da hier keine
   grosse KPI-Zahl noetig ist, nur eine Betrags-Zeile. */
.ds-dashboard-open-items-payables {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0.25rem;
  margin: -0.25rem;
  border-top: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background var(--transition);
}
.ds-dashboard-open-items-payables:hover { background: var(--bg-secondary); }

.ds-dashboard-open-items-payables-label {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.ds-dashboard-open-items-payables-value {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ds-dashboard-open-items-payables-count {
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--text-tertiary);
}

/* ── Widget: Tagesplan "Heute" (Ticket 3.400.2) ────────────────────────────
   Gemeinsame Zeitachse aus Terminen + heute fälligen Aufgaben. `.ds-dayplan`
   trägt eine Container-Query (container-type:inline-size) – bei schmalster
   Kachelbreite (Ticket-Vorgabe "ohne Achse, nur Liste") blendet
   @container die Punkt+Verbindungs-Spalte aus, die reinen Zeit+Titel-Zeilen
   bleiben stehen. Neu, weil eine Media-Query den tatsächlich gerenderten
   Kachel-Inhaltsbereich (abhängig von entry.span, nicht vom Viewport) nicht
   erfassen kann – das Widget setzt den Container selbst, ohne
   ds-dashboard-grid.js anzufassen. Zeilen-Titel/-Sub nutzen bewusst die
   bestehenden .ds-dashboard-list-row-title/-sub (s.o.) statt neuer
   Typografie-Klassen. Der Checkbox-Kreis für "Aufgaben ohne Uhrzeit"
   reused .todo-checkbox (_todos.css) – dieselbe Optik wie überall sonst im
   Todo-Modul, keine zweite Checkbox-Komponente. */
.ds-dayplan {
  container-type: inline-size;
  container-name: dayplan;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.ds-dayplan-allday { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.ds-dayplan-allday-chip {
  border: none;
  background: var(--accent-light);
  color: var(--accent);
  font-size: 0.75rem;
  font-weight: 500;
  padding: 0.25rem 0.625rem;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background var(--transition);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-dayplan-allday-chip:hover { background: color-mix(in srgb, var(--accent-light) 60%, var(--accent) 20%); }

.ds-dayplan-axis { display: flex; flex-direction: column; }

.ds-dayplan-row {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  padding: 0.3125rem 0;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background var(--transition);
}
.ds-dayplan-row:hover { background: var(--bg-secondary); }

.ds-dayplan-row-time {
  flex-shrink: 0;
  width: 38px;
  padding-top: 0.125rem;
  text-align: right;
  font-size: 0.75rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}

/* Kreis = Termin, abgerundetes Quadrat = Aufgabe -- Formunterschied, nicht
   nur Farbe (Ticket-Vorgabe "unterscheidbar von Terminen"). */
.ds-dayplan-row-dot {
  flex-shrink: 0;
  width: 9px;
  height: 9px;
  margin-top: 0.3125rem;
  border-radius: 50%;
  background: var(--accent);
}
.ds-dayplan-row--task .ds-dayplan-row-dot { border-radius: 3px; background: var(--teal); }

/* flex:1 (Ticket 3.400.2 Nachtrag) -- schiebt das optionale Video-Icon
   (.ds-dashboard-list-row-icon, s. Datei-Header "Videocall-Icon") an den
   rechten Rand der Zeile -- identisches Verhalten zu .ds-dashboard-list-row-main
   in der Kachel "Anstehende Termine" (_dashboard.css:697-703). Ohne flex:1
   wuerde das Icon direkt hinter dem Titel-Body kleben statt rechtsbuendig. */
.ds-dayplan-row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.0625rem; }

/* "Jetzt"-Zeile -- gestrichelte Linie über die volle Breite, dieselbe
   Signalfarbe wie die Kalender-Zeitachse (--cal-now-line-color, s.
   _calendar.css .cal-now-line) -- EINE Bedeutung, EINE Variable (P-5). */
.ds-dayplan-now-row { display: flex; align-items: center; gap: 0.625rem; padding: 0.1875rem 0; }
.ds-dayplan-now-row .ds-dayplan-row-time { color: var(--cal-now-line-color); font-weight: 600; }
.ds-dayplan-now-row-line { flex: 1; border-top: 2px dashed var(--cal-now-line-color); margin-left: 13px; }

.ds-dayplan-checklist { display: flex; flex-direction: column; margin-top: 0.25rem; }
.ds-dayplan-checklist-row {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  padding: 0.375rem 0;
  border-top: 1px solid var(--border);
}
.ds-dayplan-checklist-row:first-child { border-top: none; }
.ds-dayplan-checklist-row .todo-checkbox { margin-top: 0.0625rem; }
.ds-dayplan-checklist-row-body { min-width: 0; flex: 1; cursor: pointer; display: flex; flex-direction: column; gap: 0.0625rem; }

/* Schmalste Kachelbreite (Ticket-Vorgabe "in der schmalsten Kachelbreite die
   Achse weglassen und nur die Liste zeigen"): Punkt + Verbindungslinie weg,
   reine Zeit+Titel-Zeilen bleiben. 360px gemessen (Puppeteer, 1440px-Viewport,
   4-Spalten-Grid): span=1 rendert bei 320px Body-Breite, span=2 bei 658px --
   der Grenzwert liegt sicher dazwischen. */
@container dayplan (max-width: 360px) {
  .ds-dayplan-row-dot,
  .ds-dayplan-now-row-line { display: none; }
  .ds-dayplan-row-time { width: auto; margin-right: 0.125rem; }
}

/* ── Nachrichten-Feed-Kachel (Ticket 3.400.7) ────────────────────────────────
   <ds-news-feed-tile> (_widget-news-feed.js) – drei Darstellungen (Nur Titel/
   Kleine Bilder/Große Bilder) auf Basis der bestehenden .ds-dashboard-list*-
   Klassen, plus Host-Zeile (Audit-Auflage: Feed-Quelle IMMER sichtbar) und
   ein kompakter Darstellungs-Umschalter im Card-Body. */
.ds-news-feed-host {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-bottom: 0.5rem;
  font-size: 0.75rem;
  color: var(--text-tertiary);
}
.ds-news-feed-host svg { flex-shrink: 0; width: 12px; height: 12px; }

.ds-news-feed-view-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.125rem;
  padding: 0.1875rem;
  margin-bottom: 0.625rem;
  border-radius: var(--radius-pill);
  background: var(--bg-secondary);
}
.ds-news-feed-view-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.ds-news-feed-view-btn:hover { color: var(--text-primary); }
.ds-news-feed-view-btn.active { background: var(--bg-primary); color: var(--accent); box-shadow: var(--shadow-sm); }

/* Zeilen – erben Layout/Hover von .ds-dashboard-list-row, hier nur die
   News-Feed-spezifischen Ergänzungen (Thumb-Größe, "kein Link"-Zustand). */
.ds-news-feed-row--nolink { cursor: default; }
.ds-news-feed-row--nolink:hover { background: transparent; }

.ds-news-feed-list--compact { margin-top: 0.625rem; }

.ds-news-feed-thumb {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  background: var(--bg-secondary);
}

/* "Große Bilder" – erster Eintrag als Hero, Rest darunter als Titelliste
   (.ds-news-feed-list--compact). Bild-Höhe fest gedeckelt statt frei, damit
   ein sehr breites/hohes Quellbild die Kachel nicht sprengt (Stufe 1 deckelt
   den ganzen Body ohnehin bei 150px, s. modules/dashboard.md). */
.ds-news-feed-hero-wrap { display: flex; flex-direction: column; }
.ds-news-feed-hero {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  border-radius: var(--radius-md);
  overflow: hidden;
  color: inherit;
  text-decoration: none;
}
.ds-news-feed-hero--nolink { cursor: default; }
.ds-news-feed-hero-img {
  display: block;
  width: 100%;
  height: 128px;
  object-fit: cover;
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
}
.ds-news-feed-hero-body { display: flex; flex-direction: column; gap: 0.1875rem; }
.ds-news-feed-hero-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-primary);
  transition: color var(--transition);
}
.ds-news-feed-hero:hover .ds-news-feed-hero-title { color: var(--accent); }
.ds-news-feed-hero-summary {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ds-news-feed-add-btn { display: inline-flex; align-items: center; gap: 0.25rem; }
.ds-news-feed-add-btn svg { flex-shrink: 0; }

/* idEmptyHint im Katalog-Picker (Bootstrap-Fall – noch kein Feed vorhanden) */
.ds-news-feed-empty-hint-text { display: block; margin-bottom: 0.5rem; }

/* Mobile ≤900px: Raster fällt in eine Spalte (Spec 20260710, Abschnitt 3) */
@media (max-width: 900px) {
  .ds-dashboard-grid { grid-template-columns: 1fr; }
  .ds-dashboard-tile,
  .ds-dashboard-tile-loading { grid-column: span 1 !important; }
  /* Ticket 3.420 -- Rasterspalten-Fuehrungslinien sind ein Desktop-Hinweis
     fuer die 4-spaltige Breiten-Entscheidung; bei 1 Spalte gibt es nichts
     zu fuehren. Telefon bleibt dadurch VOELLIG unveraendert (AC7). */
  .ds-dashboard-grid-ruler { display: none; }
  /* Hoehenstufen wirken auf Mobile nicht (Ticket 3.383.3): einspaltig,
     Kacheln stehen untereinander wie vor der Funktion -- weder Zeilen-
     Spannweite noch feste/gedeckelte Body-Hoehe/Bildlaufleiste. Beide
     Body-Klassen (Stufe 2/3 `height` UND seit 3.383.5 Stufe 1 `max-height`)
     werden zurueckgesetzt. */
  .ds-dashboard-tile { grid-row: span 1 !important; }
  .ds-dashboard-tile-body-height-capped,
  .ds-dashboard-tile-body-maxheight-capped { height: auto !important; max-height: none !important; overflow-y: visible !important; }
  .ds-dashboard-quick-actions { width: 100%; }
  .ds-dashboard-quick-action { flex: 1 1 auto; justify-content: center; min-height: 44px; }
  /* Anpassen-Modus (Session D2): Wrapper übernimmt die Flex-Verteilung,
     die Pille darin füllt ihn zu 100% — das ×-Badge bleibt relativ positioniert. */
  .ds-dashboard-quick-action-wrap { flex: 1 1 auto; }
  .ds-dashboard-quick-action-wrap .ds-dashboard-quick-action { width: 100%; }
  .ds-dashboard-followup-row { min-height: 44px; }
  .ds-dashboard-list-row { min-height: 44px; }
  .ds-dashboard-list-row-icon { width: 32px; height: 32px; }
  /* Ticket 3.400.4: schmalere Legende-Labels auf Mobile, sonst wrapped der
     Anteilsbalken schnell auf viele Zeilen. */
  .ds-share-bar-legend-label { max-width: 7rem; }

  /* Anpassen-Modus: Drag-Griff bleibt auf Touch sichtbar (Pointer-Events sind
     Maus+Touch-vereint, touch-action:none verhindert Scroll-Hijack beim Ziehen) —
     nur mit größerem Touch-Target. Hoch/Runter-Pfeile bleiben zusätzlich als
     Fallback bestehen (nicht ersetzt), s. Spec 20260710 §3 +
     [[project_mobile_audit_2026-06-27]]. */
  .ds-dashboard-tile-drag-handle { display: inline-flex; min-width: 40px; min-height: 40px; }
  .ds-dashboard-tile-move-buttons { display: flex; }
  .ds-dashboard-edit-bar-actions { width: 100%; }
  .ds-dashboard-edit-bar-actions .btn { flex: 1 1 auto; justify-content: center; min-height: 44px; }
}
/* ── Buchhaltung (bookkeeping_periods / bookkeeping_statements) ─── */
/* Spec .claude/specs/20260717_bookkeeping_module.md Phase 2. Prefix ds-bookkeeping-*. */

/* Rechtsbündige, tabellarische Zahlen-Spalten (Einnahmen/Ausgaben/Saldo/Betrag) —
   generische Klasse fehlte bisher app-weit, hier bookkeeping-scoped angelegt statt
   Inline-style (CSS-Regel frontend.md „Klassen statt Inline-Styles"). */
.ds-bookkeeping-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ds-bookkeeping-amount--income  { color: var(--teal); }
.ds-bookkeeping-amount--expense { color: var(--coral); }

/* B48/C3 (Ticket 3.17.3): „davon Bank" / „davon bar/privat"-Unterzeile in der
   Übersichtskarte des Monats (`_renderSidebarOverview()`). Direktes Kind von
   `.invoicing-sidebar-meta-grid` — erbt dessen `display:flex;
   justify-content:space-between` (_invoicing.css), hier nur der
   Unterordnungs-Ausdruck: eingerückt + kleiner, damit die Zeile sich klar von
   der Haupt-Einnahmen/Ausgaben-Zeile absetzt statt gleichrangig zu wirken. */
.ds-bookkeeping-sidebar-source-row {
  padding-left: .875rem;
  font-size: .75rem;
}
.ds-bookkeeping-sidebar-source-label {
  color: var(--text-tertiary);
}

/* ── Monat-Detail: zweispaltiges Dokument-Layout (P2) ──────────────
   Reused strukturelle Klassen aus offers.js/invoices.js — bewusst KEIN
   eigener Klassensatz (modules/invoicing.md „Kein dokumenttyp-eigener
   CSS-Klassen-Satz"; hier modul-übergreifend dieselbe Begründung).
   Mobile-Sonderfall: Sidebar-Karten VOR die Positionsliste (Summen sind
   mobil die wichtigste Info, Spec 20260730 Abschnitt 3.4) — einzige
   Abweichung vom Rechnungs-Layout, per `order` gelöst statt DOM-Umbau. */
@media (max-width: 900px) {
  page-bookkeeping .invoicing-doc-layout-sidebar { order: -1; }

  /* 🔒 Bug gefunden bei B48/C2-Funktionstest (Ticket 3.17.2, Puppeteer,
     375px-Viewport): `_invoicing.css` blendet `.invoicing-doc-layout-main`
     auf Mobile komplett aus (`display:none`, Zeile ~1568) — der Kommentar
     dort sagt explizit warum: bei Rechnungen/Angeboten enthält die Spalte
     NUR das PDF-Iframe + den Status-Banner, beide ohnehin mobile-hidden,
     also bleibt die ganze Spalte leer und wird entfernt. Diese Annahme
     stimmt für Buchhaltung NICHT — hier liegt die komplette Positionsliste
     (Einstiegs-Button, Filter-Chips, Tabelle/Karten) in genau dieser
     Spalte. Ohne diese Override war die Positionsliste auf JEDEM Mobile-
     Gerät unsichtbar (0×0 Bounding-Box, per `getComputedStyle` verifiziert)
     — betraf nicht nur den neuen „+ Position erfassen"-Knopf, sondern die
     gesamte Tabelle/Karten-Ansicht seit P2 (2026-07-31). Override gescoped
     auf `page-bookkeeping` (höhere Spezifität, s. `order`-Regel darüber) —
     Rechnungen/Angebote bleiben unangetastet. */
  page-bookkeeping .invoicing-doc-layout-main { display: block; }
}

/* Sidebar-Karte „Übersicht": Fortschrittsbalken + klickbarer Vorschlags-Link */
.ds-bookkeeping-progress {
  display: flex;
  flex-direction: column;
  gap: .3125rem;
  margin-top: .75rem;
}
.ds-bookkeeping-progress-label {
  font-size: .75rem;
  color: var(--text-secondary);
}
.ds-bookkeeping-sidebar-link {
  appearance: none;
  -webkit-appearance: none;
  display: inline-block;
  margin-top: .5rem;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline;
}
.ds-bookkeeping-sidebar-link:hover { color: var(--accent-dark, var(--accent)); }
.ds-bookkeeping-sidebar-link--amber { color: var(--amber); }

/* ── Slide-In-Panel Aktionsleiste (analog .receipts-panel-actions, modul-eigen) ── */
.ds-bookkeeping-panel-actions {
  display: flex;
  gap: .5rem;
  margin-top: 1rem;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.ds-bookkeeping-panel-actions .btn { flex: 1; }

/* ── Monat-Detail: Kopfbereich ───────────────────────────────────── */
.ds-bookkeeping-detail-header {
  display: flex;
  flex-direction: column;
  gap: .625rem;
  margin-bottom: 1rem;
}
/* Ticket 3.154.4 (T4): Breadcrumb ersetzt Titel-Zeile + freistehenden „← Zurück"-
   Knopf (`.ds-bookkeeping-detail-title` entfallen — Breadcrumb trägt den
   Monatsnamen jetzt über `.breadcrumb-current`, s. layout.css). Eigene, kleinere
   `margin-bottom` statt der App-weiten 1.5rem (`.breadcrumb` layout.css) — der
   Abstand zur Status-Actions-Zeile darunter kommt bereits vom `gap` des
   umgebenden `.ds-bookkeeping-detail-header`-Flex-Stacks. */
.ds-bookkeeping-detail-breadcrumb { margin-bottom: 0; }

.ds-bookkeeping-detail-title-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
}
/* Seit 2026-07-31: Status-Buttons + „Mehr" bilden zusammen EIN rechtsbündiges Cluster
   in der Titel-Zeile (Domenico-Vorgabe — vorher zwei getrennte Zeilen). Der
   margin-left:auto-Push sitzt jetzt auf der Status-Actions-Gruppe (erstes Element
   im Cluster), „Mehr" folgt unmittelbar danach und landet dadurch automatisch ganz
   rechts außen. */
.ds-bookkeeping-status-actions {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  margin-left: auto;
}

/* „Mehr"-Button (P2, Spec 20260730 Abschnitt 3.2) — ersetzt die feste
   DATEV/ZIP-Button-Zeile, die vorher hier stand (.ds-bookkeeping-export-actions,
   entfernt). Sitzt seit 2026-07-31 direkt nach der Status-Actions-Gruppe im selben
   rechtsbündigen Cluster (kein eigener margin-left:auto mehr nötig). */
.ds-bookkeeping-more-btn { flex-shrink: 0; }

/* Generischer klickbarer Table-Row-Hover (Monatsliste + Positions-Tabelle) */
.ds-bookkeeping-clickable-row { cursor: pointer; }
.ds-bookkeeping-clickable-row:hover { background: var(--bg-secondary); }

/* Skeleton-Stack (Detail-Ladezustand) */
.ds-bookkeeping-skeleton-stack {
  display: flex;
  flex-direction: column;
  gap: .625rem;
}

/* ── Konten-Bereich ───────────────────────────────────────────────── */
.ds-bookkeeping-account-iban {
  color: var(--text-secondary);
  font-size: .8125rem;
  font-variant-numeric: tabular-nums;
}
.ds-bookkeeping-hint {
  color: var(--text-secondary);
  font-size: .875rem;
  margin: 0;
}

/* Sidebar-Karte „Konten" (P2, verdichtet — Spec 20260730 Abschnitt 3.3
   Karte 2): Icon-only-Aktionen statt Text-Buttons, ein Konto pro Zeile. */
.ds-bookkeeping-sidebar-accounts {
  display: flex;
  flex-direction: column;
  gap: .625rem;
  margin-bottom: .75rem;
}
.ds-bookkeeping-sidebar-account {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--border);
}
.ds-bookkeeping-sidebar-account:last-child { border-bottom: none; }
.ds-bookkeeping-sidebar-account-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .0625rem;
}
.ds-bookkeeping-sidebar-account-name {
  font-weight: 600;
  font-size: .875rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-bookkeeping-sidebar-account-actions {
  display: flex;
  gap: .125rem;
  flex-shrink: 0;
}
/* „Kasse"-Badge einer Kassen-Konto-Zeile (B48/C2, Ticket 3.17.2): der
   umschließende Flex-Column-Container (.ds-bookkeeping-sidebar-account-info)
   hat keine align-items-Regel -> Kinder strecken sich standardmäßig auf die
   volle Breite. Ein .badge würde dadurch zu einem breiten Rechteck statt
   einer schmalen Pille — align-self korrigiert nur dieses eine Element. */
.ds-bookkeeping-sidebar-account-type-badge {
  align-self: flex-start;
  margin-top: .0625rem;
}
.ds-bookkeeping-sidebar-full-btn { width: 100%; justify-content: center; }
.ds-bookkeeping-sidebar-full-btn + .ds-bookkeeping-sidebar-full-btn { margin-top: .5rem; }

/* PDF-Backup-Status je Konto — teal Erfolgs-Hinweis "Backup vorhanden" */
.ds-bookkeeping-pdf-status {
  display: flex;
  align-items: center;
  gap: .3125rem;
  margin-top: .25rem;
  color: var(--teal);
  font-size: .8125rem;
  font-weight: 500;
}

/* Sidebar-Karte „Dokumente" (Ticket 3.154.10, Punkt 4, E8) — die führende
   Kennzahl „N Dokumente" (Belege + Rechnungen zusammen) bekommt eine eigene
   Zeile mit einer kleineren Aufschlüsselungs-Zeile darunter.
   🔒 Ticket 3.154.10-Nachbesserung (2026-08-09): die Karte zeigt seither nur
   noch DIESE eine Kennzahl (der Eingangs-Zähler ist in einen Panel-Reiter
   gewandert, s. `_openReceiptsPanel()`) — der frühere `.invoicing-sidebar-
   meta-grid`-Wrapper (2 Spalten für Kennzahl + „Im Eingang") ist entfallen,
   dieser Block steht jetzt direkt im Fieldset und braucht seinen eigenen
   Abstand zu den Buttons darunter. */
.ds-bookkeeping-sidebar-doc-count {
  display: flex;
  flex-direction: column;
  gap: .125rem;
  min-width: 0;
  margin-bottom: .75rem;
}
.ds-bookkeeping-sidebar-doc-count-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .5rem;
}
.ds-bookkeeping-sidebar-doc-count-breakdown {
  font-size: .75rem;
  color: var(--text-tertiary);
}

/* Sidebar-Karte „Steuerberater-Link" (Ticket 3.326.3) — WeTransfer-artiger,
   token-geschützter Download-Link als Alternative zum AES-ZIP-Anhang.
   Wiederverwendet `.ds-bookkeeping-sidebar-doc-count*` für die Kennzahlen-
   Zeilen (Erstellt/Gültig bis/Bestätigt/Abrufe) — nur der Status-Kopf
   (Badge + Passwort-Hinweis) und der Wrapper selbst sind neu. */
.ds-bookkeeping-sharelink {
  display: flex;
  flex-direction: column;
  gap: .625rem;
}
.ds-bookkeeping-sharelink-status-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  flex-wrap: wrap;
}
.ds-bookkeeping-sharelink-pw-hint {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .75rem;
  color: var(--text-secondary);
}
.ds-bookkeeping-sharelink-pw-hint--none { color: var(--text-tertiary); }

/* Sidebar-Karte „Rechnungen ohne Zahlungsweg" (Ticket 3.153, Phase 1) — je
   Zeile Rechnungsnummer/Betrag oben, Kunde/Datum darunter, Zahlungsweg-Select
   auf eigener Zeile (im schmalen Sidebar-Kontext hat ein Select neben dem Text
   nicht genug Platz für Labels wie „Privat verauslagt"). */
.ds-bookkeeping-nochannel-list {
  display: flex;
  flex-direction: column;
  gap: .625rem;
  margin-top: .5rem;
}
.ds-bookkeeping-nochannel-item {
  display: flex;
  flex-direction: column;
  gap: .1875rem;
  padding-bottom: .625rem;
  border-bottom: 1px solid var(--border);
}
.ds-bookkeeping-nochannel-item:last-child { border-bottom: none; padding-bottom: 0; }
.ds-bookkeeping-nochannel-item-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: .5rem;
}
.ds-bookkeeping-nochannel-item-number {
  font-weight: 600;
  font-size: .875rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-bookkeeping-nochannel-item-amount {
  font-variant-numeric: tabular-nums;
  font-size: .875rem;
  white-space: nowrap;
  flex-shrink: 0;
}
.ds-bookkeeping-nochannel-item-meta {
  color: var(--text-secondary);
  font-size: .75rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-bookkeeping-nochannel-item-select { margin-top: .1875rem; width: 100%; }

/* ── Positions-Tabelle ────────────────────────────────────────────── */

/* Zustandsspalte (P2, Spec 20260730 Abschnitt 2): 4 Zustände — offen /
   Vorschlag liegt vor / zugewiesen / abgehakt ohne Beleg. Icon + Kurzlabel
   gestapelt (Desktop-Tabellenzelle); `--inline` Modifier für die Mobile-Karte
   (Icon neben Datum/Betrag, kein Label — Platzgrund). */
.ds-bookkeeping-tx-state-col {
  width: 4.5rem;
  text-align: center;
}
.ds-bookkeeping-tx-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .125rem;
}
.ds-bookkeeping-tx-state--inline {
  flex-direction: row;
  align-items: center;
}
.ds-bookkeeping-tx-state-icon { display: flex; }
.ds-bookkeeping-tx-state-label {
  font-size: .625rem;
  text-transform: uppercase;
  letter-spacing: .02em;
  color: var(--text-tertiary);
  white-space: nowrap;
}
.ds-bookkeeping-tx-state--suggested .ds-bookkeeping-tx-state-label { color: var(--amber); }
.ds-bookkeeping-tx-suggested-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--amber);
}
.ds-bookkeeping-tx-state--assigned .ds-bookkeeping-tx-state-icon { color: var(--teal); }
.ds-bookkeeping-tx-state--assigned .ds-bookkeeping-tx-state-label { color: var(--teal); }
/* „Abgehakt ohne Beleg" — derselbe Haken wie „zugewiesen", aber gedämpft
   (opacity) + neutrales Label, damit beide Zustände optisch unterscheidbar
   bleiben (Spec-Pflicht: keine Verwechslung mit echter Belegzuweisung). */
.ds-bookkeeping-tx-state--settled .ds-bookkeeping-tx-state-icon { color: var(--teal); opacity: .5; }
.ds-bookkeeping-tx-unmatched-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1.5px solid var(--border);
}
.ds-bookkeeping-tx-remark {
  color: var(--text-tertiary);
  font-size: .8125rem;
}

/* Kennzeichen manueller Positionen in der Liste (B48/C2, Ticket 3.17.2,
   Spec 20260730_bookkeeping_cash_expenses.md Abschnitt 3: „Bar"/„Privat" o.ä.
   vor Verwendungszweck/Zweck-Zeile). Reuse .badge/.badge-neutral aus
   _core.css — nur der Abstand zum folgenden Text ist neu. */
.ds-bookkeeping-tx-manual-badge { margin-right: .375rem; }

/* Einstiegs-Zeile „+ Position erfassen" über der Positionsliste (B48/C2,
   Domenico-Vorgabe 11.08.: Einstieg gehört in die Liste, nicht nur in die
   Konten-Karte). Immer sichtbar, auch bei 0 Positionen — daher eigene Zeile
   statt Teil der (bedingt gerenderten) Filter-Chips. */
.ds-bookkeeping-tx-actions {
  display: flex;
  justify-content: flex-end;
  margin-bottom: .75rem;
}

/* Filter-Chips über der Positionsliste (P2) — reuse .tab-filter, nur Abstand. */
.ds-bookkeeping-tx-filter { margin-bottom: .75rem; }

/* Mobile Positions-Karten */
.ds-bookkeeping-tx-card {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  padding: .75rem 1rem;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.ds-bookkeeping-tx-card:last-child { border-bottom: none; }
.ds-bookkeeping-tx-card:active { background: var(--bg-secondary); }
.ds-bookkeeping-tx-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
}
.ds-bookkeeping-tx-card-top-left {
  display: flex;
  align-items: center;
  gap: .375rem;
  min-width: 0;
}
.ds-bookkeeping-tx-card-date {
  font-size: .8125rem;
  color: var(--text-tertiary);
}
.ds-bookkeeping-tx-card-amount {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.ds-bookkeeping-tx-card-main {
  font-size: .9375rem;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-bookkeeping-tx-card-sub {
  font-size: .8125rem;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Matching-Panel (Phase 3) ─────────────────────────────────────── */

/* Positions-Kopf (read-only): Buchungsdatum/Betrag/Verwendungszweck/Begünstigter */
.ds-bookkeeping-tx-head {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding-bottom: 1rem;
  margin-bottom: 1rem;
  border-bottom: 1px solid var(--border);
}
.ds-bookkeeping-tx-head-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  font-size: .8125rem;
}
.ds-bookkeeping-tx-head-label { color: var(--text-tertiary); flex-shrink: 0; }
.ds-bookkeeping-tx-head-value {
  font-weight: 500;
  text-align: right;
  overflow-wrap: anywhere;
}
.ds-bookkeeping-tx-head-amount {
  font-size: 1.0625rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Ignoriert-Toggle-Zeile (iOS-Style-Toggle, feedback_ui_binary_toggle) */
.ds-bookkeeping-tx-panel-row {
  display: flex;
  align-items: center;
  gap: .625rem;
  margin: .875rem 0;
}
.ds-bookkeeping-tx-panel-row-label {
  font-size: .875rem;
  color: var(--text-secondary);
}

.ds-bookkeeping-tx-panel-actions {
  display: flex;
  gap: .5rem;
  margin: .5rem 0 1.25rem;
}
.ds-bookkeeping-tx-panel-actions .btn { flex: 1; }

.ds-bookkeeping-tx-match-section {
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.ds-bookkeeping-tx-match-heading {
  font-size: .8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--text-tertiary);
  margin: 0 0 .75rem;
}

/* Zugewiesener Beleg — Karte */
.ds-bookkeeping-match-card {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
  padding: .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
}
.ds-bookkeeping-match-card-icon { color: var(--teal); flex-shrink: 0; margin-top: .125rem; }
.ds-bookkeeping-match-card-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .125rem;
}
.ds-bookkeeping-match-card-vendor { font-weight: 600; }
.ds-bookkeeping-match-card-meta { font-size: .8125rem; color: var(--text-secondary); }

/* Beleg-Picker-Liste (Relevanz-sortiert) */
.ds-bookkeeping-picker-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-height: 22rem;
  overflow-y: auto;
  margin: 0 0 1rem;
}
.ds-bookkeeping-picker-item {
  appearance: none;
  -webkit-appearance: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  width: 100%;
  text-align: left;
  padding: .625rem .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  cursor: pointer;
  font: inherit;
  color: inherit;
  transition: background .12s ease, border-color .12s ease;
}
.ds-bookkeeping-picker-item:hover,
.ds-bookkeeping-picker-item:focus-visible {
  background: var(--bg-secondary);
  border-color: var(--accent);
  outline: none;
}
.ds-bookkeeping-picker-item--best {
  border-color: var(--teal);
  background: var(--teal-light);
}
.ds-bookkeeping-picker-item-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .125rem;
}
.ds-bookkeeping-picker-item-vendor {
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: .375rem;
  min-width: 0;
}
.ds-bookkeeping-picker-item-vendor-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.ds-bookkeeping-picker-badge { flex-shrink: 0; font-size: .625rem; padding: .0625rem .375rem; }
.ds-bookkeeping-picker-item-sub { font-size: .75rem; color: var(--text-tertiary); }
.ds-bookkeeping-picker-item-amount {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.ds-bookkeeping-picker-empty {
  padding: 1.5rem 0;
  text-align: center;
  color: var(--text-secondary);
  font-size: .875rem;
}

/* ── Split-Screen (Phase 4): Beleg-Liste + PDF/Bild-Vorschau ─────────
   P9 (design-system.md „PDF-Vorschau / authenticated File-Streams via
   Blob-URL"): iframe/img bekommen eine Blob-URL, NIE den API-Pfad direkt
   (Bearer-Auth würde am iframe-src fehlen → 401). */
.ds-bookkeeping-split {
  display: grid;
  grid-template-columns: 300px 1fr;
  gap: 1rem;
  align-items: start;
}
.ds-bookkeeping-split-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-height: 34rem;
  overflow-y: auto;
  padding-right: .25rem;
}
.ds-bookkeeping-split-item {
  appearance: none;
  -webkit-appearance: none;
  display: flex;
  align-items: center;
  gap: .625rem;
  width: 100%;
  text-align: left;
  padding: .5rem .625rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  cursor: pointer;
  font: inherit;
  color: inherit;
  transition: background .12s ease, border-color .12s ease;
}
.ds-bookkeeping-split-item:hover,
.ds-bookkeeping-split-item:focus-visible {
  background: var(--bg-secondary);
  border-color: var(--accent);
  outline: none;
}
.ds-bookkeeping-split-item--active {
  border-color: var(--accent);
  background: var(--accent-light);
}
.ds-bookkeeping-split-item-icon {
  flex-shrink: 0;
  color: var(--text-tertiary);
  display: flex;
}
.ds-bookkeeping-split-item--active .ds-bookkeeping-split-item-icon { color: var(--accent); }
.ds-bookkeeping-split-item-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .0625rem;
}
.ds-bookkeeping-split-item-vendor {
  font-weight: 600;
  font-size: .875rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-bookkeeping-split-item-sub { font-size: .75rem; color: var(--text-tertiary); }
.ds-bookkeeping-split-item-amount {
  font-weight: 600;
  font-size: .8125rem;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
/* Ticket 3.154.10 (Punkt 4, E8): Gruppen-Überschrift „Belege"/„Rechnungen"
   innerhalb der kombinierten Dokumente-Liste (Muster wie .ds-fieldset-legend,
   ohne dessen Padding — sitzt hier direkt im Flex-Column der Liste). */
.ds-bookkeeping-split-group-title {
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  margin: .375rem 0 -.125rem;
}
.ds-bookkeeping-split-group-title:first-child { margin-top: 0; }
/* Hinweis „N Dokumente zugewiesen, aber M werden geschickt" (Punkt 4) — reines
   `.ds-info-box` reicht optisch, dieser Zusatz sorgt nur für Abstand zur
   Liste darunter (Muster `.ds-bookkeeping-txdetail-suggestion`). */
.ds-bookkeeping-scope-hint { margin-bottom: 1rem; }
.ds-bookkeeping-split-preview {
  height: 34rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  overflow: hidden;
  position: relative;
}
.ds-bookkeeping-split-frame {
  width: 100%;
  height: 100%;
  border: none;
  display: block;
}
.ds-bookkeeping-split-frame--img { object-fit: contain; background: var(--bg-primary); }
.ds-bookkeeping-split-preview-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .625rem;
  padding: 1.5rem;
  text-align: center;
  color: var(--text-tertiary);
}
.ds-bookkeeping-split-preview-empty svg { width: 40px; height: 40px; opacity: .35; }
.ds-bookkeeping-split-preview-empty p { font-size: .8125rem; max-width: 16rem; margin: 0; }

/* „Dokumente"-Slide-In-Panel (`_openReceiptsPanel()`, Ticket 3.154.10-
   Nachbesserung 2026-08-09) — Reiter-Wrapper. `.ds-bookkeeping-doc-panel` ist
   der direkte Panel-Body-Kind (Titel: „Dokumente — {Monat}") und enthält die
   Reiterleiste (reuse `.tab-filter`/`.tab-filter-btn`, kein neues Muster),
   optional den Scope-Hinweis, dann `.ds-bookkeeping-split`. Reine Flex-Column
   — auf Mobile ohne Zusatzwirkung (natürlicher Block-Fluss), auf Desktop
   trägt sie die Voll-Höhen-Logik weiter unten. */
.ds-bookkeeping-doc-panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* Reiterleiste über der Liste — reuse .tab-filter, nur Abstand (Muster
   .ds-bookkeeping-tx-filter über der Positionsliste). */
.ds-bookkeeping-doc-tabs { margin-bottom: .75rem; flex-shrink: 0; }

/* Volle Panel-Höhe (Ticket 3.154.10-Nachbesserung, Domenico-Feedback Punkt 3: „Fenster
   sollte links und rechts bis nach unten gehen"). Muster 1:1 übernommen von
   `.ds-bookkeeping-editor-split` weiter unten (Ticket 3.154.1-Nachbesserung, P-5
   — keine zweite Erfindung derselben Technik): `.ds-cal-panel-body` ist der
   scrollende Flex-Container der Panel-Komponente (`_calendar.css`, `flex:1;
   overflow-y:auto`) mit dadurch DEFINIERTER Höhe — das Padding wandert auf den
   `.ds-bookkeeping-doc-panel`-Wrapper, der per `height:100%` genau diese Höhe
   ausfüllt und selbst als Flex-Column Reiterleiste/Hinweis (fixe Höhe) UND
   `.ds-bookkeeping-split` (füllt den Rest, `flex:1;min-height:0`) trägt.
   🔒 Seit der Reiter-Einführung ist `.ds-bookkeeping-split` NICHT mehr direktes
   Kind von `.ds-cal-panel-body` (die Reiterleiste steht davor) — der
   `:has(> …)`-Selektor scoped deshalb auf `.ds-bookkeeping-doc-panel`, nicht
   mehr auf `.ds-bookkeeping-split` selbst. Die Positions-Detailseite
   (`.ds-bookkeeping-txdetail-grid-right .ds-bookkeeping-split`) und das
   Beleg-Bearbeiten-Panel (eigene Klasse `.ds-bookkeeping-editor-split`) nutzen
   dieselbe `.ds-bookkeeping-split*`-Klassenfamilie an anderer DOM-Stelle und
   bleiben unberührt.
   Strikt hinter min-width:901px (Komplement zu max-width:900px, wie die übrigen
   Full-Height-Overrides dieser Datei) — auf schmalen Screens bleibt die feste,
   kleinere Vorschau-Höhe unangetastet (volle Panel-Höhe ergäbe dort wenig Sinn,
   das Panel ist mobil ohnehin 100vw/100vh). */
@media (min-width: 901px) {
  .ds-cal-panel-body:has(> .ds-bookkeeping-doc-panel) {
    padding: 0;
  }
  .ds-cal-panel-body > .ds-bookkeeping-doc-panel {
    height: 100%;
    padding: .875rem 1rem;
  }
  .ds-cal-panel-body > .ds-bookkeeping-doc-panel .ds-bookkeeping-split {
    flex: 1;
    min-height: 0;
    align-items: stretch;
  }
  .ds-cal-panel-body > .ds-bookkeeping-doc-panel .ds-bookkeeping-split-list {
    max-height: none;
  }
  .ds-cal-panel-body > .ds-bookkeeping-doc-panel .ds-bookkeeping-split-preview {
    height: auto;
  }
}

/* ── Positions-Detailseite (Phase P3, Spec 20260730 Abschnitt 4) ─────
   Eigene Seite (_view='txDetail'), kein Panel. Karte „Belege" reused die
   Split-Screen-Klassen oben (.ds-bookkeeping-split*) 1:1 (Spec 4.2 „gleiches
   Raster wie die heutige Split-Ansicht") — nur die Kandidaten-ZEILE ist neu
   (Checkbox + klickbarer Vorschau-Bereich nebeneinander; .ds-bookkeeping-
   split-item bleibt unveraendert ein reiner <button> ohne Checkbox fuer das
   bestehende „Belege ansehen"-Panel, P2). */

/* P2-Feedback: Position (1/3) neben Belege (2/3) Desktop, gestapelt Mobile;
   Titel-Zeile ersetzt durch Breadcrumb (.breadcrumb* aus layout.css, reused). */
.ds-bookkeeping-txdetail-breadcrumb { margin-bottom: 1rem; }
.ds-bookkeeping-txdetail-grid {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 1rem;
  align-items: start;
}
.ds-bookkeeping-txdetail-grid-left,
.ds-bookkeeping-txdetail-grid-right { min-width: 0; }

/* Ticket 3.154.11 (Desktop only — Domenico: linke Card „Position" in ihrer
   vollsten Ausprägung ist der Maßstab, die rechte Belege-Card übernimmt
   IMMER deren Höhe, nie umgekehrt — auch wenn die rechte Kandidatenliste von
   sich aus mehr Platz haette, z.B. bei vielen Belegen im Eingang). Auf
   schmalen Bildschirmen stapeln sich beide Spalten (Mobile-Override weiter
   unten, grid-template-columns:1fr) — dort ergibt eine erzwungene
   Gleichhoehe keinen Sinn und bleibt unangetastet, deshalb strikt hinter
   min-width:901px (Komplement zu max-width:900px).

   🔒 Bewusst NICHT `align-items:stretch` — das gleicht nur auf die Hoehe der
   NATUERLICH hoeheren Seite an (= Maximum beider). Hat die Belege-Karte von
   sich aus mehr Inhalt (z.B. ein voller Eingang mit vielen unbearbeiteten
   Belegen — ein durchaus realistischer Alltagsfall, nicht nur ein
   Test-Datensatz), waere WEITERHIN rechts die groessere Seite und links
   wuerde nach unten gezogen — genau umgekehrt zu Domenicos Vorgabe „linke
   Card ist IMMER der Massstab". Empirisch mit 16 Kandidatenzeilen geprueft:
   `align-items:stretch` liess die Differenz nahezu unveraendert (rechts blieb
   die groessere Seite).

   Stattdessen: das native CSS-Grid-Verhalten fuer absolut positionierte
   Grid-Items. Ein Kind mit `position:absolute` UND einer Grid-Platzierung
   (`grid-column`/`grid-row`) verwendet die dafuer bestimmte Grid-Area als
   Containing Block (Breite + Hoehe), traegt dabei selbst aber NICHTS zur
   Spur-Groessenberechnung des Grids bei (CSS Grid Spec §5.1 — Absolutely-
   Positioned Grid Items). Die rechte Spalte nimmt an der Hoehen-Berechnung
   der Zeile also gar nicht erst teil; die Zeilenhoehe ergibt sich rein aus
   LINKS (dem einzigen verbleibenden Grid-Item im normalen Fluss), und
   RECHTS wird per `inset:0` exakt auf die dadurch entstandene Grid-Area
   (Spalte 2, gleiche Breite/Position wie zuvor) gestreckt — unabhaengig
   davon, wie viel eigener Inhalt (Kandidatenzeilen) darin steckt. Reicht der
   Inhalt nicht in die so vorgegebene Hoehe, scrollt er intern (die drei
   Regeln danach heben dafuer die feste 34rem-Hoehe von
   .ds-bookkeeping-split-preview/-list auf — NUR innerhalb dieser Spalte,
   scoped, damit das „Alle Belege ansehen"-Panel und die Editor-Panel-
   Dokumentspalte, die dieselben Klassen andernorts mit Absicht auf 34rem
   fixieren, unveraendert bleiben).

   `position:relative` auf dem Grid-Container ist Pflicht: nur dann nutzt ein
   absolut positioniertes GRID-Kind die Grid-Area als Containing Block: ist
   der Grid-Container `position:static`, faellt ein absolut positioniertes
   Kind auf den naechsten positionierten VORFAHREN ausserhalb des Grids
   zurueck (CSS Positioned Layout, normales Verhalten) — die Grid-Area-
   Sonderregel des Grid-Spec greift nur bei einem positionierten Container. */
@media (min-width: 901px) {
  .ds-bookkeeping-txdetail-grid { position: relative; }
  .ds-bookkeeping-txdetail-grid-left {
    grid-column: 1;
    grid-row: 1;
  }
  .ds-bookkeeping-txdetail-grid-right {
    grid-column: 2;
    grid-row: 1;
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  .ds-bookkeeping-txdetail-grid-right > .ds-fieldset {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  .ds-bookkeeping-txdetail-grid-right .ds-bookkeeping-split {
    flex: 1;
    min-height: 0;
    align-items: stretch;
  }
  .ds-bookkeeping-txdetail-grid-right .ds-bookkeeping-split-list {
    max-height: none;
  }
  .ds-bookkeeping-txdetail-grid-right .ds-bookkeeping-split-preview {
    height: auto;
  }
}

.ds-bookkeeping-txdetail-settled-row {
  display: flex;
  align-items: center;
  gap: .625rem;
  margin-bottom: .75rem;
}
.ds-bookkeeping-txdetail-settled-label {
  font-size: .9375rem;
  font-weight: 500;
}
/* Ticket 3.17.8: „Position bearbeiten"-Knopf (nur bei entry_source=manual) im
   selben Flex-Row wie der Zugewiesen-Toggle — rechtsbündig ans Zeilenende. */
.ds-bookkeeping-txdetail-edit-btn {
  margin-left: auto;
  flex-shrink: 0;
}

.ds-bookkeeping-txdetail-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .75rem 1.5rem;
  margin-bottom: 1rem;
}
.ds-bookkeeping-txdetail-field-label {
  display: block;
  font-size: .75rem;
  color: var(--text-tertiary);
  margin-bottom: .125rem;
}
.ds-bookkeeping-txdetail-field-value {
  font-size: .9375rem;
  overflow-wrap: anywhere;
}

.ds-bookkeeping-txdetail-suggestion { margin-bottom: 1rem; }
.ds-bookkeeping-txdetail-suggestion-actions {
  display: flex;
  gap: .5rem;
  flex-shrink: 0;
}

/* Betragsdifferenz zum Bankbetrag (Phase 7, Spec 20260802_bookkeeping_postings.md,
   E3) — nur gerendert, wenn `_txDetailAmountDifference()` (bookkeeping.js) eine
   Differenz > 1 Cent zwischen Bankbetrag und bestätigt zugewiesenen Dokumenten
   liefert. Titel-Stil bewusst identisch zu .ds-fieldset-legend (uppercase,
   text-tertiary) — signalisiert „Unterabschnitt", ohne ein eigenes <fieldset>
   zu brauchen (der Block liegt bereits innerhalb des Position-Fieldsets). */
.ds-bookkeeping-txdetail-diff {
  border-top: 1px solid var(--border);
  padding-top: .875rem;
  margin: .25rem 0 1rem;
}
.ds-bookkeeping-txdetail-diff-title {
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  margin-bottom: .5rem;
}
.ds-bookkeeping-txdetail-diff-summary {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  margin-bottom: .75rem;
}
.ds-bookkeeping-txdetail-diff-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  font-size: .875rem;
}
.ds-bookkeeping-txdetail-diff-row--total {
  font-weight: 600;
  padding-top: .375rem;
  margin-top: .125rem;
  border-top: 1px dashed var(--border);
}
.ds-bookkeeping-txdetail-diff-label { color: var(--text-secondary); }
.ds-bookkeeping-txdetail-diff-row--total .ds-bookkeeping-txdetail-diff-label { color: var(--text-primary); }
.ds-bookkeeping-txdetail-diff-value {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex-shrink: 0;
}

.ds-bookkeeping-txdetail-cand-toolbar {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin-bottom: .75rem;
}
/* Suchfeld + Upload-Button nebeneinander (P4, Spec 20260730 Abschnitt 4.2/5.1
   — war in P3 bewusst offen gelassen). Upload-Optionen/-Fortschritt kommen
   vom geteilten Erfassungs-Modul, Klassen dafür liegen in _receipts.css
   (.receipts-add-option* / .receipts-capture-progress*, P-5, ein Klassensatz —
   🔒 Leerzeichen vor dem Schraegstrich ist hier Pflicht: Stern direkt gefolgt
   von Schraegstrich beendet einen CSS-Kommentar vorzeitig, und der GESAMTE
   nachfolgende Regelblock bis zum naechsten geschweiften Klammer-Auf wird vom
   CSS-Parser als kaputte Selector-Liste verworfen — genau das war hier der
   Fall (display:flex auf dieser Zeile landete nie im CSSOM, gefunden per
   Live-Verifikation 2026-08-07).
   Ticket 3.154.3/T3 (korrigiert 2026-08-07, Domenico-Feedback): Suchfeld
   nimmt die REST-Breite der Zeile ein (`flex:1 1 14rem`, kein `max-width`
   mehr) — der „Hochladen"-Button steht dadurch immer ganz rechts, statt
   mitten in der Zeile mit Leerraum daneben zu haengen. `flex-wrap` erlaubt
   der Zeile auf schmalen Bildschirmen weiterhin umzubrechen statt das
   Suchfeld auf 0 zu quetschen. */
.ds-bookkeeping-txdetail-cand-toolbar-row {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  align-items: center;
}
.ds-bookkeeping-txdetail-cand-toolbar-row .input { flex: 1 1 14rem; min-width: 0; }
.ds-bookkeeping-txdetail-cand-toolbar-row .btn { flex-shrink: 0; }

/* Kandidaten-Zeile: Checkbox + klickbarer Vorschau-Bereich als Geschwister
   (kein Button-in-Button). Innere Icon/Vendor/Sub/Amount-Klassen kommen aus
   der .ds-bookkeeping-split-item-*-Familie oben (P-5, keine Dopplung). */
.ds-bookkeeping-txdetail-cand-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem .625rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  transition: background .12s ease, border-color .12s ease;
}
.ds-bookkeeping-txdetail-cand-row--active {
  border-color: var(--accent);
  background: var(--accent-light);
}
.ds-bookkeeping-txdetail-cand-row--assigned { border-left: 3px solid var(--teal); }
/* Rechnungen-Reiter (dieser Task): ganze Zeile ist ein <label>, kein
   Checkbox+Button-Geschwister-Paar wie bei Belegen (keine zweite Aktion
   in der Zeile) — braucht deshalb einen eigenen Cursor+Hover-Hinweis. */
.ds-bookkeeping-txdetail-cand-row--label { cursor: pointer; }
.ds-bookkeeping-txdetail-cand-row--label:hover { background: var(--bg-secondary); }
.ds-bookkeeping-txdetail-cand-check {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}
.ds-bookkeeping-txdetail-cand-btn {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .375rem 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

/* Ticket 3.154.12: „Speichern (Zurück)"/„Speichern (Weiter)" — zwei Knöpfe
   statt eines einzelnen. `justify-content:space-between` verteilt die zwei
   Knöpfe an die Ränder (Reihenfolge im Markup ist bereits links=sekundär,
   rechts=primär); fehlt der linke (erste Position bzw. nur eine Position im
   Filter), übernimmt `.ds-bookkeeping-txdetail-save-solo` (margin-left:auto)
   dieselbe Rechtsbündigkeit, die vorher `justify-content:flex-end` allein
   leistete. `flex-wrap` erlaubt den Umbruch auf schmalen Bildschirmen
   (Auftrag Punkt „Mobile (390px): die zwei Knöpfe dürfen umbrechen"). */
.ds-bookkeeping-txdetail-savebar {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .75rem;
  margin-top: 1rem;
}
.ds-bookkeeping-txdetail-savebar .btn { min-width: 9rem; }
.ds-bookkeeping-txdetail-save-solo { margin-left: auto; }

/* Drei Navigations-Links unter dem Savebar (Ticket 3.154.12): „‹ Zurück ·
   Zur Liste · Weiter ›". Immer DREI Flex-Kinder im DOM — fehlt ein Link
   (erste/letzte Position), steht an seiner Stelle ein unsichtbarer
   `-spacer` (kein „Zurück"/"Weiter"-Element, s. Verifikations-Pflicht „nicht
   im DOM" — der Spacer ist ein reines Layout-Element, kein Navigations-Link).
   `flex:1 1 0` auf allen drei hält „Zur Liste" IMMER exakt mittig, unabhängig
   davon ob links/rechts ein echter Link oder nur der Spacer steht — robuster
   als `justify-content:space-between` mit wechselnder Kindzahl. Bleibt auf
   Mobile (390px) bewusst in einer Zeile (kein flex-wrap) — drei kurze Labels
   passen, Auftrag Punkt „die drei Links bleiben in einer Zeile lesbar". */
.ds-bookkeeping-txdetail-navlinks {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-top: .625rem;
}
.ds-bookkeeping-txdetail-navlink,
.ds-bookkeeping-txdetail-navlink-spacer {
  flex: 1 1 0;
  min-width: 0;
}
.ds-bookkeeping-txdetail-navlink {
  appearance: none;
  -webkit-appearance: none;
  padding: .25rem 0;
  border: none;
  background: none;
  font: inherit;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--text-secondary);
  cursor: pointer;
  text-decoration: none;
}
.ds-bookkeeping-txdetail-navlink:hover { color: var(--text-primary); }
.ds-bookkeeping-txdetail-navlink:disabled {
  color: var(--text-tertiary);
  text-decoration: none;
  cursor: not-allowed;
}
.ds-bookkeeping-txdetail-navlink--prev { text-align: left; }
.ds-bookkeeping-txdetail-navlink--list { text-align: center; }
.ds-bookkeeping-txdetail-navlink--next { text-align: right; }

/* C5 (Ticket 3.17.?, Spec 20260730_bookkeeping_cash_expenses.md Abschnitt
   8/C5): Änderungsverlauf einer manuellen Position — `<details>`-Aufklapper
   am Ende der Position-Karte. `.receipts-history-list`/`-row`/`-row-time`
   (_receipts.css) werden 1:1 reused (identisches Eintragsformat, P-5); nur
   der Aufklapper-Wrapper + die Summary-Optik sind hier neu, weil
   `_receipt-edit-form.js::_renderHistory()` sie per Inline-Style statt
   Klasse löst (dort außerhalb des Datei-Scopes dieser Session). */
.ds-bookkeeping-txdetail-history {
  margin-top: 1rem;
}
.ds-bookkeeping-txdetail-history-summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: .5rem;
}
.ds-bookkeeping-txdetail-history-summary:hover {
  color: var(--text-secondary);
}
.ds-bookkeeping-txdetail-history-reason {
  color: var(--text-tertiary);
  font-size: .75rem;
}

/* Betrag + Entwurf/Finalisiert-Badge gestapelt am rechten Zeilenrand. Das
   Badge kann NICHT in die Anbieter-Zeile: die ist nowrap/ellipsis
   (.ds-bookkeeping-split-item-vendor) und würde es abschneiden. Rechts
   gestapelt richten sich die Badges zudem zu einer scanbaren Spalte aus. */
.ds-bookkeeping-txdetail-cand-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .25rem;
  flex-shrink: 0;
}

/* Beleg-Bearbeiten-Panel (Slide-In, `_openTxDetailEditorPanel` in
   bookkeeping.js) — Monats-Sperre (sent_to_tax): das geteilte Beleg-Formular
   (pages/_receipt-edit-form.js) kennt nur die Beleg-eigene GoBD-Sperre, nicht
   den Monatsstatus — deshalb legt die Positionsseite es in ein
   <fieldset disabled>. Hier nur der Reset der Browser-Default-Optik
   (Rahmen/Innenabstand/min-inline-size), die Werte bleiben lesbar. */
.ds-bookkeeping-txdetail-editor-lock {
  border: 0;
  padding: 0;
  margin: 0;
  min-inline-size: 0;
}

/* Beleg-Bearbeiten-Panel auf volle Breite (Ticket 3.154.1): das Panel deckte
   vorher die Dokumentvorschau der Positionsseite ab — Werte ließen sich
   nicht gegen das Original prüfen ("Ich kann sonst nicht wirklich
   kontrollieren, ob die Dokument-Informationen korrekt übernommen wurden.").
   `.ds-bookkeeping-editor-panel--wide` sitzt auf dem <ds-cal-panel>-Host
   (bookkeeping.js render(), nur wenn `_txDetailEditorOpen`) — die Basisklasse
   `.ds-cal-panel` (clamp 480–900px) bleibt UNVERÄNDERT, weil sie app-weit
   von ~15 anderen Panels geteilt wird (Kalender, Invoicing, Settings, Notes,
   Todos…); ein Eingriff dort hätte jedes dieser Panels verbreitert. Scoped
   auf page-bookkeeping + die eigene Host-Klasse, damit NUR dieses eine Panel
   betroffen ist — die übrigen ~10 Panels dieser Seite (Monat anlegen,
   Kontoauszug hochladen, Belege ansehen, ZIP-Passwort …) bleiben normal
   schmal, da sie kein Dokument+Formular-Split zeigen. */
page-bookkeeping ds-cal-panel.ds-bookkeeping-editor-panel--wide .ds-cal-panel {
  width: min(1500px, calc(100vw - 2rem));
}

/* Dokument links / Formular rechts — Muster identisch zu `.receipts-edit-grid`
   (receipts.js Beleg-Editor-Seite, 1fr 1fr + 1.5rem Gap). Die Vorschau-Box
   selbst reused `.ds-bookkeeping-split-preview` unverändert (inkl. deren
   Mobile-Override weiter unten, height:22rem) — kein zweites Vorschau-Markup. */
.ds-bookkeeping-editor-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  align-items: start;
}
/* Sticky, damit das Dokument beim Scrollen eines langen Formulars sichtbar
   bleibt (Panel-Body ist der scrollende Container, `.ds-cal-panel-body`).
   ⚠️ Nur die Basis fuer schmale Screens (≤900px, s. Mobile-Override weiter
   unten) — ab 901px uebernimmt der Block direkt danach ein anderes Layout
   (volle Hoehe statt sticky, s. dort). */
.ds-bookkeeping-editor-doc-col {
  position: sticky;
  top: 0;
}
.ds-bookkeeping-editor-form-col {
  min-width: 0;
}

/* Ticket 3.154.1 (Nachbesserung — Domenico im Stage-Test: "Das iFrame mit dem
   Dokument sollte über die gesamte Höhe gehen"): die urspruengliche Fassung
   oben loeste nur die BREITE (volles Panel), liess die Dokument-Vorschau aber
   bei ihrer festen 34rem-Hoehe (`.ds-bookkeeping-split-preview`) — bei einem
   laengeren Formular blieb darunter eine leere Flaeche, waehrend rechts noch
   viel mehr Inhalt folgte. Fix: Dokument- und Formular-Spalte werden zu
   echten Flex-Spalten MIT eigenem, unabhaengigem Scroll (Formular scrollt
   intern, Dokument bleibt stets auf voller Panel-Hoehe — `position:sticky`
   dafuer nicht mehr noetig, die Spalte bewegt sich ja gar nicht mehr).
   Muster 1:1 uebernommen von `.cal-editor-panel` (_calendar.css: „Editor-
   Layout im Slide-In-Panel: hebelt das Padding des Panel-Bodys aus…") — dort
   bereits fuer denselben Zweck (Formular + Live-Vorschau nebeneinander, volle
   Panel-Hoehe) erprobt, P-5 keine zweite Erfindung.

   Strikt hinter min-width:901px (Komplement zu max-width:900px, wie die
   Positions-Detailseite oben, „Ticket 3.154.11") — auf schmalen Screens
   stapeln sich Dokument+Formular (Mobile-Override weiter unten), dort bleibt
   die feste, kleinere Vorschau-Hoehe unangetastet (volle Hoehe ergibt bei
   gestapelten Spalten keinen Sinn). */
@media (min-width: 901px) {
  .ds-cal-panel-body:has(> .ds-bookkeeping-editor-split) {
    padding: 0;
  }
  .ds-bookkeeping-editor-split {
    display: flex;
    align-items: stretch;
    height: 100%;
    min-height: 0;
  }
  .ds-bookkeeping-editor-doc-col {
    position: static;
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    padding: .875rem 0 .875rem 1rem;
  }
  .ds-bookkeeping-editor-doc-col .ds-bookkeeping-split-preview {
    flex: 1;
    min-height: 0;
    height: auto;
  }
  .ds-bookkeeping-editor-form-col {
    flex: 1;
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    padding: .875rem 1rem .875rem 0;
  }
}

/* ── Export-Vorabprüfung (K4, Spec 20260730_receipt_categories_accounts.md
   Abschnitt 3 + Bookkeeping-UI Punkt 3): Slide-In-Panel „Export nicht
   möglich" (GET .../export-datev?check=1). Reused das visuelle Vokabular
   der Beleg-Picker-Liste oben (Klick-Zeile, Border, Hover-Akzent) — aber
   coral statt neutral/teal, weil jede Zeile ein BLOCKIERENDES Problem ist
   (kein Auswahl-, sondern ein Sprung-Ziel; .ds-info-box--amber deckt die
   nicht-blockierenden Hinweise darunter ab, keine neue Box-Farbe nötig). */
.ds-bookkeeping-export-problem-intro {
  color: var(--text-secondary);
  font-size: .875rem;
  margin: 0 0 .875rem;
}
.ds-bookkeeping-export-problem-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-height: 22rem;
  overflow-y: auto;
  margin: 0 0 1rem;
}
.ds-bookkeeping-export-problem-item {
  appearance: none;
  -webkit-appearance: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  width: 100%;
  text-align: left;
  padding: .625rem .75rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--coral);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  cursor: pointer;
  font: inherit;
  color: inherit;
  transition: background .12s ease, border-color .12s ease;
}
.ds-bookkeeping-export-problem-item:hover,
.ds-bookkeeping-export-problem-item:focus-visible {
  background: var(--coral-light);
  border-color: var(--coral);
  outline: none;
}
.ds-bookkeeping-export-problem-item-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .1875rem;
}
.ds-bookkeeping-export-problem-item-top {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  min-width: 0;
}
.ds-bookkeeping-export-problem-item-vendor {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.ds-bookkeeping-export-problem-item-date {
  font-size: .75rem;
  color: var(--text-tertiary);
  flex-shrink: 0;
  white-space: nowrap;
}
.ds-bookkeeping-export-problem-item-reason {
  font-size: .8125rem;
  color: var(--coral);
}
.ds-bookkeeping-export-problem-item-right {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-shrink: 0;
}
.ds-bookkeeping-export-problem-item-amount {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.ds-bookkeeping-export-problem-item-arrow {
  color: var(--text-tertiary);
  display: flex;
}
.ds-bookkeeping-export-problem-item:hover .ds-bookkeeping-export-problem-item-arrow,
.ds-bookkeeping-export-problem-item:focus-visible .ds-bookkeeping-export-problem-item-arrow {
  color: var(--coral);
}

/* ── Panel „Positionen erfassen" (B48/C2, Ticket 3.17.2, Spec
   20260730_bookkeeping_cash_expenses.md Abschnitt 3) — Zeilen-Erfassung
   analog dem Positions-Editor der Rechnung (.invoice-item-row), aber mit
   eigener Klassen-Familie: die Rechnung hat 4 Spalten fester Bedeutung
   (Menge/Preis/Summe), hier sind es 8 heterogene Felder je Zeile — ein
   Wiederverwenden des Rechnungs-Grids hätte an keiner Spalte gepasst. Feld-
   Breiten selbst reusen .form-group--w130/w140/w160 aus _core.css (P-5,
   keine neuen Breiten-Klassen). ── */
.ds-bookkeeping-entry-rows {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  margin-bottom: .75rem;
}
.ds-bookkeeping-entry-row {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  padding: .75rem .875rem;
}
.ds-bookkeeping-entry-row--error {
  border-color: var(--coral);
  background: color-mix(in srgb, var(--coral) 5%, var(--bg-primary));
}
.ds-bookkeeping-entry-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .625rem;
}
.ds-bookkeeping-entry-row-index {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--text-secondary);
}
.ds-bookkeeping-entry-fields {
  display: flex;
  flex-wrap: wrap;
  gap: .625rem .75rem;
}
/* Empfänger/Zweck/Kategorie brauchen mehr Raum als die kurzen numerischen/
   Auswahl-Felder (Datum/Betrag/USt/Zahlungsart/Richtung, s. o. die
   festen .form-group--wNNN-Breiten) — wachsen bevorzugt, nie unter 12rem. */
.ds-bookkeeping-entry-field--grow { flex: 1 1 12rem; min-width: 0; }
.ds-bookkeeping-entry-row-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
  margin-top: .625rem;
  padding-top: .625rem;
  border-top: 1px dashed var(--border);
}
.ds-bookkeeping-entry-row-preview {
  font-size: .8125rem;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.ds-bookkeeping-entry-add-btn { margin-bottom: 1rem; }

/* Beleg-Slot am Zeilenfuß — Knopf / Upload-Fortschritt / angehängte Chip. */
.ds-bookkeeping-entry-receipt-busy {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  font-size: .8125rem;
  color: var(--text-secondary);
}
.ds-bookkeeping-entry-receipt-chip {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .1875rem .5rem;
  border-radius: 99px;
  background: var(--teal-light);
  color: var(--teal);
  font-size: .8125rem;
  font-weight: 500;
  max-width: 16rem;
}
.ds-bookkeeping-entry-receipt-chip-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.ds-bookkeeping-entry-receipt-remove {
  appearance: none;
  -webkit-appearance: none;
  display: inline-flex;
  flex-shrink: 0;
  border: none;
  background: none;
  padding: 0;
  color: inherit;
  cursor: pointer;
  opacity: .7;
}
.ds-bookkeeping-entry-receipt-remove:hover { opacity: 1; }
/* Inline-Erfassungsoptionen einer Zeile (renderCaptureOptions aus
   _receipt-capture.js) — kein zweites Panel-Level (dieses Modul kennt nur
   EIN Panel), stattdessen ersetzt der Beleg-Slot der Zeile sich selbst. */
.ds-bookkeeping-entry-receipt-capture {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  width: 100%;
  max-width: 26rem;
  margin-top: .5rem;
}

/* ── Steuerberater-Send-Dialog: Versandart + Passwort-Anzeige (Ticket 3.326.4) ──
   `TaxAdvisorSendPanel` (bookkeeping.js) erweitert das geteilte
   DocumentSendPanel (_document-send-panel.js, außerhalb dieses Datei-Scopes)
   per Komposition — die dortige `.ds-mail-compose`-Formularfläche bleibt
   unverändert, diese Klassen umschließen sie nur zusätzlich. */
.ds-tax-advisor-send { display: flex; flex-direction: column; gap: 1rem; }

.ds-tax-advisor-delivery { display: flex; flex-direction: column; gap: .5rem; }
.ds-tax-advisor-delivery-option {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
  padding: .625rem .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.ds-tax-advisor-delivery-option:hover { border-color: var(--accent); }
.ds-tax-advisor-delivery-option.is-active {
  border-color: var(--accent);
  background: var(--accent-light);
}
.ds-tax-advisor-delivery-option input[type="radio"] {
  margin-top: .1875rem;
  accent-color: var(--accent);
  flex-shrink: 0;
}
.ds-tax-advisor-delivery-option-body { display: flex; flex-direction: column; gap: .125rem; }
.ds-tax-advisor-delivery-option-title { font-size: .875rem; font-weight: 600; color: var(--text-primary); }
.ds-tax-advisor-delivery-option-hint { font-size: .75rem; color: var(--text-secondary); line-height: 1.4; }

/* Passwort — reine Anzeige mit Kopieren-Knopf statt eines editierbaren
   Felds (Ticket 3.326.4: „nicht als Feld, dessen Inhalt im Mailtext landen
   kann" — ein Copy-Paste aus einem sichtbaren Formularfeld in den Mailtext
   direkt darunter ist ein Tastendruck). */
.ds-tax-advisor-pw-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .75rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.ds-tax-advisor-pw-value {
  flex: 1;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .875rem;
  color: var(--text-primary);
  word-break: break-all;
  user-select: all;
}

/* Der Basis-Editor-Input für das ZIP-Passwort (aus _document-send-panel.js,
   `config.passwordField` bleibt bewusst `true` — der Wert muss weiterhin
   gesendet werden) wird ausgeblendet: `.ds-tax-advisor-pw-row` oben ersetzt
   ihn optisch, liest aber dasselbe `this.state.password` (keine zweite
   Datenquelle, nur eine zweite Darstellung). */
.ds-tax-advisor-send .form-group:has(#docsend-zip-password) { display: none; }

/* Link-Weg: der Server hängt nie ein ZIP an (delivery==='link' →
   sendBundle=false, s. BookkeepingController::sendToTaxAdvisor()) — die
   Anhänge-Checkliste der Basis-Klasse wäre hier irreführend. */
.ds-tax-advisor-send--link .form-group:has(.ds-mail-compose-attachments) { display: none; }

/* ── Mobile-Overrides ─────────────────────────────────────────────── */
@media (max-width: 900px) {
  page-bookkeeping .page-header-h1      { display: none; }
  page-bookkeeping .page-header-actions { display: none; }
  .ds-bookkeeping-picker-list { max-height: none; }
  .ds-bookkeeping-export-problem-list { max-height: none; }
  .ds-bookkeeping-split { grid-template-columns: 1fr; }
  .ds-bookkeeping-split-list { max-height: 16rem; }
  .ds-bookkeeping-split-preview { height: 22rem; }

  /* Panel „Positionen erfassen" (B48/C2): jedes Feld auf volle Breite —
     die festen .form-group--wNNN-Basisbreiten (130/140/160px) plus
     mehrere .ds-bookkeeping-entry-field--grow-Felder nebeneinander würden
     auf 375px sonst umbrechen, aber teils noch zweispaltig, uneinheitlich
     schmal wirken. Ein Feld pro Zeile ist auf dem Telefon eindeutig
     bedienbar, keine horizontale Scrollleiste. */
  .ds-bookkeeping-entry-fields .form-group { flex: 1 1 100%; }
  .ds-bookkeeping-entry-receipt-capture { max-width: none; }

  .ds-bookkeeping-txdetail-fields { grid-template-columns: 1fr; }
  .ds-bookkeeping-txdetail-grid { grid-template-columns: 1fr; }
  /* Beleg-Bearbeiten-Panel (Ticket 3.154.1): volle Breite bleibt 100%
     (Basis-Mobile-Regel für .ds-cal-panel greift bereits — hier nur zur
     Klarheit erneut, falls die höhere Spezifität der Wide-Regel oben sonst
     gewinnt) + Dokument/Formular untereinander statt nebeneinander. */
  page-bookkeeping ds-cal-panel.ds-bookkeeping-editor-panel--wide .ds-cal-panel { width: 100%; }
  .ds-bookkeeping-editor-split { grid-template-columns: 1fr; }
  .ds-bookkeeping-editor-doc-col { position: static; }
  /* Der "Differenz — Bankbetrag ist niedriger/höher …"-Zeilenlabel ist lang;
     auf schmalen Screens darf die Zeile umbrechen statt Wert und Label zu
     stauchen (space-between hält den Wert trotzdem rechtsbündig). */
  .ds-bookkeeping-txdetail-diff-row { flex-wrap: wrap; }
}
/* ── Support/Feedback-Widget (Beta) ──────────────────────────── */
/* Spec .claude/specs/20260721_support_feedback_beta.md, Schritt S3. Prefix ds-support-*.
   Status-/Typ-Badges reusen die generischen .badge/.badge-* Klassen (_core.css) —
   keine eigenen Badge-Farben hier. Segmented-Control ist bewusst KEIN .ds-theme-toggle
   (benannte Zweiwahl Bug|Feature, kein binäres on/off — s. frontend.md). */

.ds-support-dialog {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.ds-support-tabs {
  margin-bottom: 0.25rem;
}

/* Segmented-Control Bug|Feature — eigene Klasse (analog .contact-status-segment-Struktur,
   aber full-width statt inline-neben-Filtern, da hier ein Formularfeld statt Listen-Filter). */
.ds-support-type-segment {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.ds-support-type-seg-btn {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  height: 40px;
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-size: 0.8125rem;
  font-weight: 500;
  cursor: pointer;
  border: none;
  border-right: 1px solid var(--border);
  transition: background var(--transition), color var(--transition);
  -webkit-tap-highlight-color: transparent;
}
.ds-support-type-seg-btn:last-child { border-right: none; }
.ds-support-type-seg-btn:hover { background: var(--bg-tertiary); color: var(--text-primary); }
.ds-support-type-seg-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.ds-support-type-seg-btn.is-active {
  background: var(--accent-light);
  color: var(--accent-dark);
  font-weight: 600;
}

.ds-support-optional { color: var(--text-tertiary); font-weight: 400; }

.ds-support-form-error {
  color: var(--coral);
  font-size: 0.8125rem;
  margin: 0;
}

.ds-support-form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

/* Erfolgs-Banner nach Absenden — erscheint im Tab "Meine Anfragen" (dorthin wird
   nach erfolgreichem Absenden automatisch gewechselt). Auto-Dismiss nach 6s (JS). */
.ds-support-success-banner {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.75rem 0.875rem;
  border-radius: var(--radius-md);
  background: var(--teal-light);
  color: var(--teal);
  font-size: 0.85rem;
}
.ds-support-success-banner svg { flex-shrink: 0; }
.ds-support-success-banner strong { font-weight: 600; }
.ds-support-banner-dismiss {
  margin-left: auto;
  flex-shrink: 0;
  background: transparent;
  border: none;
  color: inherit;
  cursor: pointer;
  padding: 0.25rem;
  display: flex;
  border-radius: var(--radius-sm);
  opacity: 0.7;
  transition: opacity var(--transition);
}
.ds-support-banner-dismiss:hover { opacity: 1; }

.ds-support-ticket-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-height: 55vh;
  overflow-y: auto;
}

.ds-support-ticket-row {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.75rem 0.875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  text-align: left;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
  width: 100%;
}
.ds-support-ticket-row:hover { background: var(--bg-secondary); border-color: var(--accent); }
.ds-support-ticket-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.ds-support-ticket-row-top {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.ds-support-ticket-number {
  font-weight: 600;
  font-size: 0.8125rem;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.ds-support-ticket-subject {
  font-size: 0.85rem;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-support-ticket-meta {
  font-size: 0.72rem;
  color: var(--text-tertiary);
}

/* Detail-Ansicht (innerhalb desselben Tabs "Meine Anfragen") */
.ds-support-detail-back {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  background: transparent;
  border: none;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.8125rem;
  padding: 0.25rem 0;
  margin-bottom: 0.25rem;
}
.ds-support-detail-back:hover { color: var(--accent); }
.ds-support-detail-back svg { width: 16px; height: 16px; }

.ds-support-detail-head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}
.ds-support-detail-subject {
  font-size: 0.95rem;
  margin: 0 0 0.375rem;
  color: var(--text-primary);
}
.ds-support-detail-description {
  font-size: 0.875rem;
  color: var(--text-secondary);
  white-space: pre-wrap;
  margin: 0 0 1rem;
}

.ds-support-thread {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  margin-bottom: 1rem;
  max-height: 30vh;
  overflow-y: auto;
}
.ds-support-thread-empty {
  color: var(--text-tertiary);
  font-size: 0.8125rem;
  margin: 0;
}
.ds-support-comment {
  padding: 0.625rem 0.75rem;
  border-radius: var(--radius-md);
  background: var(--bg-tertiary);
}
.ds-support-comment--staff { background: var(--accent-light); }
.ds-support-comment-meta {
  font-size: 0.7rem;
  color: var(--text-tertiary);
  margin-bottom: 0.25rem;
}
.ds-support-comment-body {
  font-size: 0.85rem;
  color: var(--text-primary);
  white-space: pre-wrap;
}

/* Screenshot-Anhang (Phase 2, Migration 368) — Compose-Feld (nur Bug-Modus) */
.ds-support-attachment-preview {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
}
.ds-support-attachment-preview-img {
  width: 56px;
  height: 56px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  flex-shrink: 0;
}
.ds-support-attachment-remove { margin-left: auto; flex-shrink: 0; }

/* Anhang-Thumbnails im Ticket-Detail — geteilt zwischen ds-support-dialog.js
   (User-"Meine Anfragen") und support-admin.js (Admin-Inbox). */
.ds-support-attachments { margin: 0 0 1rem; }
.ds-support-attachments-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-tertiary);
  margin: 0 0 0.375rem;
}
.ds-support-attachment-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.ds-support-attachment-thumb-btn {
  width: 72px;
  height: 72px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  cursor: pointer;
  background: var(--bg-secondary);
  transition: border-color var(--transition);
}
.ds-support-attachment-thumb-btn:hover { border-color: var(--accent); }
.ds-support-attachment-thumb-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ds-support-attachment-thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Lade-Platzhalter waehrend die Blob-Object-URL noch geholt wird — gleiches
   Shimmer wie .skeleton-bar/-circle (_core.css @keyframes mail-skeleton-shimmer),
   hier ohne eigenes Keyframe (global bereits vorhanden, kein Duplikat noetig). */
.ds-support-attachment-thumb--loading {
  background: linear-gradient(90deg, var(--bg-tertiary) 0%, var(--border) 50%, var(--bg-tertiary) 100%);
  background-size: 200% 100%;
  animation: mail-skeleton-shimmer 1.4s ease-in-out infinite;
}

@media (max-width: 900px) {
  .ds-support-ticket-list { max-height: 50vh; }
  .ds-support-thread { max-height: 26vh; }
}

/* ── Admin-Inbox (#/admin-tools/support) — Schritt S4 ──────────────────────
   Eingebettet als eigenes Custom-Element <page-support-admin> im Tab
   "Support" von pages/admin-tools.js (pathTabs). Reused wo möglich die
   generischen .badge/.card/.table-Klassen sowie die Thread-/Kommentar-
   Klassen aus dem User-Widget oben (.ds-support-thread*/.ds-support-comment*)
   — nur admin-spezifische Ergänzungen (Filter-Leiste, Diagnose-Block,
   interne-Notiz-Kennzeichnung) sind hier neu. */

.ds-support-admin {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.25rem;
}

/* Filter-Bar (Phase 2, Feinschliff): Text-Suche + Status/Typ/Priorität/
   Sortierung + Aktualisieren-Button. Wrapper haelt die Suche als eigenes
   flex-Item neben dem Select-Cluster, damit sie auf Mobile auf eine eigene
   Zeile umbricht (statt zwischen die Selects zu wrappen). */
.ds-support-admin-filterbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.625rem;
}
.ds-support-admin-search {
  flex: 1 1 220px;
  min-width: 180px;
}
.ds-support-admin-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
/* 🔒 .select ist global width:100% (_core.css) — als DIREKTES Kind einer
   flex-wrap-Reihe macht das jeden Select zum flex-basis:100% (width:100%
   loest sich OHNE eigenen Wrapper-Container direkt zur flex-basis auf) und
   zwingt dadurch jeden Select auf eine eigene Zeile (vorbestehender Bug,
   Screenshot-belegt vor diesem Fix). Fix: width:auto + expliziter
   flex-basis statt der geerbten 100%. */
.ds-support-admin-filters .select {
  width: auto;
  flex: 0 1 9rem;
  min-width: 9rem;
}

.ds-support-admin-subject-cell {
  max-width: 16rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-support-admin-user-name  { font-size: 0.8125rem; color: var(--text-primary); font-weight: 500; }
.ds-support-admin-user-email { font-size: 0.72rem;   color: var(--text-tertiary); }

/* Detail-Ansicht */
.ds-support-admin-detail-info {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.25rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  margin: 0 0 0.75rem;
}
.ds-support-admin-detail-info-label { color: var(--text-tertiary); margin-right: 0.25rem; }

.ds-support-admin-fields-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.875rem;
  margin: 0 0 1rem;
}
.ds-support-admin-field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 10rem;
}
.ds-support-admin-field-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-tertiary);
}

/* Bearbeitungs-Bereich (Status/Priorität/Antwort/Sichtbarkeit/Senden) als
   eigene Card — optisch getrennt vom read-only-Teil (Betreff/Beschreibung/
   User/Diagnose) und vom Verlauf oberhalb. Reused .card/.card-header/
   .card-body (generisch, _core.css) + .divider zwischen Feldern und
   Antwort-Formular; nur die Positionierungs-Klasse ist hier neu. */
.ds-support-admin-edit-card { margin-top: 0.25rem; }

/* Diagnose-Block (aufklappbar) — direkt gefolgt vom Verlauf (.ds-support-thread),
   daher eigenes margin-bottom statt sich auf ein nachfolgendes Element zu verlassen. */
.ds-support-admin-diag {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: 1rem;
}
.ds-support-admin-diag-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.625rem 0.875rem;
  background: var(--bg-secondary);
  border: none;
  color: var(--text-primary);
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  text-align: left;
}
.ds-support-admin-diag-toggle:hover { background: var(--bg-tertiary); }
.ds-support-admin-diag-chevron {
  display: inline-flex;
  color: var(--text-tertiary);
  transition: transform var(--transition);
}
.ds-support-admin-diag-chevron.is-open { transform: rotate(90deg); }

.ds-support-admin-diag-body {
  padding: 0.875rem;
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  max-height: 40vh;
  overflow-y: auto;
}
.ds-support-admin-diag-section-title {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-tertiary);
  margin-bottom: 0.375rem;
}
.ds-support-admin-diag-kv {
  display: flex;
  gap: 0.5rem;
  font-size: 0.8125rem;
  padding: 0.15rem 0;
  border-bottom: 1px solid var(--border);
}
.ds-support-admin-diag-kv:last-child { border-bottom: none; }
.ds-support-admin-diag-kv-label {
  flex: 0 0 8rem;
  color: var(--text-tertiary);
}
.ds-support-admin-diag-kv-value {
  flex: 1;
  color: var(--text-primary);
  word-break: break-word;
}
.ds-support-admin-diag-pre {
  font-family: monospace;
  font-size: 0.75rem;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.625rem;
  margin-bottom: 0.375rem;
}
.ds-support-admin-diag-empty {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
  font-style: italic;
  margin: 0;
}

/* Interner Kommentar — visuell abgesetzt vom für den User sichtbaren (amber = "nur intern") */
.ds-support-comment--internal {
  background: var(--amber-light);
  border: 1px dashed var(--amber);
}
.ds-support-admin-comment-badge {
  display: inline-block;
  margin-left: 0.375rem;
  padding: 0.05rem 0.4rem;
  border-radius: var(--radius-sm);
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  background: var(--amber-light);
  color: var(--amber);
}

.ds-support-admin-visibility-row {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin: 0.5rem 0 0.75rem;
}
.ds-support-admin-visibility-label { font-size: 0.8125rem; color: var(--text-secondary); }

/* ── Board-Ticket-Verknuepfung (Ticket 3.123.2 / T2) ─────────────
   "Board-Ticket erstellen"-Aktion + Liste bereits verknuepfter Board-
   Tickets im Ticket-Detail der Support-Admin-Inbox. */
.ds-support-todo-link {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0.75rem 0;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
}
.ds-support-todo-link-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.ds-support-todo-link-title {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--text-tertiary);
}
/* Zielprojekt-Auswahl + "Board-Ticket erstellen"-Button (Ticket 3.123.5).
   Eigener Wrapper statt beide als direkte Kinder von -head, damit sie bei
   knappem Platz gemeinsam auf eine zweite Zeile umbrechen (statt Titel und
   Select getrennt) und der Button dabei nie verdraengt wird. */
.ds-support-todo-link-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-left: auto;
}
/* 🔒 .select ist global width:100% (_core.css) — als direktes Flex-Kind
   macht das den Select zu flex-basis:100% und zwingt ihn auf eine eigene
   Zeile (identisches Problem wie .ds-support-admin-filters .select oben,
   dort bereits dokumentiert). Fix: width:auto + expliziter flex-basis. */
.ds-support-todo-link-actions .select {
  width: auto;
  flex: 1 1 11rem;
  min-width: 8rem;
  max-width: 16rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-support-todo-link-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.ds-support-todo-link-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  text-align: left;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.6rem;
  font-size: 0.8125rem;
  color: var(--text-primary);
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.ds-support-todo-link-item:hover { border-color: var(--accent); background: var(--accent-light); }
/* Ticket 3.123.7 — Board-eigene Ticketnummer vor dem Titel (kann fehlen,
   s. TodoModel::findLinkedToSupportTicket()-Docblock: NULL bei Anlage ohne
   Zielprojekt/im Posteingang). */
.ds-support-todo-link-item-number {
  flex-shrink: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.75rem;
  color: var(--text-tertiary);
}
.ds-support-todo-link-item-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Deep-Link-Chevron (Ticket 3.123.7) — signalisiert "klickbar, springt zum
   Board-Ticket", analog ds-todo-detail.js ICO_CHEV_RIGHT. */
.ds-support-todo-link-item svg { flex-shrink: 0; color: var(--text-tertiary); }

@media (max-width: 900px) {
  .ds-support-admin { padding: 0.75rem; }
  .ds-support-admin-diag-body { max-height: 32vh; }
  /* Suche bekommt auf Mobile eine eigene Zeile — Select-Cluster (Status/Typ/
     Priorität/Sortierung/Aktualisieren) wrapped darunter statt dazwischen. */
  .ds-support-admin-search { flex: 1 1 100%; }
  /* Volle Breite statt 2er-Grid — bei fester 9rem-Basis schneidet der Browser
     laengere Labels ("Alle Prioritäten") unter dem Pfeil ab (kein Ellipsis auf
     nativen Selects). Full-width je Zeile haelt Labels vollstaendig lesbar. */
  .ds-support-admin-filters .select { flex: 1 1 100%; }

  /* Board-Ticket-Zielprojekt (Ticket 3.123.5): Titel bleibt in eigener Zeile,
     Select + Button ruecken als Gruppe auf die volle Breite darunter — kein
     ueberlaufen, Button bleibt immer erreichbar. */
  .ds-support-todo-link-actions { flex: 1 1 100%; margin-left: 0; }
  .ds-support-todo-link-actions .select { flex: 1 1 auto; max-width: none; }
}
/* ── Profil-Seite (page-profile) ──────────────────────────────── */

.ds-profile-section-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .05em;
}
/* ── Todos-Modul (Ticket 3.85) ────────────────────────────────────────────
   CSS aus den JS <style>-Blöcken der Todo-Komponenten ausgelagert, siehe
   .claude/rules/modules/todos.md. Herkunfts-Konvention: je Abschnitt ein
   Kommentar "aus <datei>.js", Regel-Reihenfolge innerhalb einer Herkunfts-
   Sektion unverändert zum ursprünglichen Inline-Block beibehalten. */

/* ── aus ds-todo-group-panel.js ── */
.gp-wrap { padding: 0 1.25rem 2rem; display:flex; flex-direction:column; gap:1.25rem; }
.gp-type {
  display:inline-block; padding:.15rem .45rem;
  border-radius: 999px;
  font-size: .7rem; text-transform: uppercase; letter-spacing: .04em;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.gp-type--epic {
  background: var(--accent);
  color: #fff;
}
.gp-name {
  font-size: 1.1rem; font-weight: 600; flex: 1;
  padding: .3rem .5rem; border: 1px solid transparent;
  border-radius: var(--radius-sm);
}
.gp-name:focus {
  outline: none; border-color: var(--accent);
  background: var(--bg-primary);
}
.gp-row { display: flex; align-items: center; gap: .75rem; }
.gp-label { width: 110px; font-size:.8rem; color: var(--text-tertiary); }
.gp-input {
  flex: 1; padding: .35rem .5rem; font-size: .88rem;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-primary); color: var(--text-primary);
}
.gp-progress {
  height: 6px; border-radius: 3px;
  background: var(--bg-tertiary); overflow: hidden;
}
.gp-progress-fill {
  height: 100%; background: linear-gradient(90deg, var(--accent), var(--teal));
  transition: width .2s ease;
}
.gp-section-title {
  font-size: .72rem; font-weight: 600; text-transform: uppercase;
  color: var(--text-tertiary); letter-spacing: .04em;
  margin-bottom: .4rem;
}

/* ── aus ds-todo-project-templates.js (_renderList) ── */
.tpl-list-page { padding:1.25rem; display:flex; flex-direction:column; gap:1rem; }
.tpl-list-header { display:flex; align-items:center; gap:.75rem; margin-bottom:.25rem; }
.tpl-list-header h3 { font-size:1rem; font-weight:700; margin:0; flex:1; }
.tpl-card {
  border:1px solid var(--border); border-radius:var(--radius-md);
  background:var(--bg-primary); padding:.875rem 1rem;
  display:flex; align-items:flex-start; gap:.75rem;
  transition:background var(--transition);
}
.tpl-card:hover { background:var(--bg-secondary); }
.tpl-card-body { flex:1; min-width:0; }
.tpl-card-name { font-weight:600; font-size:.9375rem; color:var(--text-primary); margin-bottom:.25rem; }
.tpl-card-meta { font-size:.8rem; color:var(--text-tertiary); display:flex; gap:.75rem; flex-wrap:wrap; }
.tpl-card-sections { margin-top:.375rem; display:flex; flex-wrap:wrap; gap:.25rem; }
.tpl-section-pill {
  font-size:.75rem; padding:.125rem .5rem; border-radius:999px;
  background:var(--bg-tertiary); color:var(--text-secondary);
  border:1px solid var(--border);
}
.tpl-card-actions { display:flex; gap:.375rem; flex-shrink:0; align-items:center; }
.tpl-star-btn { display:inline-flex; align-items:center; justify-content:center; width:32px; height:32px; border-radius:var(--radius-sm); border:none; background:transparent; cursor:pointer; color:var(--text-tertiary); transition:color var(--transition), background var(--transition); }
.tpl-star-btn:hover { background:var(--bg-tertiary); color:var(--amber); }
.tpl-star-btn--active { color:var(--amber); cursor:default; }
.tpl-star-btn--active:hover { background:transparent; color:var(--amber); }
.tpl-empty { padding:2.5rem 1rem; text-align:center; color:var(--text-tertiary); display:flex; flex-direction:column; align-items:center; gap:.75rem; }
.tpl-empty svg { opacity:.3; }

/* ── aus ds-todo-project-templates.js (_renderForm) ── */
.tpl-form-page { padding:1.25rem; display:flex; flex-direction:column; gap:1rem; }
.tpl-form-header { display:flex; align-items:center; gap:.5rem; margin-bottom:.25rem; }
.tpl-form-header h3 { font-size:1rem; font-weight:700; margin:0; flex:1; }
.tpl-form-row { display:flex; flex-direction:column; gap:.375rem; }
.tpl-form-label { font-size:.8rem; font-weight:600; text-transform:uppercase; letter-spacing:.04em; color:var(--text-tertiary); }
.tpl-section-list { display:flex; flex-direction:column; gap:.25rem; }
.tpl-section-item {
  display:flex; align-items:center; gap:.375rem;
  border:1px solid var(--border); border-radius:var(--radius-sm);
  background:var(--bg-secondary); padding:.375rem .625rem;
  font-size:.875rem;
}
.tpl-section-item-name { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.tpl-section-move { color:var(--text-tertiary); cursor:pointer; padding:.125rem; border-radius:2px; }
.tpl-section-move:hover { background:var(--bg-tertiary); color:var(--text-primary); }
.tpl-section-add { display:flex; gap:.375rem; margin-top:.25rem; }
.tpl-form-actions { display:flex; gap:.5rem; justify-content:flex-end; border-top:1px solid var(--border); padding-top:.875rem; margin-top:.5rem; }
.tpl-toggle-row { display:flex; align-items:center; justify-content:space-between; padding:.5rem 0; }
.tpl-toggle-label { font-size:.875rem; color:var(--text-primary); }

/* ── Papierkorb-Seite (Ticket 3.207 Runde B / 3.197.5-Feedback) ──────────
   page-todos.js _renderTrashView() -- Reiter Projekte/Etiketten,
   .card > .table-wrap > .table (Desktop, Bulk-Select) analog der Listenseiten-
   Konvention; Mobile .card.native-list-card > .native-list > .native-row
   ohne Bulk (design-system.md "Bulk-Selection + Action-Bar", Desktop-only). */
.todo-trash-page { padding:1.25rem; display:flex; flex-direction:column; gap:1rem; }
.todo-trash-header { display:flex; align-items:center; gap:.75rem; }
.todo-trash-header h3 { font-size:1rem; font-weight:700; margin:0; flex:1; }
.todo-trash-hint { font-size:.8125rem; color:var(--text-tertiary); margin:0; line-height:1.5; }
.todo-trash-row-name { display:flex; align-items:center; gap:.5rem; font-weight:500; min-width:0; }
.todo-trash-row-name span:last-child { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.todo-trash-dot {
  width:8px; height:8px; border-radius:50%; flex-shrink:0;
  display:inline-block; vertical-align:middle;
}
.todo-trash-row-actions { display:flex; gap:.25rem; justify-content:flex-end; }
.todo-trash-native-row-actions { display:flex; gap:.25rem; flex-shrink:0; }
.todo-trash-action-btn {
  width:30px; height:30px; display:inline-flex; align-items:center; justify-content:center;
  border:none; background:none; border-radius:var(--radius-sm);
  color:var(--text-tertiary); cursor:pointer; flex-shrink:0;
  transition: background var(--transition), color var(--transition);
}
.todo-trash-action-btn:hover { background:var(--bg-tertiary); color:var(--text-primary); }
.todo-trash-action-btn--danger:hover { background:var(--danger-light); color:var(--danger); }

/* ── Papierkorb-Reiter "Aufgaben" (Ticket 3.242) ──────────────────────────
   page-todos.js _renderTrashTasksView()/-Desktop()/-Mobile() -- eigener Reiter
   neben Projekte/Etiketten (s. Sektion oben), zusaetzlich mit Suche+Filter+
   Seitenweise-Chrome (der Papierkorb waechst unbegrenzt, keine Aufbewahrungs-
   frist, .claude/rules/modules/todos.md). Sucheingabe reused .todo-header-search
   (weiter unten in dieser Datei, aus ds-todo-list-view.js) statt einer zweiten
   Suchfeld-Definition (P-5). */
.todo-trash-tasks-toolbar {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}
.todo-trash-tasks-toolbar .todo-header-search { flex: 1 1 240px; min-width: 200px; }
/* Ticket 3.263 -- Projekt-Filter als durchsuchbare Selectbox (.ss-wrap,
   Basisklasse .todo-filter-field-ss aus ds-todo-list-view.js weiter unten in
   dieser Datei liefert die 160px-Fixbreite). Compound-Selektor (statt
   Verlassen auf Quellreihenfolge) erzwingt die abweichende Flex-/Breiten-
   Regel unabhaengig davon, wo die Basisklasse im Partial steht (frontend.md
   "Eine Media-Query erhoeht die Spezifitaet NICHT" -- dieselbe Vorsicht gilt
   fuer jede Klassen-Override-Situation). */
.todo-trash-tasks-project-filter-ss.todo-filter-field-ss {
  width: auto;
  flex: 0 0 auto;
  min-width: 160px;
  max-width: 220px;
}
.todo-trash-tasks-project-filter-ss .ss-trigger {
  height: 30px;
  min-height: 30px;
  padding: 0 .55rem;
  font-size: .8125rem;
}
.todo-trash-task-title {
  display: flex;
  align-items: center;
  gap: .375rem;
  flex-wrap: wrap;
  min-width: 0;
  font-weight: 500;
}
.todo-trash-task-title > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
  min-width: 0;
}
.todo-trash-loadmore {
  display: flex;
  justify-content: center;
  padding: .5rem 0;
}
@media (max-width: 900px) {
  .todo-trash-tasks-toolbar { flex-direction: column; align-items: stretch; }
  /* 🔒 flex-basis wirkt je nach flex-direction auf Breite ODER Hoehe
     (frontend.md "Eine Media-Query erhoeht die Spezifitaet NICHT" -- verwandte
     Falle: flex-basis:240px war fuer die Zeilen-Anordnung (Desktop, Breite)
     gedacht; in der Spalten-Anordnung oben wird daraus eine 240px HOEHE. Live
     gemessen: computed height 240px statt der erwarteten ~30px). */
  .todo-trash-tasks-toolbar .todo-header-search { flex: 0 0 auto; }
  .todo-trash-tasks-project-filter-ss.todo-filter-field-ss { max-width: none; }
  /* Dritter Reiter (Ticket 3.242) sprengt auf schmalen Screens die Breite von
     .tab-filter (Basisklasse _core.css, dort ohne Scroll/Wrap-Vorkehrung --
     bewusst nur hier gescoped ueberschrieben statt die Basisklasse fuer alle
     ~20 Verwendungen anzufassen). Horizontal scrollbar statt abgeschnitten. */
  .todo-trash-page .tab-filter { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .todo-trash-page .tab-filter-btn { flex-shrink: 0; white-space: nowrap; }
}

/* ── Verlauf-Seite (Ticket 3.369.2, Tabellen-Redesign 3.369.3) ─────────────
   page-todos.js _renderActivityView() -> TodoActivityView (pages/todos/
   _todo-activity-view.js) -- mandantenweiter Ereignis-Strom. Kopf/Hinweis
   1:1 aus der Papierkorb-Seite uebernommen (.todo-trash-page/-header/-hint
   -> .todo-activity-page/-header/-hint, dieselben Werte). Seit 3.369.3 folgt
   der Inhalt dem App-Standard "Listenseite / Tabelle" (design-system.md
   Abschnitt A): .card > .table-wrap > table.table (Desktop) bzw.
   .card.native-list-card > .native-list (Mobile, isMobile()-Switch in
   _renderBody()) -- vorher ein Eigenbau aus freien Zeilen ohne Card-Rahmen. */
.todo-activity-page   { padding:1.25rem; display:flex; flex-direction:column; gap:1rem; }
.todo-activity-header { display:flex; align-items:center; gap:.75rem; }
.todo-activity-header h3 { font-size:1rem; font-weight:700; margin:0; flex:1; }
.todo-activity-hint   { font-size:.8125rem; color:var(--text-tertiary); margin:0; line-height:1.5; }

/* Ticket 3.369.3 -- Filterleiste optisch vom Inhalt abgehoben (Domenico:
   "die Filter abheben, dünkleres grau"). --bg-tertiary ist im Farbsystem
   genau eine Stufe dunkler als der Seiten-Canvas --bg-secondary, den
   .todos-content traegt (base.css: #eeede8 vs. #f5f5f3 Light) -- erzeugt
   damit sichtbaren Kontrast ohne einen neuen Hex-Wert. Neues Muster, s.
   design-system.md "Verlauf-Seite -- abgehobene Filterleiste". */
.todo-activity-filterbar {
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .75rem .875rem;
}
.todo-activity-filters {
  display: flex;
  align-items: center;
  gap: .625rem;
  flex-wrap: wrap;
}
.todo-activity-filter-date {
  display: flex;
  align-items: center;
  gap: .375rem;
  font-size: .8125rem;
  color: var(--text-tertiary);
}
.todo-activity-filter-date input[type="date"] {
  height: 30px;
  font-size: .8125rem;
  padding: 0 .5rem;
  background: var(--bg-primary);
}
.todo-activity-filter-ss.todo-filter-field-ss { width: auto; flex: 0 0 auto; min-width: 160px; max-width: 220px; }
.todo-activity-filter-ss .ss-trigger { height: 30px; min-height: 30px; padding: 0 .55rem; font-size: .8125rem; background: var(--bg-primary); }
.todo-activity-trigger-chips { flex-wrap: wrap; overflow: visible; padding: 0; border-bottom: none; }

/* Tages-Gruppenkopf -- Desktop <td colspan> UND Mobile <div> teilen sich
   dieselbe Klasse (keine display-Abhaengigkeit in den Regeln), Muster 1:1
   aus .receipts-group-row-label (Monats-Gruppenkopf, _receipts.css). */
.todo-activity-group-row-label {
  padding: .5rem 1rem;
  font-weight: 600;
  font-size: .72rem;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.todo-activity-td-time { color: var(--text-tertiary); font-size: .8125rem; white-space: nowrap; width: 3.5rem; }
.todo-activity-row-task { display:flex; align-items:center; gap:.5rem; flex-wrap:wrap; }
.todo-activity-row-change { font-size: .8125rem; color: var(--text-secondary); }
.todo-activity-more { display: flex; justify-content: center; padding: .5rem 0; }

/* Ereignisse ohne (mehr) existierende Aufgabe sind nicht navigierbar -- kein
   Zeiger-Cursor, kein Hover-Feedback vortäuschen. #todo-activity-table als
   ID-Anker haelt die Spezifitaet zuverlaessig ueber der generischen
   `.table tbody tr { cursor:pointer }`-Basisregel (_core.css). */
#todo-activity-table tbody tr.todo-activity-tr-static { cursor: default; }
#todo-activity-table tbody tr.todo-activity-tr-static:hover { background: transparent; }
.todo-activity-native-row-static { cursor: default; }
.todo-activity-native-row-static:active { background: transparent; }

@media (max-width: 900px) {
  .todo-activity-filters { gap: .5rem; }
  .todo-activity-filter-ss.todo-filter-field-ss { max-width: none; flex: 1 1 140px; }
}

/* ── aus _todo-status.js (ehemals TODO_STATUS_CSS, 3.85 Paket 2/5/7) ──────
   Sonderfall: _todo-status.js hatte NIE einen eigenen <style>-Block,
   sondern exportierte diese Regeln als CSS-String-Konstante TODO_STATUS_CSS
   zum Interpolieren in fremde <style>-Bloecke. Beide ehemaligen Konsumenten
   sind migriert: ds-todo-item.js (Paket 5) auf den Abschnitt "aus
   ds-todo-item.js" weiter unten, ds-todo-detail.js (Paket 7, letzter
   verbliebener Interpolator, grep-geprüft vor dem Entfernen) auf den
   Abschnitt "aus ds-todo-detail.js". Der Export TODO_STATUS_CSS existiert
   seither NICHT mehr -- diese Regeln HIER sind die einzige, kanonische
   Kopie (kein Spiegel mehr, P-5 vollstaendig aufgeloest). */
.todo-type-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.todo-type-icon--bug { color: var(--coral); }
.todo-type-icon--task { color: var(--text-tertiary); }
.todo-type-icon--epic { color: var(--accent); }

.todo-status-sel {
  appearance: none; -webkit-appearance: none;
  border: 1px solid; border-radius: 999px;
  font-size: .72rem; font-weight: 600;
  padding: .1rem 1.1rem .1rem .5rem; cursor: pointer;
  background-position: right .35rem center; background-repeat: no-repeat;
  background-size: 9px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='3'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  line-height: 1.4; max-width: 8rem;
}
.todo-status-sel--sm { font-size: .68rem; padding: .05rem 1rem .05rem .4rem; }

/* ── aus ds-todo-quick-add.js (3.85 Paket 2) ── */
.quick-add-wrap {
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  box-shadow: var(--shadow-sm);
  padding: 0.625rem;
  position: relative;
}
.quick-add-input-row {
  position: relative;
}
.quick-add-input {
  width: 100%;
  font-size: 0.875rem;
  padding: 0.375rem 0.5rem;
  border: none;
  outline: none;
  background: transparent;
  color: var(--text-primary);
}
.quick-add-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  padding: 0.625rem 0 0.25rem;
  margin-top: 0.25rem;
  border-top: 1px solid var(--border);
}
.quick-add-toolbar .ds-toolbar-item .clear-x {
  display: inline-flex;
  margin-left: 0.15rem;
  opacity: 0.7;
  flex-shrink: 0;
}
.quick-add-toolbar .ds-toolbar-item .clear-x:hover { opacity: 1; }

/* Ticket 3.251 -- der Projekt-Chip ("Federated Data Governance Framework
   (1006433)") sprengte die Toolbar, weil .ds-toolbar-item selbst
   white-space:nowrap traegt (keine Zeilenumbruch-Bremse). Nur DIESER
   Button bekommt ein max-width (die anderen .ds-toolbar-items -- Typ/
   Groesse/Prioritaet/Etikett/Assignee/Datum -- haben kurze, feste
   Labels und bleiben unangetastet). Der volle Name steht als natives
   title-Attribut (Tooltip) am Button. */
.quick-add-project-btn {
  max-width: 240px;
}
.quick-add-project-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 480px) {
  .quick-add-project-btn { max-width: 160px; }
}
/* Ticket 3.292 -- Epic-Chip in der Toolbar, analog .quick-add-project-btn
   oben (identisches Muster): laengere Epic-Titel (inkl. Ticketnummer-
   Praefix) sprengen sonst die Toolbar. */
.quick-add-epic-btn {
  max-width: 220px;
}
.quick-add-epic-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 480px) {
  .quick-add-epic-btn { max-width: 150px; }
}
/* Ticket 3.292 -- wiederverwendbarer Farbpunkt fuer die Epic-Auswahl
   (Toolbar-Knopf + Dropdown-Eintraege) als CSS-Custom-Property statt
   wiederholtem Roh-Inline-Style (frontend.md "CSS: Klassen statt
   Inline-Styles" -- gilt fuer NEUEN Code, kein Pflicht-Sweep des
   bestehenden Inline-Style-Altbestands dieser Datei fuer Projekt/Label/
   Company). */
.quick-add-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  display: inline-block;
  background: var(--dot-color, var(--accent));
}
/* Toolbar-Item-Anker (Typ/Priorität/Etikett/Assignee/Datum/Projekt) --
   eigene Klasse statt Inline-Style, damit der Kompakt-Modus (s.u.)
   "position" per Klassen-Regel überschreiben kann (Inline-Styles
   schlagen jede Klassen-Regel, unabhängig von Spezifität). */
.qa-anchor {
  position: relative;
}
/* Kunde-Aufklapper (Ticket 3.262 "Kunde je Ticket zuordnen") -- eigene
   Klasse statt Inline-Style (frontend.md "CSS: Klassen statt
   Inline-Styles"), analog dem qa-anchor-Kommentar oben. Feste Breite wie
   das übrige Aufklapp-Menü-Set (.quick-add-dropdown: min 200/max 320px),
   damit <ds-company-picker> (die volle Container-Breite füllt) nicht auf
   0px kollabiert. */
.qa-company-anchor {
  position: absolute;
  left: 0;
  top: calc(100% + 4px);
  z-index: 200;
  width: 260px;
}
/* Datum-Aufklapper -- ehemals Inline-Style mit left:0 (waechst nach
   rechts aussen). Ticket 3.387-Korrektur: "Datum" ist der siebte von
   acht Toolbar-Buttons im NICHT-kompakten Slide-In-Panel (Board-Spalte/
   FAB/Kopfzeile) und sitzt damit nahe am rechten Panel-Rand -- der feste
   280px breite .datepicker-wrap ragte dort ueber die Panel-Kante hinaus
   und wurde von .ds-cal-panel{overflow:hidden} abgeschnitten (gemessen
   87px bei 1440px, 27px bei 1920px Fensterbreite). Rechts statt links am
   .qa-anchor-Button verankert waechst der Picker seither nach INNEN --
   dasselbe Prinzip wie .title-trigger-datepicker-anchor weiter unten in
   dieser Datei. Der Kompakt-Modus (s.u.) ueberschreibt left/right erneut
   fuer sein eigenes volle-Breite-Verhalten. */
.qa-datepicker-anchor {
  position: absolute;
  left: auto;
  right: 0;
  top: calc(100% + 4px);
  z-index: 200;
}
/* Mobil (.ds-cal-panel ist hier 100% Breite, s. _calendar.css) bricht
   .quick-add-toolbar auf mehrere Zeilen um -- "Datum" landet dadurch NICHT
   mehr zuverlaessig nahe am rechten Rand wie im einzeiligen Desktop-
   Toolbar. Rechts-Verankerung wuerde den 280px breiten Picker dann ueber
   den LINKEN Bildschirmrand hinausschieben (gemessen: -159px bei 390px
   Fensterbreite). Zurueck auf links-verankert -- exakt das Verhalten vor
   der 3.387-Korrektur, auf dieser Breite bereits vollstaendig sichtbar. */
@media (max-width: 900px) {
  .qa-datepicker-anchor {
    left: 0;
    right: auto;
  }
}
.quick-add-cancel {
  background: none;
  border: none;
  padding: 0 0.5rem;
  height: 32px;
  color: var(--text-secondary);
  font-size: 0.82rem;
  cursor: pointer;
}
.quick-add-cancel:hover { color: var(--text-primary); }

/* Aktions-Zeile (Ticket 3.275) -- eigene Zeile UNTER der Metadaten-Toolbar:
   Abbrechen links, Hinzufügen rechts. Trennt "Datensatz einstellen" (Toolbar
   oben, .quick-add-toolbar) von "über ihn entscheiden" (diese Zeile) --
   beide Knöpfe steckten vorher als erstes/letztes Kind IN der umbrechenden
   Toolbar, ihre Position war reine Folge des Umbruchs statt einer echten
   Festlegung. justify-content:space-between reicht bei genau zwei Kindern
   (kein .ds-toolbar-spacer nötig). Gilt unverändert im Kompakt-Modus (Board-
   Spalte) -- keine .compact-Overrides nötig, beide Buttons bleiben kurz
   genug für die schmalste Spaltenbreite. */
.quick-add-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
}
.quick-add-dropdown {
  position: absolute;
  left: 0;
  top: calc(100% + 2px);
  z-index: 200;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  min-width: 200px;
  max-width: 320px;
  max-height: 240px;
  overflow-y: auto;
  padding: 0.25rem 0;
}
.quick-add-dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.75rem;
  font-size: 0.82rem;
  cursor: pointer;
  color: var(--text-secondary);
  transition: background var(--transition);
}
.quick-add-dropdown-item:hover,
.quick-add-dropdown-item.highlighted {
  background: var(--accent-light);
  color: var(--accent);
}
.priority-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.mention-section-header {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--text-tertiary);
  padding: 0.4rem 0.75rem 0.2rem;
  letter-spacing: 0.04em;
}
/* Beschreibungsfeld (Ticket 3.19.21 / T2) -- kompaktere Variante der
   generischen .ds-rich-editor-body (_core.css, 120-280px), passend
   zur "schnellen" Erfassungs-Leiste. Ursprünglich Scoped Override im
   Component-lokalen <style>-Tag, seit Ticket 3.85 Paket 2 hierher nach
   _todos.css ausgelagert (s. Datei-Kopf).
   Ticket 3.163.4 / T7: wächst mit dem Inhalt (overflow-y:auto kommt
   bereits aus der Basisklasse, hier unverändert), Obergrenze auf
   die halbe Fensterhöhe angehoben (vorher fix 160px) -- danach
   scrollt das Feld selbst statt das ganze Formular zu sprengen. */
.quick-add-desc-wrap {
  margin: 0.375rem 0 0.125rem;
}
.quick-add-desc-wrap .ds-rich-editor-body {
  min-height: 56px;
  max-height: 50vh;
}
.quick-add-desc-wrap .ql-editor {
  min-height: 56px;
  font-size: 0.8125rem;
}

/* ── Kompakt-Modus (.compact-Property, Backlog-Gruppenende) ───────
   Normal hängt ein Aufklapp-Menü (Typ/Etikett/Datum) an seinem
   EIGENEN Toolbar-Button (.qa-anchor, position:relative) und ist
   daher bis zu 200-320px breit -- in einer schmalen Karte ragt das
   über den Rand hinaus (bzw. beim Datum-Picker sogar der 280px feste
   ds-todo-datepicker). Der Kompakt-Modus hebt die Positionierung des
   einzelnen Buttons auf (position:static) -- das Menü fällt dadurch
   auf den nächsten positionierten Vorfahren zurück (.quick-add-wrap
   selbst, volle Breite) und wird unterhalb der GESAMTEN Toolbar als
   volle Breite eingeblendet statt direkt unter dem Button. Bei
   .compact=false (Default, alle Nicht-Backlog-Einbindungen) greift
   keine dieser Regeln. Seit Ticket 3.387 nur noch von
   ds-todo-backlog.js genutzt (Quick-Add am Gruppenende) -- die
   Board-Spalte öffnet Aufgabe-hinzufügen seither als Slide-In-Panel
   (page-todos.js._openNewTodoPanel(), kein Inline-Formular mehr,
   s. .board-col-add-trigger weiter unten). */
.quick-add-wrap.compact .qa-anchor {
  position: static;
}
.quick-add-wrap.compact .quick-add-dropdown {
  left: 0;
  right: 0;
  min-width: 0;
  max-width: none;
  width: auto;
}
.quick-add-wrap.compact .qa-datepicker-anchor {
  /* left:auto/right:0 der Basisregel (s.o.) wieder aufheben -- der
     Kompakt-Modus braucht den Anker ueber die VOLLE Breite gespannt
     (left:0 UND right:0), da ds-todo-datepicker/.datepicker-wrap hier
     auf width:100% gesetzt sind (s.u.), nicht auf die feste 280px. */
  left: 0;
  right: 0;
}
.quick-add-wrap.compact .qa-datepicker-anchor ds-todo-datepicker {
  display: block;
  width: 100%;
}
.quick-add-wrap.compact .qa-datepicker-anchor .datepicker-wrap {
  width: 100%;
}
.quick-add-wrap.compact .qa-company-anchor {
  right: 0;
  width: auto;
}

/* ── aus ds-todo-datepicker.js (3.85 Paket 2) ── */
.datepicker-wrap {
  width: 280px;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  font-size: 0.82rem;
}
.datepicker-text-input {
  width: 100%;
  border: none;
  border-bottom: 1px solid var(--border);
  padding: 0.625rem 0.75rem;
  font-size: 0.82rem;
  background: var(--bg-secondary);
  color: var(--text-primary);
  outline: none;
  box-sizing: border-box;
}
.datepicker-quick {
  border-bottom: 1px solid var(--border);
}
.datepicker-quick-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.45rem 0.75rem;
  cursor: pointer;
  color: var(--text-secondary);
  transition: background var(--transition);
}
.datepicker-quick-row:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.datepicker-quick-day {
  color: var(--text-tertiary);
  font-size: 0.75rem;
}
.datepicker-cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0.75rem;
  font-weight: 600;
}
.datepicker-cal-nav {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-secondary);
  padding: 0.2rem 0.4rem;
  border-radius: var(--radius-sm);
  font-size: 1rem;
}
.datepicker-cal-nav:hover { background: var(--bg-secondary); }
.datepicker-cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0;
  padding: 0 0.5rem 0.5rem;
}
.datepicker-cal-dow {
  text-align: center;
  font-size: 0.7rem;
  color: var(--text-tertiary);
  padding: 0.2rem;
  font-weight: 600;
}
.datepicker-cal-day {
  text-align: center;
  padding: 0.3rem;
  cursor: pointer;
  border-radius: var(--radius-sm);
  position: relative;
  color: var(--text-primary);
  transition: background var(--transition);
  font-size: 0.8rem;
}
.datepicker-cal-day:hover { background: var(--bg-secondary); }
.datepicker-cal-day.today::after {
  content: '';
  position: absolute;
  bottom: 2px;
  left: 50%;
  transform: translateX(-50%);
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--accent);
}
.datepicker-cal-day.selected {
  background: var(--accent);
  color: white;
  font-weight: 600;
}
.datepicker-cal-day.selected::after { display: none; }
.datepicker-cal-day.past { color: var(--text-tertiary); }
.datepicker-cal-day.empty { cursor: default; }
.datepicker-footer {
  border-top: 1px solid var(--border);
}
.datepicker-footer-btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.5rem 0.75rem;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 0.82rem;
  color: var(--text-secondary);
  text-align: left;
  transition: background var(--transition);
}
.datepicker-footer-btn:hover { background: var(--bg-secondary); }
.datepicker-time-input {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.25rem 0.5rem;
  font-size: 0.82rem;
  background: var(--bg-primary);
  color: var(--text-primary);
  margin-left: auto;
  /* Ticket 3.276-Nachtrag: 80px schnitt die zweite Minuten-Ziffer des
     nativen <input type="time"> ab (Chrome zeigt den Widget-Inhalt bei
     zu wenig Platz nicht verkleinert, sondern clippt ihn) -- 100px zeigt
     "HH:MM" + eingebautes Uhr-Icon vollstaendig, per Screenshot-Messung
     verifiziert (90px reichte bereits knapp, 100px mit Sicherheitsabstand
     fuer abweichende OS-/Locale-Rendergroessen). flex-shrink:0 verhindert,
     dass der Flex-Footer das Feld bei wenig Platz zurueck auf die
     Browser-Minimalgroesse quetscht. */
  width: 100px;
  flex-shrink: 0;
}

/* ── aus ds-todo-api-keys.js (3.85 Paket 2) ── */
.todo-api-newkey-card { border: 2px solid var(--teal); margin-bottom: 1.5rem; }
.todo-api-newkey-title { font-weight: 600; margin-bottom: 0.5rem; }
.todo-api-newkey-code {
  display: block;
  background: var(--bg-secondary);
  padding: 0.75rem;
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  word-break: break-all;
  margin-bottom: 0.75rem;
}
.todo-api-newkey-warn { color: var(--amber); font-size: 0.875rem; margin-top: 0.75rem; }
.todo-api-newkey-close-btn { margin-top: 1rem; width: 100%; }
.todo-api-copy-icon { margin-right: 0.25rem; }

.todo-api-scopes { margin-top: 1rem; }
.todo-api-scope-row { display: flex; align-items: flex-start; gap: 0.75rem; padding: 0.5rem 0.25rem; }
.todo-api-scope-row + .todo-api-scope-row { border-top: 1px solid var(--border); }
.todo-api-scope-text { display: flex; flex-direction: column; gap: 0.1rem; }
.todo-api-scope-label { font-weight: 600; font-size: 0.875rem; color: var(--text-primary); }
.todo-api-scope-desc { font-size: 0.78rem; color: var(--text-secondary); }
.todo-api-scope-warn { color: var(--coral); font-size: 0.8rem; margin: 0.5rem 0.25rem 0; }
.todo-api-scope-hint {
  color: var(--text-tertiary);
  font-size: 0.78rem;
  margin: 0.75rem 0.25rem 0;
  padding-top: 0.5rem;
  border-top: 1px dashed var(--border);
}
.todo-api-scope-none { color: var(--text-tertiary); }
.todo-api-scope-badges { display: flex; flex-wrap: wrap; gap: 0.25rem; }

.todo-api-docs { margin-top: 1.5rem; }
.todo-api-docs-summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--text-primary);
  padding: 0.25rem 0;
}
.todo-api-docs-summary::-webkit-details-marker { display: none; }
.todo-api-docs-summary-chevron {
  transition: transform var(--transition);
  flex-shrink: 0;
  color: var(--text-tertiary);
}
.todo-api-docs[open] .todo-api-docs-summary-chevron { transform: rotate(90deg); }
.todo-api-docs-body { margin-top: 1rem; display: flex; flex-direction: column; gap: 1.25rem; }
.todo-api-docs-section-title {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
  margin: 0 0 0.5rem;
}
.todo-api-docs-text { font-size: 0.875rem; color: var(--text-secondary); line-height: 1.55; margin: 0 0 0.5rem; }
.todo-api-docs-text code {
  background: var(--bg-secondary);
  padding: 0.1rem 0.35rem;
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
}
.todo-api-docs-table-wrap { margin: 0 0 0.5rem; }
.todo-api-docs-table-wrap code { font-size: 0.8125rem; }
.todo-api-docs-rejected { margin-top: 0.5rem; font-size: 0.8125rem; line-height: 1.6; }
.todo-api-docs-rejected code {
  background: var(--bg-primary);
  padding: 0.1rem 0.35rem;
  border-radius: var(--radius-sm);
  font-size: 0.78rem;
}
.todo-api-docs-example { margin-top: 0.75rem; }
.todo-api-docs-example-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.35rem;
}
.todo-api-docs-example-label { font-size: 0.8125rem; font-weight: 600; color: var(--text-primary); }
.todo-api-docs-pre {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.75rem;
  font-size: 0.78rem;
  line-height: 1.5;
  overflow-x: auto;
  white-space: pre;
  margin: 0;
}
@media (max-width: 900px) {
  .todo-api-docs-example-head { flex-wrap: wrap; gap: 0.5rem; }
}

/* ── aus _todo-description-format.js (3.85 Paket 2) ──────────────────────
   Kein <style>-Block in dieser Datei -- reine Formaterkennungs-Logik
   (HTML- vs. Markdown-Erkennung der Todo-Beschreibung), kein CSS.
   Nichts zu verschieben. */

/* ── aus ds-todo-project-nav.js (3.85 Paket 2) ── */
.todo-nav-sidebar {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0.5rem 0;
  overflow-y: auto;
  height: 100%;
}
.todo-nav-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.75rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.875rem;
  color: var(--text-secondary);
  transition: background var(--transition), color var(--transition);
  margin: 0 0.25rem;
  user-select: none;
}
.todo-nav-item:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.todo-nav-item.active {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
}
.todo-nav-icon {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  width: 18px;
}
.todo-nav-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.todo-nav-section-title {
  padding: 0.75rem 1rem 0.25rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.todo-nav-section-title:not(:first-child) {
  border-top: 1px solid var(--border);
  margin-top: 0.5rem;
}
.todo-nav-project-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.75rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.875rem;
  font-family: inherit;
  color: var(--text-secondary);
  transition: background var(--transition), color var(--transition);
  margin: 0 0.25rem;
  user-select: none;
  background: transparent;
  border: none;
  text-align: left;
  width: 100%;
}
.todo-nav-project-row:hover {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.todo-nav-project-row.active {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
}
/* Farbpunkt in der Projekt-Zeile (Nutzer-Feedback #5 — linksbündig,
   analog .notes-ws-dot). Reines Anzeige-Element, nicht klickbar
   (Farbe ändern jetzt über das Bearbeiten-Panel, s. Pencil unten —
   kein verschachteltes <button> mehr im Filter-Button möglich). */
.todo-nav-project-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
/* Eigenes Tastenkürzel je Projekt (Ticket 3.197.6) -- dezenter Hinweis
   hinter dem Namen, Text-Konvention "Alt+X" identisch zum bestehenden
   title-Tooltip dieser Zeile ("Alt+↑/↓ blättert durch die Projekte"),
   NICHT das Mac-Symbol "⌥" (P-5 -- ein Wechsel der Schreibweise
   innerhalb derselben Datei wäre ein zweites Vokabular für dasselbe
   Konzept). */
.todo-nav-shortcut-badge {
  flex-shrink: 0;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--text-tertiary);
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
  padding: 0.05rem 0.35rem;
  white-space: nowrap;
}
.todo-nav-chevron {
  display: flex;
  align-items: center;
  width: 16px;
  flex-shrink: 0;
  color: var(--text-tertiary);
  transition: transform var(--transition);
}
.todo-nav-chevron.expanded {
  transform: rotate(90deg);
}
.todo-nav-add-btn {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.75rem;
  font-size: 0.8rem;
  color: var(--text-tertiary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  margin: 0 0.25rem;
  transition: color var(--transition), background var(--transition);
  user-select: none;
  background: none;
  border: none;
}
.todo-nav-add-btn:hover {
  color: var(--accent);
  background: var(--accent-light);
}
/* Farbpalette — Stil angelehnt an calendar-categories */
.todo-nav-color-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  width: 100%;
  padding: 0.4rem 0 0.2rem;
}
.todo-nav-inline-add {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.75rem;
  margin: 0 0.25rem;
}
.todo-nav-inline-add input {
  flex: 1;
  font-size: 0.8rem;
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-primary);
  outline: none;
}
.todo-nav-inline-add input:focus {
  border-color: var(--accent);
}
.todo-nav-inline-add button {
  font-size: 0.75rem;
  padding: 0.2rem 0.5rem;
}
.label-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
/* Projekt-Zeile: Griff (Drag) + Filter-Button + Bearbeiten-Pencil als
   Geschwister (kein verschachteltes <button>) — 1:1 Look&Feel-
   Angleichung an .notes-sidebar-item-row (pages/notes.js), Nutzer-
   Feedback #5. Nur Top-Level-Projekte tragen die Drag-Handler
   (s. JS-Kommentar „Reusability P-8"). */
.todo-nav-project-row-wrap {
  display: flex;
  align-items: center;
  gap: 0.125rem;
  margin: 0 0.25rem;
  touch-action: pan-y;
}
.todo-nav-project-row-wrap .todo-nav-project-row {
  flex: 1;
  min-width: 0;
  margin: 0;
}
.todo-nav-drag-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.125rem;
  height: 1.75rem;
  flex-shrink: 0;
  color: var(--text-tertiary);
  cursor: grab;
}
.todo-nav-project-row-wrap.is-dragging {
  opacity: 0.45;
  cursor: grabbing;
}
.todo-nav-project-row-wrap.is-dragging .todo-nav-drag-handle {
  cursor: grabbing;
}
.todo-nav-project-row-wrap.is-drop-target {
  position: relative;
}
.todo-nav-project-row-wrap.is-drop-target::before {
  content: '';
  position: absolute;
  left: 0.25rem;
  right: 0.25rem;
  top: -2px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
}
.todo-nav-project-edit-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  background: none;
  border: none;
  color: var(--text-tertiary);
  cursor: pointer;
  padding: 0;
  transition: background var(--transition), color var(--transition);
}
.todo-nav-project-edit-btn:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}
/* Papierkorb-Zähler-Badge (Ticket 3.207 Runde B) — neben dem
   "Papierkorb"-Link in der Verwaltung-Sektion; die Zeilen-Liste
   selbst (Restore/Purge je Eintrag) lebt jetzt auf der eigenen
   Trash-Seite (page-todos.js), hier bleibt nur der Zähler. */
.todo-nav-trash-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.125rem;
  height: 1.125rem;
  padding: 0 0.3rem;
  margin-left: 0.25rem;
  border-radius: 999px;
  background: var(--bg-tertiary);
  color: var(--text-tertiary);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: normal;
  text-transform: none;
  vertical-align: middle;
}
.todo-nav-template-row {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  width: 100%;
  padding-top: 0.25rem;
}
.todo-nav-template-label {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
  flex-shrink: 0;
}
.todo-nav-template-select {
  flex: 1;
  font-size: 0.75rem;
  padding: 0.2rem 0.375rem;
  min-width: 0;
}
@media (max-width: 900px) {
  .todo-nav-project-edit-btn,
  .todo-nav-drag-handle {
    display: flex;
  }
}

/* ── aus _todo-quick-menu.js (QUICK_MENU_CSS, 3.85 Paket 3) ────────────────
   Sonderfall wie TODO_STATUS_CSS oben (Paket 2): _todo-quick-menu.js hatte
   KEINEN eigenen <style>-Block (Plain-JS-Modul, kein Custom Element),
   sondern exportierte diese Regeln als CSS-String-Konstante QUICK_MENU_CSS.
   Interpoliert wurde sie EINZIG von ds-todo-item.js -- dort zweimal, je
   einmal im Listen- und im Board-Karten-<style>-Block.
   🔒 Seit Ticket 3.85 Paket 5 ist ds-todo-item.js vollständig auf diese
   Sektion migriert (ihr eigenes CSS liegt seither im Abschnitt "aus
   ds-todo-item.js" weiter unten und referenziert die Regeln HIER statt sie
   erneut zu kopieren) -- sie war der letzte Interpolator (grep-geprüft),
   der Export QUICK_MENU_CSS in _todo-quick-menu.js ist deshalb ERSATZLOS
   entfernt. Diese Regeln sind damit die EINZIGE verbliebene Kopie, nicht
   mehr Spiegel eines JS-Exports. */
.todo-menu-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
/* „Neue Etikett anlegen"-Zeile im Etiketten-Flyout (Ticket 3.84.18) --
   lebt als Flyout-Kind in ds-context-menu.js, das body-level rendert
   (außerhalb dieser Component). Diese Regeln müssen global gelten,
   genau wie .todo-menu-dot oben (kein Shadow-DOM, s. base-component.js). */
.todo-menu-label-create-row {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  width: 100%;
}
/* min-width:190px (statt frei schrumpfend via flex:1) mildert einen
   bestehenden Bug in ds-context-menu.js (core/, außerhalb dieses
   Datei-Scopes, daher hier NUR gemildert statt behoben -- s. Erfolgsreport
   Ticket 3.84.18): Text, der über die sichtbare Eingabefeld-Breite hinaus
   wächst, lässt den Browser den INTERNEN Textbereich des <input>
   scrollen -- das feuert nativ ein 'scroll'-Event AUF DEM INPUT SELBST,
   welches vom app-weiten window.addEventListener('scroll', _close, true)
   in ds-context-menu.js (schließt das Menü bei Seiten-Scroll) FÄLSCHLICH
   mitgefangen wird und das GESAMTE Kontextmenü während des Tippens
   schließt. Breiter = höhere Zeichen-Schwelle bis der Bug greift (~7 auf
   ~21 Zeichen empirisch verifiziert), behebt die Ursache aber NICHT. */
.todo-menu-label-create-input {
  flex: 1;
  min-width: 190px;
  font-size: 0.8125rem;
  cursor: text;
}
.todo-menu-label-create-ok {
  flex-shrink: 0;
}
/* Auf schmalen Screens rendert ds-context-menu.js Untermenüs als Inline-
   Accordion (eingerückt, volle verfügbare Breite statt Flyout) -- der
   190px-Floor oben sprengt dort die schmale Accordion-Breite und schiebt
   das Feld aus dem Viewport (per Puppeteer-Screenshot verifiziert). Auf
   schmalen Screens wieder frei schrumpfen lassen -- deckungsgleicher
   Breakpoint zu ds-context-menu.js _isNarrowScreen(). */
@media (max-width: 480px) {
  .todo-menu-label-create-input { min-width: 0; }
}

/* ── aus ds-todo-reporting.js (3.85 Paket 4) ── */
.report-wrap { padding: 0 0 2rem; }

.report-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .75rem;
  margin-bottom: .75rem;
}
.report-window-hint {
  font-size: .8125rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* Additiver Ladezustand (Muster ds-todo-list-view.js
   ".todo-list-loadbar", T1/Befund B1 — kein Template-Zweigwechsel
   beim Laden, nur Optik). */
.report-loadbar {
  height: 2px;
  overflow: hidden;
  position: relative;
  background: transparent;
  border-radius: 2px;
  margin-bottom: .75rem;
}
.report-loadbar.is-active { background: var(--accent-light); }
.report-loadbar.is-active::after {
  content: '';
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 35%;
  background: var(--accent);
  border-radius: 2px;
  animation: report-loadbar-sweep 1.1s ease-in-out infinite;
}
@keyframes report-loadbar-sweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(385%); }
}

.report-body { transition: opacity var(--transition); }
.report-body.is-dimmed { opacity: .55; pointer-events: none; }

.report-refresh-error {
  margin: 0 0 .75rem;
  padding: .5rem .75rem;
  border-radius: var(--radius-sm);
  background: var(--coral-light);
  color: var(--coral);
  font-size: .8125rem;
}
.report-hint-line, .report-empty-note {
  margin: 0 0 .75rem;
  font-size: .8125rem;
  color: var(--text-tertiary);
}
.report-empty-note { font-style: italic; }

/* Die 5 Kennzahlen-Kacheln stehen seit der 3.216.1-Nachschärfung (Review-
   Feedback Domenico: "die ersten 5 kacheln ... oben in einer Zeile") als
   EIGENE volle Zeile ÜBER dem Zweispalter, nicht mehr in dessen rechter
   Spalte. auto-fit(minmax(200px,1fr)) verhindert horizontalen Überlauf
   strukturell (Spaltenzahl wird aus der verfügbaren Breite berechnet, nie
   fest vorgegeben) und liefert auf mittleren Breiten (~1024px) automatisch
   einen 2+3-Umbruch statt eines Überlaufs. */
.report-tiles-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: .875rem;
  margin-bottom: 1.5rem;
}

/* Verlauf links, Aufschlüsselung rechts daneben (Ticket 3.216.1)
   — nur ab 900px (Modul-Breakpoint); darunter fällt die Grid-Spalte
   auf 1 zusammen, die "order"-Werte (s. Media-Query am Ende dieses
   Blocks) stellen dort die ursprüngliche Lesereihenfolge (Aufschlüsselung
   → Verlauf) wieder her statt "Verlauf zuerst" — die Kacheln-Zeile selbst
   steht immer schon VOR diesem Zweispalter (kein order nötig). */
.report-two-col {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: start;
  gap: .875rem;
}
.report-col-history, .report-col-stats { min-width: 0; }
.report-tile { padding: 1rem 1.125rem; }
.report-tile-label {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-weight: 600;
  color: var(--text-tertiary);
  margin-bottom: .4rem;
}
.report-tile-value {
  font-size: 1.65rem;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.report-tile-value--empty { color: var(--text-tertiary); }
.report-tile-sub {
  margin-top: .3rem;
  font-size: .8125rem;
  color: var(--text-secondary);
}
.report-tile-hint {
  margin-top: .3rem;
  font-size: .7rem;
  color: var(--text-tertiary);
}

.report-tile-compare {
  margin-top: .5rem;
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
}
.report-tile-compare-text { font-size: .75rem; color: var(--text-tertiary); }

.report-delta {
  display: inline-flex;
  align-items: center;
  gap: .2rem;
  padding: .1rem .45rem;
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.report-delta.is-up   { color: var(--teal);         background: var(--teal-light); }
.report-delta.is-down { color: var(--coral);        background: var(--coral-light); }
.report-delta.is-flat { color: var(--text-tertiary); background: var(--bg-tertiary); }

.report-tile-flow-row { display: flex; align-items: center; gap: .625rem; }
.report-tile-flow-item { display: flex; flex-direction: column; align-items: center; gap: .1rem; }
.report-tile-flow-value {
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.report-tile-flow-caption { font-size: .68rem; color: var(--text-tertiary); }
.report-tile-flow-sep { color: var(--text-tertiary); flex-shrink: 0; display: flex; }

.report-breakdown-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: .875rem;
}
.report-breakdown-card { padding: .875rem 1rem 1rem; }
.report-breakdown-title {
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: .625rem;
}
.report-breakdown-empty {
  margin: 0;
  font-size: .8125rem;
  color: var(--text-tertiary);
  font-style: italic;
}
.report-breakdown-list { display: flex; flex-direction: column; gap: .55rem; }
.report-breakdown-row-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  margin-bottom: .25rem;
}
.report-breakdown-row-label {
  font-size: .82rem;
  color: var(--text-primary);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.report-breakdown-row-values {
  display: flex;
  align-items: baseline;
  gap: .4rem;
  flex-shrink: 0;
}
.report-breakdown-row-count {
  font-size: .78rem;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.report-breakdown-row-pct {
  font-size: .72rem;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
  min-width: 2.6em;
  text-align: right;
}
.report-breakdown-note {
  margin: 0 0 .5rem;
  font-size: .72rem;
  color: var(--text-tertiary);
  font-style: italic;
}
.report-breakdown-bar-track {
  height: 6px;
  border-radius: 3px;
  background: var(--bg-tertiary);
  overflow: hidden;
}
.report-breakdown-bar-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
  transition: width .25s ease;
}

/* ── Verlaufs-Diagramm ── */
.report-history-card {
  margin-bottom: 1.5rem;
  padding: 1rem 1.125rem 1.25rem;
}
.report-history-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-bottom: .75rem;
}
.report-history-legend-item {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .78rem;
  color: var(--text-secondary);
}
.report-history-legend-swatch {
  width: 13px;
  height: 13px;
  border-radius: 3px;
  flex-shrink: 0;
}
.report-history-legend-swatch--solid { background: var(--teal); }
.report-history-legend-swatch--hatch {
  border: 1px solid var(--accent);
  background: repeating-linear-gradient(45deg, var(--accent) 0 2px, var(--accent-light) 2px 5px);
}
.report-history-chart-wrap { margin-bottom: .875rem; }
/* Natürliche Breite aus der Geometrie (style="width:…px" je Render,
   s. _renderHistorySvg) statt erzwungenem width:100% — sonst zieht
   der Browser wenige Balken-Paare auf die volle Kartenbreite
   auseinander (Ticket 3.216.1). max-width:100% bleibt als
   Schrumpf-Grenze für schmale Spalten/Mobile, height:auto hält
   dabei das SVG-Seitenverhältnis (kein horizontaler Überlauf). */
.report-history-svg { display: block; max-width: 100%; height: auto; }
.report-history-table-wrap.table-wrap { margin-top: .5rem; }
.report-history-table-wrap .table { font-size: .78rem; }
.report-history-table-wrap .table th,
.report-history-table-wrap .table td { padding: .4rem .625rem; }
.report-history-table-wrap .table th:not(:first-child),
.report-history-table-wrap .table td:not(:first-child) {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.report-history-table-wrap .table tbody tr { cursor: default; }

.report-skeleton .report-tile { display: flex; flex-direction: column; gap: .5rem; }

.report-error-state {
  padding: 2.5rem 1.5rem;
  text-align: center;
  color: var(--text-tertiary);
}
.report-error-state svg { margin-bottom: .75rem; opacity: .4; }
.report-error-state p { margin: 0 0 1rem; font-size: .9rem; }

@media (max-width: 900px) {
  .report-tile-value { font-size: 1.4rem; }
  .report-two-col { grid-template-columns: 1fr; }
  .report-col-history { order: 2; }
  .report-col-stats { order: 1; }
}

/* ── aus ds-todo-project-panel.js (3.85 Paket 4) ── */
.project-panel { display:flex; flex-direction:column; gap:1.5rem; padding: 0 1.25rem 2rem; }
.project-panel h2 {
  font-size:1.25rem; margin:0; flex:1; cursor:pointer;
  padding:.25rem .5rem; border-radius: var(--radius-sm);
}
.project-panel h2:hover { background: var(--bg-tertiary); }
.project-panel-header {
  display:flex; align-items:center; gap:.5rem; margin-top:.5rem;
}
.project-panel-progress-bar {
  height: 6px; border-radius: 3px;
  background: var(--bg-tertiary); overflow:hidden;
}
.project-panel-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--teal));
  transition: width .2s ease;
}
.project-panel-meta {
  display:flex; flex-direction:column; gap:.25rem;
}
.project-panel-row {
  display:flex; align-items:center; gap:.75rem;
  padding:.5rem .5rem; border-radius: var(--radius-sm);
  cursor:pointer; transition: background var(--transition);
}
.project-panel-row:hover { background: var(--bg-tertiary); }
.project-panel-row-label {
  width: 110px; font-size:.8rem; color: var(--text-tertiary);
  flex-shrink: 0;
}
.project-panel-row-value {
  flex: 1; font-size: .9rem; color: var(--text-primary);
  display:flex; align-items:center; gap:.5rem; min-width:0;
}
.project-panel-row-value.placeholder { color: var(--text-tertiary); font-style: italic; }
.project-panel-stats {
  display:grid; grid-template-columns: repeat(4, 1fr); gap:.75rem;
}
.project-panel-stat {
  padding:.75rem; border-radius: var(--radius-md);
  background: var(--bg-tertiary); text-align:center;
}
.project-panel-stat-val { font-size:1.25rem; font-weight:600; color: var(--text-primary); }
.project-panel-stat-lab { font-size:.75rem; color: var(--text-tertiary); margin-top:.15rem; }
.project-panel-section-title {
  font-size: .75rem; font-weight: 600; text-transform: uppercase;
  color: var(--text-tertiary); letter-spacing: .05em;
  margin-bottom: .5rem;
}
.project-panel-chip {
  display:inline-flex; align-items:center; gap:.35rem;
  padding:.2rem .6rem; border-radius: 999px;
  background: var(--accent-light); color: var(--accent);
  font-size: .825rem;
}
.project-panel-chip .chip-clear {
  cursor: pointer; opacity: .6; margin-left: .15rem;
}
.project-panel-chip .chip-clear:hover { opacity: 1; }
/* Verknüpfungs-Fieldset */
.project-panel-relations { display:flex; flex-direction:column; gap:.125rem; }
.project-panel-relation-row {
  display:flex; align-items:flex-start; gap:.75rem;
  padding:.5rem .5rem; border-radius: var(--radius-sm);
}
.project-panel-relation-icon {
  width:20px; flex-shrink:0; margin-top:.35rem;
  color: var(--text-tertiary); display:flex; align-items:center;
}
.project-panel-relation-field { flex:1; min-width:0; }
/* User-Picker Dropdown */
.project-panel-user-picker { position:relative; flex:1; }
.project-panel-user-list {
  position:absolute; top:100%; left:0; right:0; z-index:50;
  background:var(--bg-primary); border:1px solid var(--border);
  border-radius:var(--radius-sm); margin-top:2px;
  max-height:200px; overflow-y:auto; box-shadow:var(--shadow-md);
}
.project-panel-user-item {
  padding:.5rem .75rem; cursor:pointer; font-size:.85rem;
}
.project-panel-user-item:hover { background:var(--bg-tertiary); }
/* Dokumenten-Anhänge */
.project-panel-attach-header {
  display:flex; align-items:center; justify-content:space-between;
  margin-bottom:.5rem;
}
.project-panel-attach-add {
  display:inline-flex; align-items:center; gap:.35rem;
  font-size:.8rem; color: var(--accent); cursor:pointer;
  background:none; border:none; padding:.15rem .4rem;
  border-radius: var(--radius-sm); transition: background var(--transition);
}
.project-panel-attach-add:hover { background: var(--accent-light); }
.project-panel-attach-add:disabled { opacity:.5; cursor:default; pointer-events:none; }
.project-panel-attach-list {
  display:flex; flex-direction:column; gap:.25rem;
}
.project-panel-attach-row {
  display:flex; align-items:center; gap:.5rem;
  padding:.4rem .5rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--bg-primary);
  transition: background var(--transition);
}
.project-panel-attach-row:hover { background: var(--bg-tertiary); }
.project-panel-attach-icon { color: var(--text-tertiary); flex-shrink:0; display:flex; }
.project-panel-attach-name {
  flex:1; min-width:0; font-size:.85rem; color: var(--text-primary);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.project-panel-attach-size { font-size:.75rem; color: var(--text-tertiary); flex-shrink:0; }
.project-panel-attach-actions { display:flex; gap:.15rem; flex-shrink:0; }
.project-panel-attach-btn {
  width:26px; height:26px; display:flex; align-items:center; justify-content:center;
  background:none; border:none; border-radius: var(--radius-sm);
  color: var(--text-tertiary); cursor:pointer; transition: all var(--transition);
}
.project-panel-attach-btn:hover { background: var(--bg-tertiary); color: var(--text-primary); }
.project-panel-attach-btn.is-danger:hover { background: var(--coral-light); color: var(--coral); }
.project-panel-attach-empty {
  font-size:.8125rem; color: var(--text-tertiary); font-style: italic;
  padding:.35rem .5rem;
}

/* ── aus ds-todo-item.js (3.85 Paket 5) ────────────────────────────────────
   Einzelne Todo-Zeile/-Karte -- Component rendert zwei Modi mit je einem
   eigenen <style>-Block: compact=true -> _renderListRow() (Listen-/Backlog-
   Zeile, Klassen mit den Präfixen todo-list und todo), compact=false ->
   _renderBoardCard() (Board-Karte, Klassen mit dem Präfix tbc). Reihenfolge
   innerhalb jedes Blocks ist
   unverändert zum Ursprung übernommen (List-Row-Block zuerst, danach
   Board-Karten-Block, exakt wie die beiden Render-Methoden im JS
   aufeinanderfolgen).

   Zwei der drei ehemals hier interpolierten Bausteine sind NICHT erneut
   eingefügt, weil sie bereits an anderer Stelle dieser Datei stehen (kein
   dritter Kopie-Ort):
   - ${TODO_STATUS_CSS} (Kopf jedes Blocks) -- s. Abschnitt "aus
     _todo-status.js" weiter oben (Zeile ~126). Export bleibt bestehen,
     ds-todo-detail.js (außerhalb des Datei-Scopes von Paket 5)
     interpoliert ihn weiterhin.
   - ${QUICK_MENU_CSS} (Kopf jedes Blocks) -- s. Abschnitt "aus
     _todo-quick-menu.js" weiter oben (Zeile ~835). ds-todo-item.js war der
     letzte Interpolator (grep-geprüft) -- der Export ist deshalb dort
     ERSATZLOS entfernt worden, diese Regeln sind seither die einzige Kopie.
   Der dritte Baustein, die private (nicht exportierte) JS-Konstante
   TOUCH_REVEAL_CSS, stand identisch am Ende JEDES der beiden Blöcke -- hier
   zu EINEM Block am Ende dieser Sektion zusammengefasst, s. Kommentar dort. */

/* Der Host setzt das native HTML5-draggable-Attribut DIREKT auf das
   <ds-todo-item>-Tag (Vorbild ds-todo-board-view.js:1364-1377,
   dasselbe Muster) -- daher hier ein Tag-Attribut-Selektor, nicht
   .todo-list-row[draggable]. */
ds-todo-item[draggable=true] .todo-list-row { cursor: grab; }

.todo-list-row {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  padding: 10px 16px;
  position: relative;
  background: var(--bg-primary);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  margin-bottom: 2px;
  cursor: pointer;
  transition: background var(--transition), box-shadow var(--transition);
  /* Langes Drücken (Ticket 3.213.1) darf nicht die native Text-
     Auswahl/das iOS-Callout-Menü auslösen -- kapert sonst den
     500ms-Kontextmenü-Timer (Vorbild .cal-event-block/-agenda-entry). */
  -webkit-touch-callout: none;
  user-select: none;
}
.todo-list-row:hover {
  background: color-mix(in srgb, var(--accent-light) 40%, var(--bg-primary));
  box-shadow: 0 2px 4px rgba(0,0,0,.08);
}
.todo-list-row:hover .todo-list-menu-btn { opacity: 1; }
/* Unteraufgaben-Modifier (taskKind='sub'): Einrueckung + Toenung,
   1:1 der ehemalige .bl-row.subtask-Wert. */
.todo-list-row--sub {
  margin-left: 1.75rem;
  background: color-mix(in srgb, var(--bg-tertiary) 40%, var(--bg-primary));
}
.todo-list-row.done .todo-title-text { text-decoration: line-through; color: var(--text-tertiary); }

/* Hinweiszeile ueber einer verwaisten Unteraufgabe (Ticket 3.308) -- die
   Eltern-Aufgabe ist in dieser projektuebergreifenden Flachliste nicht
   geladen, die Zeile darunter bleibt trotzdem eine ganz normale
   .todo-list-row (kein --sub-Modifier, volle Prominenz -- s. JS-Docblock
   _nestOrOrphanSubtasks()). Padding matcht die horizontalen 16px von
   .todo-list-row, damit Hinweis und Karte optisch buendig stehen. */
.todo-list-orphan-hint {
  display: flex;
  align-items: center;
  gap: .3rem;
  padding: 0 16px 2px;
  font-size: .72rem;
  color: var(--text-tertiary);
}

.todo-list-rail {
  display: flex;
  align-items: center;
  gap: .3rem;
  flex-shrink: 0;
  padding-top: 1px;
}
.todo-expand-btn {
  width: 18px; height: 18px; display: flex; align-items: center;
  justify-content: center; color: var(--text-tertiary);
  background: none; border: none; padding: 0; cursor: pointer;
  transition: transform var(--transition), color var(--transition);
}
.todo-expand-btn.open { transform: rotate(90deg); }
.todo-expand-btn:hover { color: var(--text-primary); }
.todo-expand-placeholder { width: 18px; height: 18px; flex-shrink: 0; }

.todo-checkbox {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--border);
  flex-shrink: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color var(--transition), background var(--transition);
  background: transparent;
}
/* Prioritaet als Rahmenfarbe (Ticket 3.163.6): 1=coral, 2=amber,
   3=accent, 4=keine eigene Regel -> Standardrahmen var(--border).
   MUSS vor .done stehen -- .done soll die Prioritaetsfarbe immer
   schlagen (Border UND Fuellung), nicht umgekehrt. */
.todo-checkbox.prio-1 { border-color: var(--coral); }
.todo-checkbox.prio-2 { border-color: var(--amber); }
.todo-checkbox.prio-3 { border-color: var(--accent); }
.todo-checkbox:hover { border-color: var(--teal); }
.todo-checkbox.done { background: var(--teal); border-color: var(--teal); }
.todo-checkbox.completing { opacity: 0.5; }

.todo-list-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .2rem; }

.todo-list-badge {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: 2px 8px; font-size: .72rem;
  border-radius: 4px; font-weight: 500;
  max-width: 100%;
  align-self: flex-start;
}
.todo-list-badge-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.todo-list-badge.epic { background: var(--accent-light); color: var(--accent-dark); }

.todo-title-line { display: flex; align-items: flex-start; gap: .4rem; min-width: 0; }
.todo-title-text {
  flex: 1; min-width: 0;
  font-size: .875rem; color: var(--text-primary);
  white-space: normal; word-break: break-word;
  line-height: 1.35;
}
.todo-title-text.done-text { text-decoration: line-through; color: var(--text-tertiary); }

.todo-subline { display: flex; align-items: center; gap: .4rem; min-width: 0; }

.todo-meta {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: .4rem .6rem; margin-top: .1rem;
}
.todo-subtask-counter {
  display: flex; align-items: center; gap: .25rem;
  font-size: .72rem; font-weight: 600; flex-shrink: 0;
}
/* Größenklasse (Ticket 3.206.6) -- dezentes Kürzel-Badge (S/M/L/XL). */
.todo-size-badge {
  font-size: .68rem; font-weight: 700; letter-spacing: .02em;
  padding: .05rem .35rem; border-radius: 4px;
  color: var(--text-tertiary); background: var(--bg-tertiary);
  flex-shrink: 0;
}
/* Kunde-Chip (Ticket 3.262 "Kunde je Ticket zuordnen") -- Anzeige des
   zugewiesenen Geschaeftspartners (Feld heisst in der UI bewusst "Kunde",
   die Entitaet dahinter ist der app-weite Geschaeftspartner). Position +
   Kuerzung 1:1 aus dem abgenommenen Design-Entwurf
   (.claude/design/todo-card-entwurf.html): direkt vor dem Faellig-Datum,
   kuerzt per Ellipsis, verschwindet nie durch Truncation (nur wenn kein
   Kunde gesetzt ist -- s. ds-todo-item.js _companyLabel(), kein
   reservierter Platz). */
.todo-company-chip {
  display: flex; align-items: center; gap: .25rem;
  font-size: .72rem; color: var(--text-tertiary); font-weight: 500;
  min-width: 0; max-width: 9rem;
}
.todo-company-chip svg { flex-shrink: 0; opacity: .7; }
.todo-company-chip-text {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* Projekt-Referenz (Ticket 3.308, Paket B "Projekt auf Karte und
   Listenzeile") -- NUR sichtbar wenn der Host showProject setzt (s.
   ds-todo-item.js _projectLabel()), also ausschliesslich in den
   projektuebergreifenden Flachlisten (Posteingang/Heute/Demnaechst/Alle
   Todos/Etikett) -- niemals in der Projekt-Ansicht selbst. Bewusst KEIN
   farbig gefuelltes Abzeichen wie die Epic-Ticket-Referenz-Plakette
   (.todo-epic-ticket-chip weiter unten) -- schlichter Text mit
   vorangestelltem Farbpunkt, identisch zur Projekt-Zeile der Seitenleiste
   (.todo-nav-project-dot, weiter oben in dieser Datei), damit Epic und
   Projekt nebeneinander klar unterscheidbar bleiben (design-entwurf
   .claude/design/todo-card-entwurf.html: "zwei farbige Abzeichen
   nebeneinander sind nicht unterscheidbar"). */
.todo-project-chip {
  display: flex; align-items: center; gap: .3rem;
  font-size: .72rem; color: var(--text-tertiary); font-weight: 500;
  min-width: 0; max-width: 9rem;
}
.todo-project-chip-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.todo-project-chip-text {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.todo-list-due-chip {
  display: flex; align-items: center; gap: .2rem;
  font-size: .72rem; color: var(--text-tertiary); font-weight: 500;
}
.todo-list-due-chip.overdue { color: var(--coral); font-weight: 600; }
/* Zustaendig-Chip (Ticket 3.128-Nachtrag) -- 1:1 der ehemalige
   .todo-assignee-chip-Wert, jetzt Teil der gemeinsamen Meta-Zeile. */
.todo-assignee-chip {
  font-size: .72rem; padding: .1rem .4rem; border-radius: 999px;
  background: var(--bg-tertiary); color: var(--text-secondary);
}
/* Termin-Chip (Ticket 3.128-Nachtrag) -- Spec 20260416_1100. War vorher
   inline gestylt (style="..."), jetzt als Klasse (frontend.md "CSS:
   Klassen statt Inline-Styles" -- diese Stelle wird ohnehin beruehrt). */
.todo-scheduled-chip {
  display: inline-flex; align-items: center; gap: .25rem;
  padding: 1px 6px; font-size: .72rem;
  color: var(--teal); background: var(--teal-light);
  border-radius: 999px; text-decoration: none;
}
/* Etiketten-Symbol (Ticket 3.264) -- ersetzt den vormaligen Textchip
   (.todo-label-chip + Farbpunkt in der Liste, .tbc-label in der
   Board-Karte) durch ein farbiges Etiketten-Symbol je Label (Domenico:
   "das Icon ... in der entsprechenden Farbe. Mit Mouse-Over oder Touch
   sieht man dann den Tooltip. Wuerde wenig Platz kosten, aber der
   farbliche Klecks orientiert mich"). Name kommt ausschliesslich ueber
   das title-Attribut (kein sichtbarer Text mehr) -- spart Platz, Farbe
   bleibt das alleinige Signal. EINE Klasse fuer Listen-Zeile UND
   Board-Karte (P-5, vorher zwei fast identische Chip-Definitionen);
   Symbol selbst kommt aus core/icons.js iconTag() (ebenfalls
   zusammengefuehrt mit den Kalender-Kategorien, s.
   .claude/rules/modules/todos.md "Etiketten als farbiges Symbol").
   drop-shadow(...) x2 gibt jedem Symbol einen dezenten Rand, der bei
   SEHR HELLEN Label-Farben (z.B. Pastell-Gelb) auf hellem Karten-
   Hintergrund Kontur sorgt, ohne bei normalen/dunklen Farben sichtbar
   zu werden -- folgt der Icon-Silhouette (drop-shadow statt box-shadow/
   border, die waeren rechteckig und wuerden das Symbol optisch wieder
   zu einem Chip machen). */
.todo-label-icon {
  display: inline-flex; align-items: center; flex-shrink: 0;
}
.todo-label-icon svg {
  filter: drop-shadow(0 0 .5px var(--text-tertiary)) drop-shadow(0 0 .5px var(--text-tertiary));
}
/* "+N"-Sammel-Symbol ab MAX_VISIBLE_LABELS (ds-todo-item.js) -- title
   traegt die Namen der weiteren Etiketten. Optik 1:1 an .todo-size-badge
   angelehnt (dezentes Kuerzel-Badge), nur als Pille statt Rechteck. */
.todo-label-icon-more {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 15px; height: 14px; padding: 0 .3rem;
  font-size: .62rem; font-weight: 700; line-height: 1;
  color: var(--text-tertiary); background: var(--bg-tertiary);
  border-radius: 999px; flex-shrink: 0;
}

.todo-list-menu-btn {
  width: 24px; height: 24px; display: flex;
  align-items: center; justify-content: center;
  border: none; background: none; cursor: pointer;
  color: var(--text-tertiary); border-radius: var(--radius-sm);
  opacity: 0; flex-shrink: 0; margin-left: auto;
  transition: opacity var(--transition), color var(--transition), background var(--transition);
}
.todo-list-menu-btn:hover { color: var(--text-primary); background: var(--bg-tertiary); }

/* Ziehen-Griff (rein optisch, s. dragEnabled-Property-Doc in ds-todo-item.js) --
   1:1 der ehemalige .bl-drag-handle-Wert. */
.todo-list-drag-handle {
  position: absolute;
  left: 1px; top: 50%; transform: translateY(-50%);
  width: 12px; display: flex; align-items: center; justify-content: center;
  color: var(--text-tertiary); opacity: 0; pointer-events: none;
  transition: opacity var(--transition);
}
.todo-list-row:hover .todo-list-drag-handle { opacity: .55; }
.todo-list-row.dnd-dragging    { opacity: .4; }
.todo-list-row.dnd-over-top    { box-shadow: inset 0 2px 0 0 var(--accent); }
.todo-list-row.dnd-over-bottom { box-shadow: inset 0 -2px 0 0 var(--accent); }

/* Unteraufgaben-Container: reine vertikale Stapelung, KEIN eigenes
   padding-left -- die Einrueckung kommt bereits von
   .todo-list-row--sub selbst (1:1 Backlog-Vorbild, keine doppelte
   Einrueckung). */
.todo-list-subtasks-wrap { display: flex; flex-direction: column; gap: 2px; }

@media (max-width: 900px) {
  .todo-list-row--sub { margin-left: .9rem; }
  .todo-checkbox { width: 20px; height: 20px; }
}

/* ── Board-Karte (_renderBoardCard()) ── */
.tbc-wrap {
  position: relative;
  cursor: pointer;
  display: flex;
  align-items: flex-start;
  padding: 0.5rem 0.5rem 0.5rem 0;
  min-height: 72px;
  /* Langes Drücken (Ticket 3.213.1) darf nicht die native Text-
     Auswahl/das iOS-Callout-Menü auslösen -- s. .todo-list-row. */
  -webkit-touch-callout: none;
  user-select: none;
}
/* Radius/Border/Hover kommen aus .ds-card-tile (_core.css) — dieselbe
   Optik wie die Notizen-Karten (.notes-card), s. design-system.md. */

.tbc-drag {
  opacity: 0;
  flex-shrink: 0;
  width: 18px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 3px;
  color: var(--text-tertiary);
  cursor: grab;
  transition: opacity var(--transition);
}
.tbc-wrap:hover .tbc-drag { opacity: 1; }

.tbc-check {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid;
  background: none;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 2px;
  margin-right: 0.5rem;
  cursor: pointer;
  transition: background var(--transition);
}
.tbc-check.tbc-done { opacity: 0.55; }

.tbc-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* Zeile 1: Titel + das ⋯-Menü (rechts oben — Domenico-Feedback
   2026-07-30: Zeile 2 gehoert jetzt Nummer+Zaehler, das Menü
   braucht daher wieder einen Platz und wandert zurueck in die
   Titelzeile, wie vor Spec 20260730). .tbc-title bleibt flex:1 +
   word-break:break-word (darf umbrechen), .tbc-menu ist
   flex-shrink:0 und zerreisst den Titel dadurch nicht. */
.tbc-title-row {
  display: flex;
  align-items: flex-start;
  gap: 0.35rem;
  min-width: 0;
}
.tbc-title {
  flex: 1;
  min-width: 0;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-primary);
  line-height: 1.4;
  word-break: break-word;
}
.tbc-title.tbc-done {
  text-decoration: line-through;
  color: var(--text-tertiary);
}

/* Zeile 2: links Ticketnummer (falls vorhanden), rechts der
   Unteraufgaben-Zaehler — .tbc-subtasks bekommt margin-left:auto
   und wandert damit IMMER ganz nach rechts, auch wenn die Nummer
   fehlt (kein Platzhalter nötig, kein zweiter Layout-Zweig). Die
   ganze Zeile entfaellt komplett, wenn Nummer UND Zaehler fehlen
   (kein leerer Abstand, s. Render-Bedingung im Markup). */
.tbc-subline {
  display: flex;
  align-items: center;
  min-width: 0;
  margin-top: 0.3rem;
  gap: 0.375rem;
}
.tbc-subline .tbc-subtasks { margin-left: auto; }

.tbc-subtasks {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.72rem;
  font-weight: 500;
  flex-shrink: 0;
}

.tbc-meta {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-top: auto;
  padding-top: 0.25rem;
  flex-wrap: wrap;
}
.tbc-date {
  font-size: 0.72rem;
  display: flex;
  align-items: center;
  gap: 0.2rem;
  font-weight: 500;
}
/* Kunde-Chip Board-Karte (Ticket 3.262) -- s. .todo-company-chip
   (Listenzeile) fuer die volle Begruendung, identische Optik. */
.tbc-company {
  display: flex; align-items: center; gap: .25rem;
  font-size: 0.72rem; color: var(--text-tertiary); font-weight: 500;
  min-width: 0; max-width: 9rem;
}
.tbc-company svg { flex-shrink: 0; opacity: .7; }
.tbc-company-text {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* Projekt-Referenz Board-Karte (Ticket 3.308, Paket B) -- s.
   .todo-project-chip (Listenzeile) fuer die volle Begruendung, identische
   Optik. Heute strukturell unerreichbar (Board lebt nur innerhalb EINER
   Projekt-Ansicht, s. ds-todo-item.js showProject-Property-Docblock) --
   trotzdem definiert fuer Design-Paritaet + falls eine kuenftige
   projektuebergreifende Board-Ansicht entsteht. */
.tbc-project-chip {
  display: flex; align-items: center; gap: .3rem;
  font-size: 0.72rem; color: var(--text-tertiary); font-weight: 500;
  min-width: 0; max-width: 9rem;
}
.tbc-project-chip-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.tbc-project-chip-text {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* Haertere Kuerzung auf schmalen Screens (Design-Entwurf: Telefon-
   Spezimen kuerzt staerker als Desktop) -- 🔒 Reihenfolge-Pflicht
   (frontend.md "Eine Media-Query erhoeht die Spezifitaet NICHT"): steht
   bewusst NACH beiden Basisregeln oben, nicht davor. */
@media (max-width: 900px) {
  .tbc-company, .todo-company-chip, .tbc-project-chip, .todo-project-chip { max-width: 7rem; }
}
/* Größenklasse (Ticket 3.206.6) -- dezentes Kürzel-Badge (S/M/L/XL). */
.tbc-size-badge {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: .02em;
  padding: .05rem .35rem;
  border-radius: 4px;
  color: var(--text-tertiary);
  background: var(--bg-tertiary);
  flex-shrink: 0;
}
.tbc-assignee {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.72rem;
  color: var(--text-secondary);
}
.tbc-av {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: 0.55rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
/* .tbc-label (Textchip fuer Etiketten) entfallen -- Ticket 3.264, Board-
   Karte nutzt seither dieselbe .todo-label-icon-Klasse wie die Listen-
   zeile (s. dort). Kommentarverweis "bei .tbc-label/.tbc-menu" weiter
   unten in dieser Datei bezeichnet weiterhin diese Stelle (.tbc-select). */

/* Auswahl-Checkbox der Karte (Ticket 3.260 Nachtrag 2, 2026-08-17) — nur
   gerendert waehrend der Auswahl-Modus einer Spalte aktiv ist
   (ds-todo-item.js .selectMode-Property), erste Position von .tbc-meta:
   "unten links, auf der Ebene der Status-Checkbox" (Domenico-Feedback).
   Kein reservierter Platz ausserhalb des Auswahl-Modus — die Karte
   bleibt im Ruhezustand byte-identisch, .tbc-meta ist ohnehin flex-wrap. */
.tbc-select {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  cursor: pointer;
}
.tbc-select input[type="checkbox"] {
  width: 15px; height: 15px;
  cursor: pointer;
  accent-color: var(--accent);
  border-radius: 3px;
}

.tbc-menu {
  opacity: 0;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  transition: opacity var(--transition);
}
.tbc-wrap:hover .tbc-menu { opacity: 1; }
.tbc-menu-btn {
  background: none;
  border: none;
  padding: 2px;
  cursor: pointer;
  color: var(--text-tertiary);
  border-radius: var(--radius-sm);
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
.tbc-menu-btn:hover {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}

/* Epic- und Meilenstein-Badges auf der Board-Karte
   (Spec drich_suite_project_views.md – Teil 2 / Schritt 10) */
.tbc-epic-badge, .tbc-ms-badge {
  display: inline-flex; align-items: center; gap: .25rem;
  max-width: 100%;
  padding: .08rem .4rem; border-radius: 999px;
  font-size: .68rem; font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  margin-bottom: .2rem;
}
.tbc-epic-badge { background: var(--accent-light); color: var(--accent-dark); }
.tbc-ms-badge   { background: var(--bg-tertiary);  color: var(--text-secondary); font-size: .64rem; }
.tbc-epic-dot {
  width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;
}

/* Epic-Ticket-Referenz-Plakette (Ticket 3.261.3, Epics P3) -- zeigt am
   rechten Rand der Symbol-/Status-Zeile (.todo-meta / .tbc-meta), zu
   welchem Epic-Ticket (todos.epic_id) eine Aufgabe gehoert. Geteilte Klasse
   fuer BEIDE Rendermodi von ds-todo-item.js (analog .ds-ticket-badge, das
   ebenfalls list-row UND board-card gemeinsam nutzen). NICHT zu verwechseln
   mit .todo-list-badge.epic/.tbc-epic-badge weiter oben (aelteres,
   unabhaengiges Gruppen-System todo_groups.type='epic', oberhalb des
   Titels) -- beide koennen laut ds-todo-detail.js-Sidebar-Kommentar
   ("Epic-Ticket") gleichzeitig sichtbar sein, sind aber bewusst
   unterschiedlich positioniert/gestylt, damit sie nicht verwechselt werden.
   Farbe kommt als Hex ueber --epic-badge-bg/--epic-badge-fg (dieselben
   Custom-Property-Namen wie .ds-ticket-badge--epic weiter unten in dieser
   Datei) -- Kontrastfarbe ueber epicContrastFg() (WCAG-Rechnung, s.
   ds-todo-item.js Kopf-Kommentar), nicht fest verdrahtet. Kein Epic-Verweis
   -> das Element wird gar nicht gerendert (kein reservierter Platz, s.
   ds-todo-item.js epicRefBadge-Berechnung). Kuerzung rein ueber CSS
   (max-width + ellipsis) -- der volle Name steht im title-Attribut.
   🔒 Seit 17.08.2026 (Domenico-Entscheidung): der sichtbare NUTZERTEXT fuer
   dieses Feld heisst schlicht "Epic", nicht mehr "Epic-Ticket" -- der Zusatz
   war nur eine vorsorgliche Abgrenzung zum alten Gruppen-Epic
   (todo_groups.type='epic'), dessen einziger Bestandsdatensatz von Domenico
   selbst geraeumt wird. Code-Bezeichner (Klassen-/Variablennamen, Kommentare
   in dieser Datei) behalten "Epic-Ticket" zur technischen Unterscheidung --
   nur der User-facing Text wurde geaendert. Beim Aufraeumen NICHT erneut
   umbenennen. */
.todo-epic-ticket-chip {
  display: inline-flex; align-items: center;
  max-width: 9rem; min-width: 0;
  padding: 1px 8px; border-radius: 999px;
  font-size: .68rem; font-weight: 600;
  font-family: inherit;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background: var(--epic-badge-bg, var(--bg-tertiary));
  color: var(--epic-badge-fg, var(--text-tertiary));
  flex-shrink: 1;
  margin-left: auto;
  /* Seit Ticket 3.261.4: <button> statt <span> -- oeffnet das verlinkte
     Epic-Ticket per Klick (ds-todo-item.js::_openEpicRef()), auch wenn
     dessen eigene Karte gerade ausgeblendet ist (todo_projects.show_epics). */
  border: none; cursor: pointer;
}
.todo-epic-ticket-chip:hover {
  filter: brightness(0.92);
}
.todo-epic-ticket-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* 🔒 Touch-Geraete: Hover-Reveal (.todo-list-menu-btn / .tbc-menu) ist auf
   einem Finger nicht zuverlaessig ausloesbar — dauerhaft sichtbar, analog
   ds-todo-board-view.js .board-col-menu-wrap. War in ds-todo-item.js als
   private JS-Konstante TOUCH_REVEAL_CSS je EINMAL am Ende JEDES der beiden
   <style>-Bloecke (List-Row- UND Board-Karten-Modus) interpoliert --
   identischer Inhalt an beiden Stellen, hier zu EINEM Block zusammengefasst
   statt zweimal dupliziert. MUSS als LETZTE Regel für BEIDE betroffenen
   Selektoren stehen — die Basisregel .todo-list-menu-btn{opacity:0} steht
   weiter oben im List-Row-Abschnitt, die Basisregel .tbc-menu{opacity:0}
   direkt darüber im Board-Karten-Abschnitt; dieser Block steht nach BEIDEN.
   Ticket 3.163.12: eine Media-Query erhoeht die CSS-Spezifitaet NICHT, bei
   gleicher Spezifitaet gewinnt die im Dokument SPAETER stehende Regel — vor
   diesem Ticket stand der Block bei GLEICHER Spezifitaet VOR den
   Basisregeln und war dadurch wirkungslos: ⋯-Menü + Loeschen-Knopf waren
   auf Touch-Geraeten monatelang unsichtbar UND nicht treffbar. */
@media (pointer: coarse) {
  .todo-list-menu-btn { opacity: 1; }
  .tbc-menu { opacity: 1; }
}

/* 🔒 Touch-Geraete: Ziehen-Griff sichtbar + treffbar (Ticket 3.256, echtes
   Touch-Ziehen ueber core/touch-drag.js). Steht bewusst NACH den
   Basisregeln .todo-list-drag-handle{opacity:0;pointer-events:none}
   (List-Row-Abschnitt) und .tbc-drag{opacity:0} (Board-Karten-Abschnitt) --
   dieselbe Reihenfolge-Pflicht wie beim Block direkt darueber (Ticket
   3.163.12: eine Media-Query erhoeht die Spezifitaet NICHT, bei Gleichstand
   gewinnt die spaeter stehende Regel). `.todo-list-drag-handle` traegt in
   der Basisregel zusaetzlich `pointer-events:none` (Desktop: nur optische
   Hover-Affordanz, ziehbar ist die ganze Zeile per Maus) -- auf Touch MUSS
   das Element selbst Events empfangen, sonst laeuft der @touchstart-Handler
   nie an. `.tbc-drag` hat `pointer-events` nie eingeschraenkt (war schon
   vorher treffbar, nur unsichtbar per opacity:0). */
@media (pointer: coarse) {
  .todo-list-drag-handle {
    opacity: .55;
    pointer-events: auto;
  }
  .tbc-drag {
    opacity: .55;
    /* 🔒 Griff braucht ein eigenes Trefferpolster (Ticket 3.256, empirisch
       gefunden per Puppeteer-Touch-Event-Log): Chromiums eingebaute
       Touch-Zieljustierung (die Interpretation eines Fingertipps als
       kleine Flaeche statt eines Punkts) verschob einen Touch mitten im
       18x17px-Griff auf den DIREKT ANGRENZENDEN .tbc-check-Button (0px
       Abstand dazwischen) -- gemessen: Touch bei x=42 (Griffmitte, Box
       33-51) landete als `touchstart`-Ziel auf dem Button. Fix in zwei
       Teilen: (1) `margin-right` schafft echten Abstand zum Nachbarn --
       Chromiums Adjustment bevorzugt naeheliegende Ziele, ein Luecken-
       Abstand entzieht dem Button seinen Vorteil. (2) `position:relative`
       + `::before`-Ueberlagerung vergroessert die TATSAECHLICHE Trefferflaeche
       des Griffs selbst, aber NUR nach oben/unten/links (`right:0`) --
       niemals nach rechts in Richtung Checkbox, sonst wuerde ein Tipp auf
       den sichtbaren linken Rand der Checkbox faelschlich einen Zug statt
       eines Abhakens ausloesen. */
    position: relative;
    margin-right: 6px;
  }
  .tbc-drag::before {
    content: '';
    position: absolute;
    top: -10px; bottom: -10px; left: -10px; right: 0;
  }
}

/* ── Touch-Drag-Ziehbild (Ticket 3.256, core/touch-drag.js) ───────────────
   Folgt dem Finger waehrend eines Touch-Ziehens -- Browser liefern bei
   Touch (anders als bei Maus) kein natives Drag-Ziehbild. Reiner Klon des
   gezogenen Karten-/Zeilenkoerpers, `pointer-events:none` (darf die
   `elementFromPoint()`-Ermittlung des Ziehkerns nie stoeren). z-index ueber
   dem app-weiten ContextMenu (1100) UND dem `.ds-drawer--right`-Portal
   (1200) -- ein Drag-Vorgang schliesst beide Interaktionen ohnehin aus,
   das Ziehbild soll trotzdem nie dahinter verschwinden koennen. */
.ds-touch-drag-ghost {
  position: fixed;
  z-index: 1300;
  pointer-events: none;
  opacity: .92;
  box-shadow: var(--shadow-lg);
  border-radius: var(--radius-md);
  transform: scale(1.02) rotate(-1deg);
}

/* ── Maus-Drag-Ziehbild bei Mehrfachauswahl (Ticket 3.361.1) ───────────────
   Ersetzt ueber setDragImage() das native Ziehbild einer einzelnen Karte,
   sobald mehr als eine Aufgabe gemeinsam gezogen wird -- zeigt "N Aufgaben"
   statt der (aus Nutzersicht irrefuehrenden) angefassten Einzelkarte. Der
   Knoten lebt nur den einen Frame lang, in dem der Browser das Ziehbild
   fotografiert (position:fixed weit ausserhalb des Viewports, danach per
   requestAnimationFrame() wieder entfernt -- s. ds-todo-board-view.js
   _setMultiDragImage()). */
.board-multi-drag-ghost {
  position: fixed;
  top: -1000px;
  left: -1000px;
  padding: 6px 12px;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: #fff;
  font-size: .8125rem;
  font-weight: 600;
  box-shadow: var(--shadow-lg);
  white-space: nowrap;
  pointer-events: none;
}

/* ── aus ds-todo-board-view.js (3.85 Paket 6) ─────────────────────────────
   Kanban-Board-Spalten. Reihenfolge unverändert zum ursprünglichen
   einzigen <style>-Block übernommen.
   🔒 Verlauf der mobilen Spaltenhöhe (Kurzfassung, volle Begründung je
   Runde im Kommentar bei .board-col-cards in der @media(max-width:900px)-
   Sektion unten):
   - Ticket 3.215.2: JS-Passgenau-Messung (--board-mobile-col-max).
   - Ticket 3.232: JS-Messung ERSATZLOS entfernt, .board-col-cards ungedeckelt
     → erzwang (wegen .board-wraps overflow-x:auto) ein Stapel-Layout.
   - Ticket 3.232.1 Variante A: Rückkehr zu Spalten NEBENEINANDER (nicht
     verhandelbar) über eine reine, hartcodierte CSS-calc()-Formel
     (436px-Fixbudget) statt der JS-Messung.
   - Ticket 3.232.1 (Folge-Runde): die JS-Messung ist REAKTIVIERT — die
     hartcodierte Formel bleibt NUR als Fallback (var()-Default) bestehen.
   - Ticket 3.232.3: --board-mobile-col-max → --board-mobile-col-height,
     misst jetzt die SPALTE (.board-col, `height`) statt nur ihrer Karten-
     Liste (`max-height`) — behebt einen toten, scroll-losen Streifen
     zwischen kurzer Kartenliste und Bottom-Nav. `.board-col-cards`
     bekommt dafür `flex:1` statt einer eigenen festen Höhe. Details/
     Methode s. Docblock bei ds-todo-board-view.js::_syncMobileColHeight(). */
ds-todo-board-view { display: block; }
/* ── Board container ── */
.board-wrap {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 1.5rem;
  align-items: flex-start;
  /* allow horizontal scrolling without showing scrollbar on the page */
  scroll-behavior: smooth;
}
.board-wrap::-webkit-scrollbar { height: 6px; }
.board-wrap::-webkit-scrollbar-track { background: transparent; }
.board-wrap::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

/* ── Column ── */
.board-col {
  width: 280px;
  min-width: 280px;
  max-width: 280px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg-secondary);
  border-radius: var(--radius-md);
  padding: 8px 8px 10px 8px;
  transition: opacity 150ms ease;
}
.board-col.dnd-dragging { opacity: 0.4; }
.board-col.dnd-col-over { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── Sticky Kopf INNERHALB von .board-col-cards (T6, Ticket 3.163.2) ──
   Muss ein direktes Kind des Scroll-Containers sein, sonst greift
   sticky nicht zuverlässig (s. Kommentar in _renderColumn()).
   background deckt darunter wegscrollende Karten ab; z-index hebt
   ihn über die Karten (kein Konflikt mit dem app-weiten ContextMenu-
   Overlay, das deutlich höher liegt). */
.board-col-sticky-head {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg-secondary);
}

/* ── Column header ── */
.board-col-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 4px 12px 4px;
  position: relative;
}
.board-col-drag-handle {
  cursor: grab;
  color: var(--text-tertiary);
  display: none;
  align-items: center;
  padding: 2px;
  border-radius: 4px;
  flex-shrink: 0;
  transition: color 150ms ease;
}
.board-col-drag-handle:active { cursor: grabbing; }
.board-col-header:hover .board-col-drag-handle { display: flex; }
.board-col-title {
  flex: 1;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.board-col-count {
  font-size: 0.78rem;
  color: var(--text-tertiary);
  font-weight: 400;
  flex-shrink: 0;
}
/* Spec Teil 7: Progress-Bar im Spalten-Header */
.board-col-progress {
  height: 4px;
  border-radius: 2px;
  background: rgba(0,0,0,.08);
  overflow: hidden;
  margin: 0 4px 10px 4px;
}
.board-col-progress-fill {
  height: 100%;
  background: var(--accent);
  transition: width .2s ease;
}
.board-col-subtitle {
  font-size: 0.72rem;
  color: var(--text-tertiary);
  padding: 0 4px 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* "Alle auswählen" je Spalte (Ticket 3.260 Nachtrag 2, 2026-08-17) — nur
   waehrend des Auswahl-Modus im Spaltenkopf sichtbar (s.
   _renderColumnSelectAll() in ds-todo-board-view.js), Position zwischen
   Header und Subtitle/Progress-Bar (dieselbe Markup-Reihenfolge). Bauform
   analog .bl-select-all-check (ds-todo-backlog.js) — kompakter fuer die
   schmale Spalte (~250-280px), eigene Klasse statt Wiederverwendung, da
   die Spalte KEIN Aequivalent zur globalen Backlog-Checkbox hat. */
.board-col-select-all {
  display: flex;
  align-items: center;
  gap: .35rem;
  padding: 0 4px 8px 4px;
  cursor: pointer;
  font-size: .72rem;
  color: var(--text-tertiary);
  user-select: none;
}
.board-col-select-all:hover { color: var(--text-secondary); }
.board-col-select-all input[type="checkbox"] {
  width: 14px; height: 14px;
  cursor: pointer;
  accent-color: var(--accent);
  border-radius: 3px;
  flex-shrink: 0;
}
.board-col-progress-text {
  font-size: 0.7rem;
  color: var(--text-tertiary);
  padding-left: 4px;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
.board-col-menu-wrap {
  position: relative;
  flex-shrink: 0;
  display: none;
}
.board-col-header:hover .board-col-menu-wrap { display: block; }
.board-col-menu-btn {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: 4px;
  color: var(--text-tertiary);
  transition: color 150ms ease, background 150ms ease;
  padding: 0;
}
.board-col-menu-btn:hover {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}
/* Das Spalten-⋯-Dropdown selbst rendert seit S4.1 über das app-weite
   ContextMenu (core/ds-context-menu.js, eigenes CSS in _core.css) —
   kein lokales .board-col-menu-dropdown/-item mehr nötig. */

/* ── Rename input in header ── */
.board-col-rename-row {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 4px 12px 4px;
}
.board-col-rename-input {
  flex: 1;
  border: 1px solid var(--accent);
  border-radius: 6px;
  padding: 3px 8px;
  font-size: 0.875rem;
  font-weight: 600;
  background: var(--bg-primary);
  color: var(--text-primary);
  outline: none;
  min-width: 0;
}
.board-col-rename-input:focus { box-shadow: 0 0 0 2px var(--accent-light); }
.board-col-rename-action {
  width: 24px;
  height: 24px;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: 4px;
  font-size: 0.8rem;
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: color 150ms ease, background 150ms ease;
}
.board-col-rename-action:hover { color: var(--text-primary); background: var(--bg-tertiary); }

/* ── Column card list ── */
.board-col-cards {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 32px;
  max-height: calc(100vh - 220px);
  overflow-y: auto;
  padding: 0 0 4px 0;
}
.board-col-cards::-webkit-scrollbar { width: 4px; }
.board-col-cards::-webkit-scrollbar-track { background: transparent; }
.board-col-cards::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }

/* Ticket 3.260 Nachtrag 2 (2026-08-17) — die Mehrfachauswahl-Checkbox einer
   Karte lebt seither IN der Karte selbst (.tbc-select, s. weiter oben in
   dieser Datei bei .tbc-label/.tbc-menu), die Spalten-weite "Alle
   auswählen"-Checkbox steht im Spaltenkopf (.board-col-select-all, s.
   weiter oben bei .board-col-subtitle/.board-col-progress-text). Die
   frühere eigenstaendige Checkbox-Zeile VOR jeder Karte
   (.board-card-select-row) ist damit ERSATZLOS entfallen — kein
   Wrapper-Problem mehr, da <ds-todo-item> weiterhin unveraendert direktes
   Kind von .board-col-cards bleibt. */

/* ── DnD drop indicator ── */
.dnd-drop-indicator {
  height: 2px;
  background: var(--accent);
  border-radius: 1px;
  margin: 0 4px;
  pointer-events: none;
  flex-shrink: 0;
  position: relative;
}
.dnd-drop-indicator::before {
  content: '';
  position: absolute;
  left: -4px;
  top: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

/* ── Ticket 3.163.11 — grössere Ablagehilfen beim Karten-Drag ──
   Rein visuell: welche Position tatsächlich getroffen wird,
   entscheidet weiterhin unverändert _onBodyDragOver()/_onBodyDrop()
   (Kartenmitten-Vergleich). Hier wird nur (a) die Trefferfläche vor
   der ersten / hinter der letzten Karte über zusätzliches Padding
   vergrössert und (b) die Einfügemarke an genau diesen zwei Rand-
   Positionen deutlich grösser/auffälliger dargestellt, statt der
   dünnen 2px-Linie. Klasse .board-drag-active sitzt auf dem Host-
   Element (ds-todo-board-view, Light-DOM) und wird nur während eines
   aktiven Karten-Drags gesetzt (_onTodoDragStart/_clearDndState) —
   im Ruhezustand ändert sich dadurch nichts. */
ds-todo-board-view.board-drag-active .board-col-cards {
  padding-bottom: 16px;
}

/* Rand-Positionen: direkt nach dem Spaltenkopf ("ganz oben") oder
   als letztes Kind ("ganz unten") — statt der dünnen Linie eine
   grosszügige, gestrichelte Akzent-Leiste über die volle Breite. */
.board-col-sticky-head + .dnd-drop-indicator,
.dnd-drop-indicator:last-child {
  height: 36px;
  margin: 4px 2px;
  border-radius: var(--radius-sm);
  background: var(--accent-light);
  border: 1.5px dashed var(--accent);
}
.board-col-sticky-head + .dnd-drop-indicator::before,
.dnd-drop-indicator:last-child::before {
  display: none; /* Punkt-Bullet der duennen Linie passt nicht zur Flaeche */
}

/* ── Leere Spalte: grosse Ablagefläche statt der schmalen 32px-
   Restfläche. Existiert im DOM immer wenn die Spalte leer ist,
   bleibt aber via display:none unsichtbar bis ein Karten-Drag
   läuft — die Karte selbst entscheidet weiterhin _onBodyDrop(). */
.board-col-empty-dropzone {
  display: none;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 4px;
  min-height: 92px;
  margin: 4px 2px 2px 2px;
  border: 2px dashed var(--border);
  border-radius: var(--radius-md);
  color: var(--text-tertiary);
  font-size: 0.78rem;
  text-align: center;
  pointer-events: none;
  transition: border-color 150ms ease, background 150ms ease, color 150ms ease;
}
ds-todo-board-view.board-drag-active .board-col-empty-dropzone {
  display: flex;
}
.board-col-cards.dnd-cards-over .board-col-empty-dropzone {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
}
/* Die duenne Einfuegemarke ist neben der grossen Ablagefläche
   redundant -- wird ausgeblendet statt doppelt angezeigt zu werden. */
.board-col-empty-dropzone ~ .dnd-drop-indicator {
  display: none;
}

/* ── Quick-add trigger ── */
.board-col-add-trigger {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 4px;
  font-size: 0.82rem;
  color: var(--text-tertiary);
  cursor: pointer;
  border: none;
  background: none;
  border-radius: 6px;
  width: 100%;
  text-align: left;
  transition: color 150ms ease;
  margin-top: 4px;
}
.board-col-add-trigger:hover { color: var(--accent); }
.board-col-add-trigger svg { flex-shrink: 0; }

/* ── Phantom "add section" column ── */
.board-phantom-col {
  width: 280px;
  min-width: 280px;
  max-width: 280px;
  flex-shrink: 0;
  border: 2px dashed var(--border);
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 80px;
  cursor: pointer;
  transition: border-color 150ms ease, background 150ms ease;
  color: var(--text-tertiary);
  font-size: 0.82rem;
}
.board-phantom-col:hover {
  border-color: var(--accent);
  background: var(--accent-light);
  color: var(--accent);
}
.board-phantom-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 24px 16px;
  text-align: center;
  pointer-events: none;
}

/* ── New section inline column ── */
.board-new-section-col {
  width: 280px;
  min-width: 280px;
  max-width: 280px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
}
.board-new-section-header {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 4px 12px 4px;
}
.board-new-section-input {
  flex: 1;
  border: 1px solid var(--accent);
  border-radius: 6px;
  padding: 4px 8px;
  font-size: 0.875rem;
  font-weight: 600;
  background: var(--bg-primary);
  color: var(--text-primary);
  outline: none;
  min-width: 0;
}
.board-new-section-input:focus { box-shadow: 0 0 0 2px var(--accent-light); }

/* ── "Alle Spalten ausgeblendet" — Leer-Zustand (Ticket 3.230, Rückweg
   seit 3.230.2 im Kopfzeilen-Menü statt eines eigenen Chips/Buttons hier) ──
   Ersetzt .board-wrap komplett (kein Flex-Kind davon — braucht die volle
   Breite, s. _renderAllHiddenEmptyState()). Wrapper .todo-empty-state
   reused (s. ds-todo-list-view.js _renderEmpty()), nur Titel/Hinweis-Text
   sind hier neu. */
.board-all-hidden-empty-title {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text-primary);
}
.board-all-hidden-empty-hint {
  font-size: 0.82rem;
  color: var(--text-tertiary);
  max-width: 320px;
  margin: 0.35rem auto 0;
}

/* ── Card dragging state ── */
ds-todo-item.dnd-dragging { opacity: 0.35; }
/* Swimlanes (Spec drich_suite_project_views.md – Teil 2) */
.board-swimlane {
  border-top: 1px solid var(--border);
  padding-top: .75rem; margin-top: .75rem;
}
.board-swimlane:first-child {
  border-top: none; padding-top: 0; margin-top: 0;
}
.board-swimlane-header {
  font-size: .78rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; color: var(--text-secondary);
  padding: .25rem .5rem; margin-bottom: .5rem;
  background: var(--bg-tertiary); border-radius: var(--radius-sm);
  display: inline-block;
}

/* ── Mobile Fixes (≤900px) ── */
@media (max-width: 900px) {
  /* 🔒 Ticket 3.232.1 (2026-08-16) — Rückbau des 3.232-Stapel-Layouts.
     3.232 stapelte die Spalten mobil UNTEREINANDER (volle Breite), weil
     .board-wrap sonst per CSS-Kopplungsregel (overflow-x:auto + kein
     eigener overflow-y-Wert → overflow-y wird implizit "auto") selbst zum
     vertikalen Scrollport wurde und den sticky Spaltenkopf einfing statt
     ihn an .todos-content kleben zu lassen. Domenico (2026-08-16, nach
     Sichtung): "Ein kanban Board macht nur Sinn, wenn es nebeneinander
     ist. […] Ich wollte ja nur, dass der Header der Spalten genau so
     sticky ist wie im Desktop." Klargestellte Priorität: Spalten
     NEBENEINANDER ist PFLICHT und nicht verhandelbar, das sticky-Kleben
     ist NACHRANGIG — bei Zielkonflikt gewinnt Nebeneinander, niemals
     zurück zum Stapeln.
     Spalten stehen daher wieder NEBENEINANDER (85vw + Peek + Snap-Scroll,
     1:1 der Vor-3.232-Stand).
     ⚠️ 🔒 Versuchter Fix fürs sticky-Kleben — GEPRÜFT UND VERWORFEN, hier
     dokumentiert damit niemand denselben Weg nochmal geht: overflow-y auf
     dieser Box explizit auf `clip` statt auf den (durch die Kopplungs-
     regel entstehenden) impliziten `auto`-Wert zu setzen, in der Annahme,
     `clip` würde (im Unterschied zu `hidden`/`scroll`/`auto`) KEINEN
     Scroll-Container etablieren und die Box dadurch nur auf der X-Achse
     zum Sticky-Bezugsrahmen machen. **Empirisch widerlegt** (isolierter
     Minimal-Test AUSSERHALB der App, `_temp/playwright/isolate-sticky-
     clip.js`, sowie am echten Board: Spaltenkopf wandert 1:1 mit dem
     Scroll-Delta statt zu kleben, `colHeadTop` bewegt sich exakt um den
     Betrag von `.todos-content.scrollTop`). Reale Browser-Regel ist
     BOX-, nicht ACHSEN-basiert: sobald IRGENDeine Achse einer Box einen
     Overflow-Wert ≠ `visible` traegt (hier `overflow-x:auto`), wird die
     GESAMTE Box zum Sticky-Bezugsrahmen fuer ihre Nachfahren — unabhaengig
     davon, ob die ANDERE Achse tatsaechlich scrollt oder nur `clip`t.
     `.board-wrap` MUSS aber `overflow-x:auto` tragen (das Spalten-
     Karussell) — der Spaltenkopf kann folglich strukturell NICHT gegen
     `.todos-content` kleben, solange Spalten mobil nebeneinander UND per
     natives Overflow scrollbar sind UND gleichzeitig .board-col-cards
     selbst ungedeckelt (max-height:none) bleibt — dieser Befund gilt NUR
     unter genau dieser Bedingung.
     🔒 Ticket 3.232.1 Variante A (2026-08-16, Domenicos ausdrückliche
     Entscheidung nach Rückfrage) loest den scheinbaren Widerspruch auf,
     statt ihn hinzunehmen: .board-col-cards bekommt seine eigene, gedeckelte
     max-height + overflow-y:auto ZURUECK (Desktop-Mechanik, s.
     .board-col-cards unten) — dann ist .board-col-cards selbst wieder der
     naechstgelegene Scroll-Container fuer .board-col-sticky-head, NICHT
     mehr .board-wrap. Sticky klebt damit unabhaengig davon, ob .board-wrap
     nebenbei noch sein eigenes overflow-x:auto traegt — das Karussell und
     das Kleben widersprechen sich nur, wenn die Spalte KEINEN eigenen
     Scroll hat. Der Preis (bewusst uebernommen): .todos-content selbst
     scrollt kaum noch vertikal, der Projektkopf bleibt oben stehen. */
  .board-wrap {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
  }
  .board-col {
    min-width: 85vw;
    max-width: 85vw;
    width: 85vw;
    scroll-snap-align: start;
    scroll-snap-stop: always;
  }

  /* 🔒 Ticket 3.256 — waehrend eines aktiven Karten-Zugs (Touch UND Maus,
     beide setzen `.board-drag-active` ueber `ds-todo-board-view.js::
     _onTodoDragStart()`/`_clearDndState()`) wird das Spalten-Karussell kurz-
     zeitig aus dem mandatory Scroll-Snap genommen. Ohne diesen Override
     verwirft der Browser jeden kleinen Rand-Auto-Scroll-Schritt sofort
     wieder auf den naeheren Ankerpunkt zurueck, BEVOR der naechste Schritt
     ueberhaupt zaehlt -- `core/touch-drag.js`s Rand-Scroll (`scrollLeft +=`
     pro Animationsframe) blieb dadurch wirkungslos: empirisch belegt (>250
     aufeinanderfolgende Versuche, `.board-wrap.scrollLeft` blieb exakt bei
     0 -- sowohl per Touch-Emulation als auch bei blossem `el.scrollLeft=80`
     ohne jeden Drag-Bezug; ein expliziter `!important`-Override von
     `scroll-snap-type` UND `scroll-behavior` war die einzige Kombination,
     die eine Verschiebung ueberhaupt sichtbar machte -- `scroll-snap-type`
     allein reichte NICHT). Snap greift wieder, sobald der Zug endet
     (Klasse verschwindet) -- kein Verhaltensverlust im Ruhezustand, die
     Spalte "rastet" nach dem Loslassen wie gewohnt ein. */
  ds-todo-board-view.board-drag-active .board-wrap {
    scroll-snap-type: none;
    scroll-behavior: auto;
  }

  /* 🔒 Ticket 3.232.1 (Folge-Runde, direkt im Anschluss an Variante A) —
     die JS-Passgenau-Messung (--board-mobile-col-height) ist REAKTIVIERT, s.
     ds-todo-board-view.js::_syncMobileColHeight(). Grund: die Variante-A-
     Formel unten (Fixbudget) kann nicht gleichzeitig zu ZWEI
     Umgebungen passen — die lokale Dev-Umgebung zeigt ein zusätzliches
     Umgebungs-Banner (".env-banner", app/index.php), das auf PROD nicht
     existiert. Ein Budget, das lokal (mit Banner) passt, verschenkt auf
     PROD (ohne Banner) exakt den Banner-Betrag an Spaltenhöhe. Die
     JS-Messung liest die real verfügbare Höhe zur Laufzeit und trifft damit
     in JEDER Umgebung automatisch das richtige Maß.
     🔒 Das ist NICHT die alte 50%-Deckelung von vor Ticket 3.215.2 — Ziel
     bleibt "fast die gesamte Restfläche", nur GEMESSEN statt geschätzt.
     Die feste calc()-Formel unten bleibt als FALLBACK bestehen
     (var()-Default) — für den allerersten Frame vor der ersten JS-Messung
     und für den (praktisch nicht vorkommenden) Fall, dass JS nicht läuft.
     100dvh statt 100vh (mobile Adressleiste faehrt ein/aus und aendert
     100vh sonst mitten im Scrollen) — die vh-Zeile davor ist der Fallback
     fuer Browser ohne dvh-Unterstuetzung; eine unbekannte Einheit macht
     die GESAMTE Deklaration ungueltig, die Kaskade faellt dann auf die
     vh-Zeile zurueck.
     🔒 Ticket 3.232.3 — ZWEI Aenderungen gegenueber der urspruenglichen
     Variante A, beide am selben Befund: eine Spalte mit WENIGEN Karten
     bekam vorher nur ihre Karten-Liste (`.board-col-cards`) auf die
     gemessene Resthöhe GEDECKELT (`max-height`) — bei kurzem Inhalt blieb
     die Box entsprechend klein, und der Streifen BIS ZUR Bottom-Nav
     gehoerte zu KEINEM Scroll-Container mehr. Eine Wisch-Geste dort (Rand
     neben/unter der kurzen Kartenliste) bewegte nichts — genau Domenicos
     gemeldetes Symptom ("Ich scrolle am Rand neben der Liste"). Live
     vermessen (`_temp/playwright/diag-deadzone.js`, Projekt 7, iPhone-13-
     Emulation, Variante A vor diesem Fix): Spalte endete bei y=438, die
     Bottom-Nav begann erst bei y=787 — 349px toter Streifen.
     (1) Die Variable heisst jetzt `--board-mobile-col-height` (misst die
     SPALTE, nicht mehr nur ihre Karten-Liste) und wird als `height` HIER
     auf `.board-col` selbst gesetzt — die Spalte fuellt den verfuegbaren
     Platz bis zur Bottom-Nav dadurch IMMER komplett aus, unabhaengig vom
     Karteninhalt. `.board-col` ist bereits `box-sizing:border-box`
     (globaler Reset) — ihr eigenes Padding ist in dieser Hoehe
     eingerechnet.
     (2) `.board-col-cards` bekommt dafuer KEINE eigene feste Hoehe mehr,
     sondern `flex:1` (s. unten) — sie teilt sich den Innenraum der jetzt
     fixen Spaltenhoehe automatisch mit ihrem Nachbarn (dem "Aufgabe
     hinzufuegen"-Knopf ODER einem geoeffneten, deutlich hoeheren Quick-
     Add-Formular). Eine literal FESTE Hoehe auf BEIDEN Ebenen (Spalte UND
     Karten-Liste gleichzeitig) haette bei einem offenen Formular in einer
     ANDEREN Spalte als der fuer die Messung herangezogenen zum Ueberlaufen
     der Spalte gefuehrt (die Formularhoehe wird nicht gemessen, s.
     Docblock in ds-todo-board-view.js) — mit `flex:1` schrumpft die
     Karten-Liste stattdessen automatisch, kein Sonderfall noetig. */
  .board-col {
    height: var(--board-mobile-col-height, calc(100dvh - 441px - env(safe-area-inset-bottom)));
  }
  .board-col-cards {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow-y: auto;
  }
  /* 🔒 Ticket 3.232.1 Variante A — KEIN top-Offset mehr noetig
     (Ruecknahme des 3.232-Fixes fuer .board-col-sticky-head): dessen
     top:calc(-1 * var(--todos-content-pad)) glich vorher aus, dass
     .todos-content (mit eigenem padding-top) der tatsaechlich scrollende
     Vorfahre war. Jetzt ist .board-col-cards SELBST wieder der scrollende
     Vorfahre (s.o.) — sie hat KEIN eigenes padding-top (padding: 0 0 4px
     0), die Basisregel `top:0` (s. .board-col-sticky-head oben) ist daher
     wieder korrekt, exakt der Stand vor Ticket 3.232 (Git-Historie vor
     Commit dfed34f). Kein Mobile-Override mehr auf dieser Klasse. Bleibt
     nach 3.232.3 unveraendert — `.board-col-cards` ist weiterhin der
     naechstgelegene Scroll-Container fuer den Kopf, `flex:1` aendert nur
     WIE ihre Hoehe berechnet wird, nicht DASS sie selbst scrollt. */

  /* Fix 2: Drag-Handle + Spaltenmenü auf Touch-Geräten immer sichtbar */
  .board-col-drag-handle {
    display: flex;
    padding: 6px;
    min-width: 32px;
    min-height: 32px;
    justify-content: center;
  }
  .board-col-menu-wrap {
    display: block;
  }
  .board-col-menu-btn {
    width: 40px;
    height: 40px;
    min-width: 40px;
    min-height: 40px;
  }
}

/* Touch-Geräte (Pointer: coarse) — unabhängig von Viewport-Breite */
@media (pointer: coarse) {
  .board-col-drag-handle {
    display: flex;
    padding: 6px;
    min-width: 32px;
    min-height: 32px;
    justify-content: center;
  }
  .board-col-menu-wrap {
    display: block;
  }
  .board-col-menu-btn {
    width: 40px;
    height: 40px;
    min-width: 40px;
    min-height: 40px;
  }
}

/* ── aus ds-todo-backlog.js (3.85 Paket 6) ────────────────────────────────
   Backlog/Listen-Ansicht. Reihenfolge unverändert übernommen, komplett
   literales CSS (keine ${}-Interpolation im ursprünglichen Block). .bl-badge
   .epic/.ms und .bl-header-row/-cell bedienen weiterhin _renderEpicRow()/
   _renderMilestoneRow()/_renderColumnHeader() — unverändert 1:1 verschoben. */
.bl-wrap { padding: 0 0 2rem; }

/* Fix 2B – Epic/Meilenstein-Zeilen über den Tasks */
.bl-group-rows {
  display: flex; flex-direction: column; gap: 2px;
  margin-bottom: .75rem;
}
.bl-group-row {
  display: flex; align-items: center; gap: .6rem;
  padding: .55rem .75rem;
  background: var(--bg-primary);
  border-radius: var(--radius-sm);
  box-shadow: 0 1px 2px rgba(0,0,0,0.05);
  cursor: pointer;
  transition: background var(--transition), box-shadow var(--transition);
}
.bl-group-row:hover {
  background: var(--bg-tertiary);
  box-shadow: 0 2px 4px rgba(0,0,0,0.08);
}
.bl-group-row-epic {
  border-left: 3px solid var(--accent);
  font-weight: 600;
  font-size: .95rem;
}
.bl-group-row-milestone {
  margin-left: 1.25rem;
  font-weight: 500;
  font-size: .88rem;
  color: var(--text-secondary);
}
.bl-group-icon {
  width: 18px; text-align: center; flex-shrink: 0;
  font-size: 1rem; line-height: 1;
}
.bl-group-name {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bl-group-count {
  font-size: .75rem; color: var(--text-tertiary);
  padding: .1rem .45rem;
  background: var(--bg-tertiary);
  border-radius: 999px;
  flex-shrink: 0;
}
/* Ticket 3.163.5 (T3): Suche + Filter sind aus dieser Toolbar
   ausgezogen (leben jetzt zentral in ds-todo-list-view.js, s.
   Kommentar bei _visibleTopLevel()) -- .bl-grouping traegt seither nur
   noch "Gruppieren".
   Unteraufgabe 3.231.2 (17.08., Platzsparen): ehemals .bl-toolbar als
   EIGENE volle Zeile (mit .bl-toolbar-spacer) UEBER .bl-select-all-row --
   jetzt ein reines Inline-Cluster (kein eigener Spacer mehr noetig), das
   .bl-select-all-row rechts neben "Alle auswählen" in dieselbe Zeile
   haengt (s. dort, justify-content:space-between). Spart eine komplette
   Zeile Vertikalabstand zwischen Kopfbereich und erster Aufgaben-Zeile. */
.bl-grouping {
  display: flex; gap: .5rem;
  align-items: center;
  flex-shrink: 0;
}
.bl-grouping select {
  padding: .3rem .5rem; font-size: .82rem;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-primary); color: var(--text-primary);
  cursor: pointer;
}
.bl-group-label { font-size: .75rem; color: var(--text-tertiary); white-space: nowrap; }

/* Ticket 3.231 (Massenaktionen) — "Alle auswählen"-Kopfzeile.
   Bewusst EIN eigener Kopfbereich statt Teil von .bl-header-row (die ist
   auf Mobile ausgeblendet, s. modules/todos.md "Backlog-Ansicht Mobile") —
   damit bleibt Select-All auf Desktop UND Mobile gleichermassen erreichbar.
   🔒 Korrigiert Ticket 3.260 (2026-08-17, Domenico-Feedback 17.08.): die
   Desktop-Aktionsleiste stand hier vorher INLINE (.bl-bulk-inline, "Bauform
   wie .bulk-action-bar/_core.css, aber ohne die sticky-Positionierung --
   Domenico-Vorgabe 'im Kopfbereich'"). Diese Vorgabe ist AUFGEHOBEN: die
   Desktop-Aktionsleiste nutzt seither die GETEILTE, sticky .bulk-action-bar
   selbst (_core.css) — sie sitzt am Ende von .bl-wrap (s. ds-todo-backlog.js
   render()/_renderDesktopBulkBar()) und bleibt beim Scrollen sichtbar, statt
   beim Scrollen nach unten aus dem Kopfbereich zu verschwinden. .bl-bulk-inline
   bleibt als Klasse bestehen, wird aber seither NICHT mehr verwendet — nicht
   entfernt, da .bl-bulk-count (identischer Name-Baustein) weiterhin vom
   mobilen Balken genutzt wird (s.u.); der mobile, unten fixierte Balken
   (.bl-bulk-mobile-bar) bleibt UNVERAENDERT (Domenico: "Mobil nichts
   verschlimmbessern... sie ist die Vorlage, nicht der Gegenstand").
   Unteraufgabe 3.231.2: traegt seither zusaetzlich rechts .bl-grouping
   (s.o.) -- justify-content:space-between haelt "Alle auswählen" links und
   "Gruppieren" rechts, auch wenn .bl-select-all-left (naechster Block)
   mangels sichtbarer Top-Level-Aufgaben leer bleibt. */
.bl-select-all-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .75rem;
  padding: .35rem 0 .5rem;
  margin-bottom: .25rem;
  font-size: .8rem;
  color: var(--text-secondary);
}
/* Linker Cluster: Checkbox + Label + (bei aktiver Auswahl) die Desktop-
   Aktionsleiste -- eigener Flex-Wrapper, damit .bl-select-all-row als
   Ganzes per justify-content:space-between GENAU zwei Bloecke positioniert
   (dieser + .bl-grouping), unabhaengig davon wie viele Kinder links stehen. */
.bl-select-all-left {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .75rem;
  min-width: 0;
}
.bl-select-all-check {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  cursor: pointer;
  user-select: none;
}
.bl-select-all-check:hover { color: var(--text-primary); }
.bl-select-all-check input[type="checkbox"] {
  width: 16px; height: 16px;
  cursor: pointer;
  accent-color: var(--accent);
  border-radius: 3px;
}
.bl-bulk-inline {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}
.bl-bulk-count {
  font-size: .8rem;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
}
.bl-bulk-inline .btn svg,
.bl-bulk-mobile-actions .btn svg {
  width: 13px; height: 13px;
}

/* Mobile: unten fixierter Aktionsbalken (Domenico-Entscheidung E3 --
   abweichend vom Vorbild pages/companies.js, das mobile Bulk-Aktionen
   bewusst NICHT anbietet, s. design-system.md "Bulk-Selection +
   Action-Bar"). Sitzt ÜBER der unteren Hauptnavigation (die auf Mobile
   selbst NICHT position:fixed ist, sondern im normalen Flow steht --
   56px + safe-area ist ihre bekannte Gesamthöhe, s. .ds-bottom-item
   min-height:56px in nav.css). Wiederverwendet die globale @keyframes
   bulk-bar-in (_core.css) -- kein zweites Keyframe.
   🔒 Korrigiert (Ticket 3.260 Nachtrag, 2026-08-17): der Satz "ein Überlappen
   des FAB ist ausdrücklich in Ordnung" ist AUFGEHOBEN. Er galt, solange die
   Mehrfachauswahl im Board mobil unerreichbar war -- seit sie über das
   Karten-⋯-Menü erreichbar ist ("Mehrfachauswahl starten"), verdeckt der
   Schwebeknopf sichtbar Aktionen dieser Leiste (UND der gleichartigen Leiste
   im Board, s. .bulk-action-bar weiter oben). Der Schwebeknopf wird jetzt
   während jeder aktiven Auswahl ausgeblendet, s. Regel unmittelbar nach
   .bl-wrap.has-mobile-bulk-bar unten. Das Verdecken der Bottom-Nav bleibt
   unverändert ausgeschlossen (unverändertes CSS, kein Bezug zu dieser
   Korrektur). */
.bl-bulk-mobile-bar {
  position: fixed;
  left: 0; right: 0;
  bottom: calc(56px + env(safe-area-inset-bottom, 0px));
  z-index: 95;
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .625rem .875rem;
  background: var(--bg-primary);
  border-top: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  animation: bulk-bar-in .15s ease-out;
}
.bl-bulk-mobile-actions {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-left: auto;
}
/* Reserviert Platz am unteren Rand solange der fixe Balken sichtbar ist --
   sonst verdeckt er die letzte(n) Zeile(n) der Liste (s. render()). */
.bl-wrap.has-mobile-bulk-bar { padding-bottom: 4.5rem; }

/* Ticket 3.260 Nachtrag (2026-08-17, Domenico-Feedback 17.08.) -- Schwebeknopf
   (FAB) waehrend jeder aktiven Mehrfachauswahl auf Mobile ausblenden (Board:
   .bulk-action-bar; Backlog: .bl-bulk-mobile-bar). Der Knopf bietet in diesem
   Zustand ohnehin die falsche Aktion an ("Neue Aufgabe" mitten in einer
   Mehrfachauswahl) -- er gehoert weg statt umplatziert, dieselbe Begruendung
   wie bei der Bottom-Nav-Ausblendung fuer Vollbild-Panels (s. nav.css,
   "Untere Hauptnavigation bei geoeffnetem Panel"). Bewusst NICHT in jene
   gepflegte Liste eingetragen: das ist kein Vollbild-Panel, sondern ein
   reiner Auswahl-Zustand innerhalb der bereits offenen Seite, und nav.css/
   layout.css liegen ausserhalb des Datei-Scopes dieser Session. Rein CSS via
   :has() -- KEINE JS-verwaltete body-Klasse (koennte haengen bleiben und den
   Nutzer dauerhaft ohne Schwebeknopf zuruecklassen). Selektor bewusst ueber
   die TODOS-EIGENEN Klassen (ds-todo-board-view .bulk-action-bar /
   .bl-bulk-mobile-bar) statt generisch ueber .bulk-action-bar -- Kontakte/
   Firmen/Belege rendern .bulk-action-bar NIE auf Mobile (grep-verifiziert,
   isMobile()-Guard je Aufrufer) und bleiben damit unberuehrt; betrifft aktuell
   ausschliesslich das Board, bleibt aber praezise falls ein anderes Modul
   spaeter eine eigene Mobile-Bulk-Leiste bekommt. */
@media (max-width: 900px) {
  body:has(ds-todo-board-view .bulk-action-bar) #fab,
  body:has(.bl-bulk-mobile-bar) #fab {
    display: none;
  }
}

/* Fix 3B – Sektions-Header: dunkler Bg, Uppercase, gedimmt.
   Ticket 3.163.2 (T6): Kopf ist klickbar (Gruppe ein-/ausklappen) --
   Chevron rotiert wie das etablierte .todo-section-chevron-Muster
   (ds-todo-list-view.js), hier als eigene Klasse (P-5-Ausnahme: jede
   Todos-Komponente traegt ihr eigenes, scope-lokales CSS, s.
   frontend.md "Component-Ablage"/design-system.md).
   Bugmeldung Domenico ("Sticky Header klappt nicht auf dem
   Telefon"): sticky war hier nie verdrahtet -- grep-Befund, keine
   Regression. .bl-section-header ist direktes Kind von
   .bl-section (Header + Zeilen als Geschwister, kein separater
   Scroll-Wrapper dazwischen), .bl-section selbst hat kein eigenes
   overflow -- der real scrollende Vorfahre ist .todos-content
   (page-todos.js, overflow-y:auto), dazwischen liegt laut Grep KEIN
   Element mit eigenem overflow (anders als beim Board-Spaltenkopf,
   wo .board-wrap durch sein overflow-x:auto zum falschen
   Sticky-Kontext wurde -- hier gibt es dieses Zwischenglied nicht).
   Damit klebt der Header exakt innerhalb der Grenzen von
   .bl-section: sobald deren Boden ueber top:0 hinaus scrollt, wird
   der naechste .bl-section-Header automatisch hochgeschoben (kein
   Stapeln zweier Header, reines CSS-Verhalten von position:sticky
   relativ zur Containing-Block-Grenze). z-index:2 identisch zum
   bestehenden .board-col-sticky-head-Muster (ds-todo-board-view.js)
   -- liegt ueber den Karten (auto/0), weit unter ContextMenu (1100)
   und den Slide-In-/Drawer-Panels (300/1200+). background ist
   bereits deckend gesetzt (var(--bg-tertiary)), verhindert
   Durchscheinen darunter wegscrollender Karten.
   🔒 Nachschaerfung (Ticket 3.163.17, 2026-08-10): .todos-content
   (page-todos.js) hat oben Innenabstand. Ein sticky-Kind respektiert
   diesen Abstand als DAUERHAFTEN Puffer zur Padding-Kante des
   scrollenden Vorfahren -- ohne Korrektur klebt der Header nicht an
   der echten Oberkante, sondern padding-tief darunter, und genau in
   diesem Streifen blieb die jeweils oberste Karte kurz unbedeckt
   sichtbar (nicht die Karte HINTER dem Header -- der ist selbst
   voll deckend, s.o. -- sondern die Karte DARUEBER, im Padding-
   Streifen). Fix: top bekommt ein negatives Offset in genau der
   Hoehe dieses Innenabstands -- das zieht den Klebe-Punkt exakt auf
   die Oberkante des Scrollports, Karten verschwinden dann sauber
   dahinter statt teilweise davor sichtbar zu bleiben. Die Variable
   --todos-content-pad wird auf .todos-content selbst gesetzt
   (page-todos.js, ausserhalb des HARTE-GRENZEN-Scopes dieser
   Aenderung) -- der Fallback 1.5rem haelt diese Regel unabhaengig
   davon korrekt, ob jene Variable im aktuell deployten Stand
   bereits existiert. */
.bl-section { margin-bottom: .75rem; }
.bl-section-header {
  display: flex; align-items: center; gap: .5rem;
  padding: .4rem .75rem;
  position: sticky;
  top: calc(-1 * var(--todos-content-pad, 1.5rem));
  z-index: 2;
  background: var(--bg-tertiary);
  border-bottom: 1px solid var(--border);
  color: var(--text-secondary);
  font-size: .72rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .05em;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  cursor: pointer;
  user-select: none;
}
.bl-section-header:hover { color: var(--text-primary); }
.bl-section-chevron {
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  width: 18px; height: 18px;
  padding: 0; border: none; background: none;
  color: inherit; cursor: pointer;
  border-radius: var(--radius-sm);
  transition: transform var(--transition), background var(--transition);
}
.bl-section-chevron:hover { background: var(--bg-primary); }
.bl-section-chevron.collapsed { transform: rotate(-90deg); }
.bl-section-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bl-section-count {
  font-size: .7rem; color: var(--text-tertiary);
  padding: .05rem .4rem; background: var(--bg-primary);
  border-radius: 999px; font-weight: 500;
  flex-shrink: 0;
}

/* Unteraufgabe 3.231.1 (Domenico-Feedback 16.08.): Auswahl-Checkbox im
   Gruppen-Kopf -- "Alle von Abschnitt X". Sitzt zwischen Chevron und
   Gruppennamen (s. _renderSection()), traegt ein eigenes @click-
   stopPropagation() im Template (kein CSS-Beitrag dafuer noetig -- der
   Klick auf den umgebenden .bl-section-header wuerde sonst zusaetzlich die
   Gruppe ein-/ausklappen). Bauform bewusst kompakter als
   .bl-select-all-check (kein Label-Text -- der Kontext "dieser Abschnitt"
   ist durch die Position im Header bereits eindeutig), gleiche
   Farb-/Radius-Tokens fuer visuelle Konsistenz mit .bl-select-check/
   .bl-select-all-check. Deaktivierter Zustand (Gruppe ohne Top-Level-
   Aufgaben) nutzt das native :disabled-Dimmen des Browsers -- kein eigenes
   CSS noetig, da .bl-section-header bereits reduzierte, gedaempfte Farben
   traegt (color:var(--text-secondary)). */
.bl-section-select-check {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 20px;
  cursor: pointer;
}
.bl-section-select-check input[type="checkbox"] {
  width: 14px; height: 14px;
  cursor: pointer;
  accent-color: var(--accent);
  border-radius: 3px;
}
.bl-section-select-check input[type="checkbox"]:disabled { cursor: not-allowed; }

/* Ticket 3.128: Zeilen-Markup (Rail/Body/Titel/Subline/Meta-Zeile,
   ehemals .bl-row/.bl-rail/.bl-expand/.bl-check/.bl-body/
   .bl-title-row/.bl-title-text/.bl-subline/.bl-meta-row/
   .bl-subtask-counter/.bl-due-chip/.bl-label-chip) ist ENTFERNT --
   diese Datei rendert Zeilen seither ueber <ds-todo-item
   taskKind="main"> (s. _renderRow() unten), das seine eigene, damit
   identische CSS mitbringt (todo-list-row/-rail/-body/... in
   ds-todo-item.js). .bl-badge bleibt (naechster Block) -- wird
   weiterhin von den unveraendert bestehenden, aber von render() aus
   nicht aufgerufenen Gruppen-Header-Zeilen _renderEpicRow()/
   _renderMilestoneRow() genutzt. */

/* Ticket 3.231 (Massenaktionen): .bl-row-select-wrap ist KEINE Wiederbelebung
   der oben entfernten .bl-row-Klasse -- reiner NEUER Flex-Wrapper um Checkbox
   + <ds-todo-item>, GESCHWISTER-Element (kein Eingriff in ds-todo-item.js).
   Kein explizites align-items -> Default "stretch" macht die Checkbox-Spalte
   automatisch so hoch wie die Karte (grosszuegiges Touch-Ziel ohne feste
   Hoehe, die bei mehrzeiligen Titeln/Meta-Zeilen wieder falsch waere). */
.bl-row-select-wrap {
  display: flex;
  gap: .5rem;
}
.bl-row-select-wrap ds-todo-item {
  flex: 1;
  min-width: 0;
}
.bl-select-check {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  flex-shrink: 0;
  cursor: pointer;
}
.bl-select-check input[type="checkbox"] {
  width: 16px; height: 16px;
  cursor: pointer;
  accent-color: var(--accent);
  border-radius: 3px;
}
@media (max-width: 900px) {
  .bl-select-check { width: 32px; }
  .bl-select-check input[type="checkbox"] { width: 20px; height: 20px; }
  /* Unteraufgabe 3.231.1: Trefferflaeche der Abschnitts-Checkbox auf
     >=40px Kantenlaenge anheben (Touch-Zielgroesse) -- .bl-section-header
     ist eine Flex-Zeile mit align-items:center, ein hoeheres Kind zieht die
     ganze Kopfzeile automatisch mit hoch (kein zusaetzliches CSS am Header
     noetig). Das sichtbare Kaestchen selbst waechst moderat mit (18px statt
     14px), bleibt aber kleiner als die Trefferflaeche. */
  .bl-section-select-check { width: 40px; height: 40px; }
  .bl-section-select-check input[type="checkbox"] { width: 18px; height: 18px; }
}

/* Fix 3C – Epic-Badge. Meilenstein/Zuständig entfallen aus der Zeile
   (Ticket 3.163.8/T4 — Daten unangetastet, weiterhin im Detail-Panel
   sichtbar); Epic bleibt (nicht Teil der Entfernungs-Vorgabe) und
   rueckt ueber den Titel — angelehnt an die Board-Karte
   (ds-todo-item.js .tbc-epic-badge). .bl-badge.ms bleibt fuer die
   (unveraendert bestehenden, aber von render() aus nicht
   aufgerufenen) Gruppen-Header-Zeilen _renderMilestoneRow() erhalten
   — nicht Teil dieser Aenderung. */
.bl-badge {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: 2px 8px; font-size: .72rem;
  border-radius: 4px; font-weight: 500;
  max-width: 100%;
}
.bl-badge-dot {
  width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;
}
.bl-badge-text {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bl-badge.epic::before { content: '◈ '; opacity: .8; margin-right: 2px; }
.bl-badge.ms::before   { content: '◆ '; opacity: .6; margin-right: 2px; }
.bl-badge.epic     { background: var(--accent-light); color: var(--accent-dark); }
.bl-badge.ms       { background: var(--bg-tertiary);  color: var(--text-secondary); }
.bl-badge.empty    { opacity: .4; font-style: italic; }
/* .bl-body ist display:flex (Spalte) -> Kinder stretchen standardmaessig
   auf volle Breite; die Epic-Badge soll sich wie ein Pill an ihren
   Inhalt anpassen statt die ganze Kartenbreite einzunehmen. */
.bl-body .bl-badge.epic { align-self: flex-start; }

/* Fix 3B – Spalten-Header: kleiner, Uppercase, gedimmt, Trennlinie.
   Ticket 3.163.8 (T4): von Grid auf Flex-Bar umgebaut (Zeilen sind
   keine Grid-Spalten mehr) — Meilenstein-/Zustaendig-Sortier-
   Eintraege entfallen (Header + Zellen entfallen aus der
   Listenansicht, Daten unangetastet — die Sortier-Funktionen
   byMs/byAssi bleiben in _sortRows() bestehen, nur der UI-
   Einstiegspunkt entfaellt). */
.bl-header-row {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-wrap: wrap;
  padding: .3rem 16px;
  font-size: .68rem; text-transform: uppercase;
  color: var(--text-tertiary); font-weight: 600; letter-spacing: .05em;
  border-bottom: 1px solid var(--border);
  margin-bottom: .25rem;
}
.bl-header-cell { cursor: pointer; user-select: none; }
.bl-header-cell:hover { color: var(--text-primary); }
.bl-header-cell.active { color: var(--accent); }

.bl-empty {
  text-align: center; padding: 3rem 1rem;
  color: var(--text-tertiary); font-size: .9rem;
}

/* „Aufgabe hinzufügen" am Sektionsende (Ticket 3.163.8/T4) — dieselbe
   .todo-quick-add-trigger-Optik wie ds-todo-list-view.js/
   ds-todo-board-view.js (kein globales CSS-Modul, jede Komponente
   traegt ihr eigenes <style>, s. frontend.md „Component-Ablage"). */
.bl-add-trigger {
  display: flex; align-items: center; gap: .5rem;
  padding: .4rem .75rem; margin-top: .25rem;
  font-size: .82rem; color: var(--text-tertiary);
  cursor: pointer; border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
  user-select: none; background: none; border: none;
  width: 100%; text-align: left;
}
.bl-add-trigger:hover { color: var(--accent); background: var(--accent-light); }
.bl-section-quickadd { margin-top: .25rem; }
/* Ticket 3.128: Touch-Reveal-/Mobile-/Drag-CSS fuer die Zeile selbst
   (ehemals .bl-menu-btn/.bl-row.subtask/.bl-check/.bl-row[draggable]/
   .bl-drag-handle/.dnd-*) lebt seither in ds-todo-item.js
   (TOUCH_REVEAL_CSS + die todo-list-Klassenfamilie) -- diese Datei
   rendert die Zeile nicht mehr selbst, s. Kommentar beim
   .bl-row-Block oben. Der Status-Pillen- und Quick-Menue-Inhalts-CSS
   (frueher hier per String-Interpolation eingebunden) ist aus
   demselben Grund nicht mehr noetig: jede gerenderte
   ds-todo-item-Instanz bringt beides bereits selbst mit. */

/* ── aus page-todos.js (3.85 Paket 7) ──────────────────────────────────────
   Aeusserer Seiten-Rahmen (Shell/Sidebar/Content/Detail-Panel). Zwei ehemals
   interpolierte Stellen sind hier aufgeloest -- s. render() in page-todos.js
   fuer die neue Mechanik:
   - .todos-sidebar/.todos-sidebar-toggle: der boolesche Ein-/Ausklapp-
     Zustand (_sidebarCollapsed) laeuft jetzt ueber die Modifier-Klasse
     .collapsed (Template setzt sie im class-Attribut -- dasselbe, bereits
     bestehende Muster wie .todos-detail-panel.closed weiter unten).
   - .todos-detail-panel: die kontinuierlich per Drag verstellbare Breite
     (_detailWidth) laeuft ueber die CSS-Custom-Property
     --todos-detail-width, gesetzt per style-Attribut im Template UND
     waehrend des Ziehens direkt am DOM (_onDetailResizeStart() in
     page-todos.js, panel.style.setProperty()) -- identisches Muster zu
     --anchor-top/-left/-width weiter unten (Abschnitt "aus
     ds-todo-detail.js"). Der Fallback 320px ist die untere Breiten-Klemme
     derselben Resize-Logik. Eine Custom Property schlaegt (anders als ein
     roher width-Wert per Inline-Style) NICHT die normale Kaskade -- die
     .closed-Regel greift dadurch weiterhin unabhaengig vom zuletzt
     gezogenen Wert. */
.todos-shell {
  display: flex;
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: relative;
}
.todos-sidebar {
  width: 220px;
  min-width: 220px;
  border-right: 1px solid var(--border);
  overflow: hidden;
  overflow-y: auto;
  background: var(--bg-primary);
  flex-shrink: 0;
  transition: width .2s ease, min-width .2s ease;
  position: relative; /* Containing Block fuer den Ziehgriff, Ticket 3.220.2 */
}
.todos-sidebar.collapsed {
  width: 0;
  min-width: 0;
  overflow-y: hidden;
}
/* Ticket 3.297: Position leitet sich aus --ds-sidebar-w ab (gesetzt von
   core/sidebar-resize.js auf .todos-shell, dem gemeinsamen Elternteil von
   .todos-sidebar UND .todos-sidebar-toggle -- s. Docblock dort). Vorher stand
   hier ein roher Wert (208px = ehemalige Festbreite 220px minus halbe
   Knopfbreite), der bei jeder gezogenen Breite falsch war, sobald die Spalte
   ziehbar wurde. Fallback 220px = Default-Breite ohne aktiven Ziehgriff
   (Erstrender vor firstUpdated()/auf Mobile, wo der Griff nie angehaengt
   wird). Die .collapsed-Regel (naechste Zeile) ueberschreibt `left` per
   hoeherer Selektor-Spezifitaet weiterhin unabhaengig vom aktuellen
   Variablenwert -- dieselbe Kaskaden-Eigenschaft wie bei
   --todos-detail-width oben. */
.todos-sidebar-toggle {
  position: absolute;
  left: calc(var(--ds-sidebar-w, 220px) - 12px);
  top: 0.5rem;
  z-index: 5;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--bg-primary);
  cursor: pointer;
  transition: left .2s ease;
  color: var(--text-tertiary);
  padding: 0;
}
.todos-sidebar-toggle.collapsed { left: 0; }
.todos-sidebar-toggle:hover {
  color: var(--text-primary);
  background: var(--bg-secondary);
}
/* Waehrend des Ziehens (body.ds-sidebar-resizing, gesetzt von
   core/sidebar-resize.js fuer jeden der 5 Konsumenten) folgt der Knopf
   OHNE Verzoegerung -- die .2s-ease-Transition ist nur fuer den Ein-/
   Ausklapp-Wechsel gedacht (Klick auf .todos-sidebar-toggle), nicht fuer
   den kontinuierlichen Drag. */
body.ds-sidebar-resizing .todos-sidebar-toggle { transition: none; }
/* Mobile Nav-Bar: nur noch Drawer-Toggle + Kontext-Label — Pills
   (Posteingang/Projekte/Timeline/Board) + Projekt-Select entfernt,
   Navigation läuft vollständig über den Drawer (_renderDrawer()).
   Zeilen-/Kontext-Layout lebt jetzt in der geteilten Klassen-Familie
   .ds-mobile-navbar* (_core.css) — s. auch pages/notes.js. */
@media (max-width: 900px) {
  .todos-sidebar-toggle { display: none; }
}
.todos-content {
  /* Ticket 3.163.17-Zuarbeit (Paket 2): als Custom Property verfuegbar
     machen, damit sticky positionierte Kinder (z.B. die Backlog-
     Abschnitts-Ueberschrift) diesen Scrollport-Innenabstand per
     negativem top ausgleichen koennen, ohne den Wert als Zahl zu
     spiegeln (P-5). Wert selbst UNVERAENDERT auf Desktop. */
  --todos-content-pad: 1.5rem;
  flex: 1;
  overflow-y: auto;
  /* Ticket 3.253.1 -- NUR padding-top haengt an der Variable (mobil
     unten gesenkt), links/rechts/unten bleiben literal 1.5rem -- eine
     Aenderung an --todos-content-pad darf NICHT das horizontale/untere
     Padding mitverschieben (kein ungewollter Layout-Shift dort). Die
     .bl-section-header-Sticky-Korrektur (s.u.) zieht automatisch mit,
     da sie dieselbe Variable liest -- kein zweiter Spiegel-Wert (P-5). */
  padding: var(--todos-content-pad) 1.5rem 1.5rem 1.5rem;
  min-width: 0;
  transition: margin-right var(--transition-slow);
}
@media (max-width: 900px) {
  /* Ticket 3.253.1 -- Domenico-Screenshot: 58px Luecke zwischen der
     mobilen Sub-Nav-Leiste (page-todos.js .ds-mobile-navbar) und dem
     ersten Inhalt (z.B. Board-Spaltenkopf), obwohl .todo-header-titlecol
     mobil immer ausgeblendet ist und .todo-header-searchcol meist
     eingeklappt (s. .page-header-Regel unten). Reduziert den oberen
     Scrollport-Innenabstand von 24px auf 8px -- zusammen mit der
     kollabierten .page-header ergibt das die geforderten <=16px Rest-
     Luecke (8px hier + 8px .board-col-Eigenpadding, das explizit bleibt).
     Nur padding-TOP -- links/rechts/unten unveraendert (s.o.). */
  .todos-content { --todos-content-pad: .5rem; }
}
/* Ticket 3.88: Auf dem Desktop steuert AUSSCHLIESSLICH width das Oeffnen/
   Schliessen (s. .closed unten) -- transform war hier nie mehr als ein
   ruhender translateX(0), der sich NIE aendert (die Mobile-@media-Regel
   weiter unten uebernimmt die eigentliche Schiebe-Animation vollstaendig
   mit eigenen transform-Werten). Trotzdem war die Basisregel bis hierhin
   NICHT "transform: none" -- und jeder transform-Wert ausser none (auch
   die Identitaet translateX(0)) macht das Element zum umgebenden Block
   fuer position:fixed-Nachfahren. Genau das brach die am Feld verankerten
   Popover (Datum/Start-Ende, s. .sb-popover--anchored): deren Koordinaten
   werden in _positionAnchoredPopover() (ds-todo-detail.js) gegen die ECHTEN
   Viewport-Masse berechnet, landeten aber wegen dieses Vorfahren relativ
   zur Panel-Box -- auf typischen Panel-Breiten damit haeufig ausserhalb
   des sichtbaren Bereichs (gemessen: Popover-Linkskante bei 1614px auf
   einem 1400px breiten Fenster). Keine transform-Regel hier -> Desktop
   bleibt viewport-bezogen, ohne die Mobile-Animation zu beruehren.
   Gilt unveraendert weiter fuer Ticket 3.364 (s.u.): weder `position:absolute`
   noch ein gesetzter `z-index` gehoeren zu den Eigenschaften, die einen
   umgebenden Block fuer `position:fixed`-Nachfahren erzeugen (nur
   transform/filter/perspective/will-change/contain tun das) -- die
   Popover bleiben also weiterhin viewport-bezogen korrekt positioniert. */
/* Ticket 3.364: Das Panel legt sich ab hier UEBER den Inhalt statt ihn zu
   stauchen -- vorher ein normales Flex-Kind von .todos-shell (nahm .todos-
   content per flex-shrink echten Platz weg, bei mehrspaltigem Board blieb
   dafuer kaum noch Raum -- Woerter brachen buchstabenweise um). Jetzt
   `position:absolute` innerhalb von .todos-shell (das bereits
   `position:relative` traegt, s.o. -- kein neuer Vorfahre noetig).
   Bewusst `absolute` statt `fixed` wie beim App-weiten `.ds-cal-panel`-
   Vorbild: das haelt das Panel innerhalb der Modul-Huelle (haengt nicht
   unter die Kopfzeile/ueber die Modulgrenze hinaus) und braucht keine
   nachgerechnete Kopfzeilenhoehe. `box-shadow` grenzt die neue Ebene optisch
   vom Inhalt dahinter ab -- OHNE Backdrop (bewusste Abweichung vom
   `.ds-cal-panel`-Muster): das Board soll daneben sichtbar+bedienbar
   bleiben, das Panel ist kein modaler Dialog. z-index 300 ist identisch zum
   bisherigen Wert der Mobile-Fixed-Variante (s. @media weiter unten) --
   liegt damit ueber allem Inhalt dieser Seite (hoechster dort verwendeter
   Wert: 200) und unter Kontextmenue (1100)/Off-Canvas-Schublade (1200),
   s. design-system.md „Aufgaben-Detailpanel ueberlagert statt staucht". */
.todos-detail-panel {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 300;
  width: var(--todos-detail-width, 320px);
  min-width: 0;
  border-left: 1px solid var(--border);
  background: var(--bg-primary);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.todos-detail-panel.closed {
  width: 0;
  min-width: 0;
  pointer-events: none;
}
/* Resize-Griff am linken Panel-Rand (Desktop) */
.todos-detail-resize {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 7px;
  cursor: ew-resize;
  z-index: 10;
  background: transparent;
  transition: background var(--transition);
}
.todos-detail-resize:hover,
.todos-detail-resize.dragging { background: var(--accent-light); }
.todos-detail-panel.closed .todos-detail-resize { display: none; }
@media (max-width: 900px) {
  .todos-sidebar {
    display: none;
  }
  .todos-detail-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: 100vw !important;
    min-width: unset;
    z-index: 300;
    transform: translateX(100%);
    transition: transform var(--transition-slow);
  }
  .todos-detail-resize { display: none; }
  .todos-detail-panel:not(.closed) {
    transform: translateX(0);
  }
}

/* ── aus ds-todo-detail.js (3.85 Paket 7) ──────────────────────────────────
   Detail-Panel (Slide-in von rechts) -- Topbar, Header, Beschreibung,
   aufgeklappte Unteraufgabe, Kommentare, Sidebar-Felder/-Popover. Reihen-
   folge unveraendert zum ursprünglichen Inline-Block übernommen.

   Ein Baustein ist NICHT erneut eingefügt, weil er bereits an anderer
   Stelle dieser Datei steht (kein zweiter Kopie-Ort): der ehemalige
   ${TODO_STATUS_CSS}-Interpolationspunkt (zwischen ".sb-schedule-input"
   und dem Status-Zeile-Baustein-Kommentar unten) -- diese Regeln stehen
   im Abschnitt "aus _todo-status.js" weiter oben (Zeile ~126). ds-todo-
   detail.js war der letzte verbliebene Interpolator (grep-geprüft vor dem
   Entfernen) -- der Export TODO_STATUS_CSS in _todo-status.js ist deshalb
   seither ERSATZLOS entfernt, diese Regeln oben sind die einzige Kopie.

   Zwei CSS-Custom-Properties bleiben bewusst dynamisch (der einzige
   erlaubte Fall, s. Kommentar bei .sb-popover--anchored unten):
   --anchor-top/--anchor-left/--anchor-width werden von
   _positionAnchoredPopover() (ds-todo-detail.js) per style-Attribut im
   Template gesetzt (Koordinaten aus getBoundingClientRect, koennen nicht
   statisch sein). */
.todo-detail-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--bg-primary);
  overflow: hidden;
  position: relative;
}

/* Close button top-right + Ticketnummer/Support-Herkunft (Ticket
   3.163.4 / T7): beide wandern in dieselbe Zeile wie das
   Schliessen-Kreuz, damit die Ueberschrift direkt darunter ohne
   Leerraum beginnt. justify-content:space-between haelt das Kreuz
   IMMER rechts, auch wenn .todo-detail-topbar-left (Details-
   Schalter + Ticketnummer + Support-Hinweis) auf schmalen
   Viewports in eine zweite Zeile umbricht (flex-wrap dort, s.u.) —
   align-items:flex-start verankert das Kreuz dabei oben statt es
   zwischen zwei Zeilen zu zentrieren. */
.todo-detail-topbar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.5rem 0.5rem 0;
  flex-shrink: 0;
}
.todo-detail-topbar-left {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
  min-width: 0;
  flex: 1 1 auto;
}
.todo-detail-close {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
  padding: 0.3rem;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  transition: color var(--transition), background var(--transition);
}
.todo-detail-close:hover { color: var(--text-primary); background: var(--bg-secondary); }

/* Swipe-Griff (Ticket 3.163.7 / T9, B5) — analog .ds-more-handle-row/
   .ds-more-handle (nav.css) bzw. .ds-note-nav-sheet-handle-row (Notes-
   Modul, component-lokal) — dieselbe visuelle Konvention app-weit,
   hier ebenfalls component-lokal definiert (Todos-Modul hat kein
   eigenes _todos.css-Partial). Tap schliesst zusätzlich sofort. */
.todo-detail-swipe-handle-row {
  display: flex;
  justify-content: center;
  padding: 0.5rem 0 0.25rem;
  cursor: pointer;
}
.todo-detail-swipe-handle {
  width: 36px;
  height: 4px;
  background: var(--border);
  border-radius: 2px;
}

/* Mobile-Metadaten-Drawer-Schalter (Spec 20260730) — links in
   .todo-detail-topbar-left (Ticket 3.163.4 / T7: kein eigenes
   margin-right:auto mehr noetig, das leistet jetzt
   justify-content:space-between auf dem Eltern-Flex). */
.todo-detail-sidebar-toggle-btn {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  font-size: 0.8rem;
  font-weight: 600;
  padding: 0.4rem 0.6rem;
  min-height: 44px;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
}
.todo-detail-sidebar-toggle-btn:hover { color: var(--text-primary); background: var(--bg-secondary); }
.todo-detail-sidebar-toggle-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
}

/* 2-Spalten-Body */
.todo-detail-split {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  overflow: hidden;
}
.todo-detail-main {
  overflow: hidden;
  min-height: 0;
  padding: 0.5rem 1.25rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.todo-detail-sidebar {
  overflow-y: auto;
  padding: 1rem 1rem 1.25rem;
  border-left: 1px solid var(--border);
  background: var(--bg-primary);
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}
/* Mobile-Metadaten-Drawer (Spec 20260730): dieselbe Sidebar, aber
   eingebettet in .ds-drawer--right (page-todos.js) statt in
   .todo-detail-split — kein linker Trennstrich noetig, der Drawer
   selbst hat bereits einen border-left (s. _core.css). */
.todo-detail-sidebar--drawer { border-left: none; }
@media (max-width: 900px) {
  .todo-detail-split {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Ticketnummer (Spec 20260730 P4) — seit Ticket 3.163.4 / T7 Teil
   von .todo-detail-topbar-left (Zeile mit dem Schliessen-Kreuz)
   statt eigener Zeile ueber dem Titel; kein eigenes CSS mehr
   noetig, .ds-ticket-badge--lg (_core.css) reicht als Inline-Item. */

/* Support-Ticket-Herkunftshinweis (Ticket 3.123.3 / T3) — s.
   _renderSupportTicketHint(). --link ist nur für Platform-Admins
   gerendert (klickbar, springt zur Support-Admin-Ansicht). Seit
   Ticket 3.163.4 / T7 ebenfalls Teil von .todo-detail-topbar-left,
   auf derselben Ebene wie die Ticketnummer — kein eigener
   margin-bottom mehr noetig (Zeilenabstand kommt vom Flex-Wrap-Gap
   des Eltern-Containers, falls die Zeile auf schmalen Viewports
   umbricht). */
.todo-detail-support-hint {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: fit-content;
  max-width: 100%;
  padding: 0.3rem 0.6rem;
  border-radius: var(--radius-sm);
  background: var(--accent-light);
  color: var(--accent);
  font-size: 0.78rem;
  font-weight: 500;
  flex-shrink: 0;
}
.todo-detail-support-hint svg { flex-shrink: 0; }
.todo-detail-support-hint strong { font-weight: 700; }
button.todo-detail-support-hint--link {
  border: none;
  cursor: pointer;
  text-align: left;
  transition: background var(--transition), color var(--transition);
}
button.todo-detail-support-hint--link:hover {
  background: var(--accent);
  color: #fff;
}

/* Header (title + checkbox) */
.todo-detail-header {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  flex-shrink: 0;
}
.todo-detail-checkbox {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid var(--border);
  flex-shrink: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color var(--transition), background var(--transition);
  margin-top: 2px;
  background: transparent;
}
.todo-detail-checkbox:hover { border-color: var(--teal); }
/* Ticket 3.189: .prio-* MÜSSEN vor .done stehen -- gleiche Spezifität
   (je 2 Klassen), bei "erledigt UND Prio gesetzt" trägt eine Karte
   BEIDE Klassen gleichzeitig und die spätere Regel gewinnt (Quell-
   reihenfolge entscheidet, s. frontend.md "Eine Media-Query erhöht
   die Spezifität NICHT"-Falle, hier ohne Media-Query dieselbe
   Ursache). .done muss daher zuletzt stehen, sonst überschreibt eine
   gesetzte Priorität die Erledigt-Rahmenfarbe. */
.todo-detail-checkbox.prio-1 { border-color: var(--coral); }
.todo-detail-checkbox.prio-2 { border-color: var(--amber); }
.todo-detail-checkbox.prio-3 { border-color: var(--accent); }
.todo-detail-checkbox.done { background: var(--teal); border-color: var(--teal); }
.todo-detail-title {
  flex: 1;
  width: 100%;
  min-width: 0;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.35;
  border: none;
  outline: none;
  background: transparent;
  resize: none;
  padding: 0;
  font-family: inherit;
  min-height: 28px;
}
.todo-detail-title.done-text {
  text-decoration: line-through;
  color: var(--text-tertiary);
}
/* Ellipsis bei abgeschnittenem Titel der aufgeklappten Unteraufgabe
   (Ticket 3.163.14, Akzeptanzkriterium 6) — NUR auf Mobile und NUR
   für dieses eine Input-Element (Klasse .todo-subtask-expand-
   title-input, s. _renderExpandedSubtask()), NICHT für die
   geteilte Klasse .todo-detail-title als Ganzes: die trägt auch
   das Textarea-Element des Haupt-Tickets (mehrzeilig, waechst mit
   dem Inhalt) -- dort würde overflow:hidden/white-space:nowrap
   das Auto-Wachsen kaputt machen. Ein natives Input-Element hat
   bereits overflow:hidden per UA-Default; hier trotzdem explizit
   deklariert (browser-uebergreifend zuverlaessig, s. text-overflow-
   Doku: greift nur mit overflow:hidden + white-space:nowrap). */
@media (max-width: 900px) {
  .todo-subtask-expand-title-input {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
}

/* Inline-Trigger-Dropdown unter dem Titel */
.title-trigger-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 250;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  min-width: 280px;
  max-width: 360px;
  max-height: 360px;
  overflow-y: auto;
  padding: 0.35rem;
}
.title-trigger-dropdown .sb-popover-item.hl {
  background: var(--accent-light);
}
/* Datum-Trigger ("!") im Titelfeld -- Ticket 3.276-Nachtrag. <ds-todo-
   datepicker> bringt bereits eine vollstaendige Karten-Optik mit (eigener
   Rahmen/Radius/Schatten, s. .datepicker-wrap) -- ein zusaetzlicher
   .title-trigger-dropdown-Rahmen DARUM waere "ein Fenster im Fenster"
   (identisches Nutzer-Feedback wie bei .todo-detail-datepicker-anchor
   weiter unten in dieser Datei). Bewusst OHNE max-height/overflow -- der
   Picker soll vollstaendig sichtbar sein, exakt wie in der
   Schnellerfassung (ds-todo-quick-add.js .qa-datepicker-anchor, dort als
   Inline-Style vorbestehend -- hier als Klasse fuer neuen Code, s.
   frontend.md "CSS: Klassen statt Inline-Styles"). */
.title-trigger-datepicker-anchor {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 250;
}
/* Sehr schmale Schubladen (320px-Klasse): links verankert wuerde die feste
   280px-Breite von .datepicker-wrap ueber den rechten Bildschirmrand hinaus
   schieben (Ausloeser-Feld startet erst hinter Checkbox+Abstand). Rechts
   verankern haelt den Picker auf dieser Breite vollstaendig sichtbar --
   dasselbe Prinzip wie .quick-add-wrap.compact .qa-datepicker-anchor
   (dortiger Kompakt-Modus), hier ueber Media-Query statt Property, weil
   der Titel-Trigger kein "compact"-Aequivalent kennt. */
@media (max-width: 340px) {
  .title-trigger-datepicker-anchor {
    left: auto;
    right: 0;
  }
}

/* Description trigger-look — Punkt 9/4.4: die Beschreibung fuellt den
   Rest der Ticket-Tab-Hoehe (.todo-detail-ticket-body ist flex-column)
   und scrollt selbst, statt in einer kleinen Fixhoehe abzuschneiden.
   Dafür braucht die Zeile "stretch" statt "flex-start" -- Icon/Button
   bekommen unten ein eigenes align-self:flex-start, damit sie trotzdem
   oben ausgerichtet bleiben statt ueber die volle (jetzt hohe) Zeile
   vertikal zu zentrieren. */
.todo-desc-wrap {
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
  color: var(--text-tertiary);
  font-size: 0.85rem;
  flex: 1;
  min-height: 0;
}
.todo-desc-wrap .desc-icon {
  margin-top: 0.2rem;
  flex-shrink: 0;
  color: var(--text-tertiary);
  align-self: flex-start;
}
.todo-desc-wrap ds-rich-editor,
.todo-desc-wrap .ds-rich-editor {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.todo-desc-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* .ds-rich-editor-body ist generisch auf max-height:280px gedeckelt
   (_core.css „ds-rich-editor (Quill v2)"-Sektion, für die vielen
   kompakten Bestandsverwendungen gedacht) -- hier gezielt aufgehoben,
   analog dem bestehenden Mail-Compose-Muster (.mail-compose-editor-wrap
   .ds-rich-editor-body). Gilt für Lese- UND Bearbeitungsmodus gleich,
   da readOnly nur die Toolbar versteckt, dieselbe .ds-rich-editor-body
   bleibt bestehen (Punkt 4.4 + 9 sind derselbe Kasten). */
.todo-desc-body .ds-rich-editor-body {
  flex: 1;
  min-height: 0;
  max-height: none;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.todo-desc-body .ql-container {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
/* Bugfix: Quill (Snow-Theme) setzt .ql-container bewusst OHNE
   eigenen border-top (quill.snow.min.css: ".ql-toolbar.ql-snow +
   .ql-container.ql-snow{border-top:0}", ein Adjacent-Sibling-
   Selektor) -- im Bearbeitungsmodus schliesst die Toolbar direkt
   darueber die Box optisch mit ihrem eigenen unteren Rand ab. Der
   Selektor bleibt aber auch aktiv, wenn ds-rich-editor.js die
   Toolbar per display:none ausblendet (sie ist weiterhin ein DOM-
   Geschwister) -- im Lesemodus (P3-Default für bestehende
   Aufgaben) fehlt dadurch jede obere Kante. Nur HIER, nur im
   Lesemodus, den Rand + die Eck-Rundung nachtragen (kein Eingriff
   in ds-rich-editor.js/_core.css noetig -- die generische
   Bottom-Rundung kommt bereits von dort). */
.todo-desc-body--readonly .ds-rich-editor-body {
  border-top: 1px solid var(--border);
  border-top-left-radius: var(--radius-md);
  border-top-right-radius: var(--radius-md);
}
.todo-desc-edit-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  padding: 0.3rem;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  flex-shrink: 0;
  margin-top: 0.1rem;
  align-self: flex-start;
  transition: color var(--transition), background var(--transition);
}
.todo-desc-edit-btn:hover { color: var(--accent); background: var(--bg-secondary); }
.todo-detail-contact-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  flex-shrink: 0;
}

/* Subtask add trigger */
.subtask-add-trigger {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: none;
  border: none;
  padding: 0.3rem 0;
  color: var(--text-tertiary);
  font-size: 0.85rem;
  cursor: pointer;
}
.subtask-add-trigger:hover { color: var(--accent); }

/* ── Reiter "Tickets" eines Epics (Ticket 3.261.2, Epics P2) ─────────────
   Ersetzt den Reiter "Unteraufgaben" ausschließlich bei task_type='epic'
   (s. Klassendoc bei ds-todo-detail.js::_renderEpicTicketsTab()). Einfache
   Zeilen statt <ds-todo-item> -- hier reichen vier Info-Spalten + zwei
   Aktionen (Status ändern, entfernen), keine volle Karten-Interaktion wie
   bei Unteraufgaben nötig. */
.epic-tickets-tab { display: flex; flex-direction: column; gap: 0.75rem; }
.epic-ticket-list { display: flex; flex-direction: column; gap: 0.375rem; }
.epic-ticket-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
}
.epic-ticket-type { display: flex; align-items: center; flex-shrink: 0; color: var(--text-tertiary); }
.epic-ticket-title {
  flex: 1;
  min-width: 0;
  font-size: 0.875rem;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.epic-ticket-remove {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
}
.epic-ticket-remove:hover { background: var(--coral-light); color: var(--coral); }

.epic-ticket-add { position: relative; }
.epic-ticket-add-dropdown {
  position: absolute;
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  z-index: 300;
  max-height: 200px;
  overflow-y: auto;
}
.epic-ticket-add-option {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.375rem 0.625rem;
  font-size: 0.8125rem;
  cursor: pointer;
}
.epic-ticket-add-option:hover { background: var(--bg-secondary); }
.epic-ticket-add-option-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.epic-ticket-add-empty {
  padding: 0.375rem 0.625rem;
  font-size: 0.8rem;
  color: var(--text-tertiary);
}

/* Epic-Ticket-Badge mit eigener Farbe (Ticket 3.261.2) -- die Custom
   Properties kommen inline vom jeweiligen Datensatz (t.epic_color ist frei,
   innerhalb der festen Palette EPIC_COLOR_PALETTE, gewählt -- s.
   ds-todo-detail.js::epicContrastFg()). Compound-Selektor (0,2,0) statt
   nur .ds-ticket-badge--epic, damit die Regel .ds-ticket-badge--lg
   (_core.css, ebenfalls 0,1,0) unabhängig von der Partial-Reihenfolge im
   gebauten components.css zuverlässig überschrieben wird. */
.ds-ticket-badge.ds-ticket-badge--epic {
  background: var(--epic-badge-bg, var(--bg-secondary));
  color: var(--epic-badge-fg, var(--text-tertiary));
}

/* Unteraufgaben-Zeile (Ticket 3.163.6/T8): nutzt seit diesem Ticket
   dieselbe Kartenkomponente wie Board/Backlog (<ds-todo-item compact>,
   P-5 -- "kein dritter Kartenbau", s. modules/todos.md T8). Der Wrapper
   trägt nur noch die Drag&Drop-Semantik (draggable, Griff-Cursor) +
   stapelt optional die aufgeklappte Box darunter -- KEINE eigene
   Card-Optik mehr (.ds-card-tile kommt jetzt von <ds-todo-item> selbst). */
.todo-subtask-detail-row {
  display: flex;
  flex-direction: column;
  margin-bottom: 0.4rem;
  cursor: grab;
}
.todo-subtask-detail-row.dnd-dragging { opacity: 0.4; }

/* Umschalt-Wrapper: voller Kopf+Reiter-Block (Desktop) vs. schmale
   Kontext-Leiste (Mobile) während eine Unteraufgabe aufgeklappt ist
   (Nachschaerfung Ticket 3.163.6, 09.08.2026, Domenico-Korrektur +
   dringender Nachtrag "Mobil kannst du die schmale Leiste lassen,
   wie es JETZT ist"). Beide Bloecke werden von _renderContent()
   IMMER gleichzeitig gerendert -- CSS blendet je nach Breite den
   jeweils falschen aus. Bewusst KEIN JS-isMobile()-Check (waere die
   einfachere Alternative gewesen): Lit rendert nur bei State-
   Aenderung neu, nicht bei einer reinen Fenster-Groessenaenderung --
   ein rein zur Renderzeit ausgewerteter Check würde beim Verkleinern
   des Fensters bis zum nächsten Re-Render den falschen (vollen)
   Kopf zeigen. Der CSS-Umweg kostet dafür etwas doppeltes Markup
   (siehe .todo-detail-expanded-parent--mobile { display:none } als
   Default -- der schmale Block existiert im DOM, ist aber unsichtbar
   und nicht interaktiv, solange Desktop-Breite gilt). Breakpoint
   900px = Projekt-Standard (isMobile() in utils.js). */
.todo-detail-expanded-parent--desktop {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  flex-shrink: 0;
}
.todo-detail-expanded-parent--mobile { display: none; }
@media (max-width: 900px) {
  .todo-detail-expanded-parent--desktop { display: none; }
  .todo-detail-expanded-parent--mobile {
    display: block;
    flex-shrink: 0;
  }
}

/* Eltern-Kontext-Leiste ueber der aufgeklappten Unteraufgabe
   (Nachschaerfung Ticket 3.163.6, Punkt 1) — kompakte, NICHT
   editierbare Kurzfassung von .todo-detail-header (Ticketnummer +
   Titel des Haupt-Tickets), s. _renderExpandedSubtaskParentBar().
   🔒 Seit der ZWEITEN Fassung (09.08.2026) nur noch auf MOBILE
   (≤900px) sichtbar, s. .todo-detail-expanded-parent--mobile oben --
   auf Desktop zeigt _renderMainHeader() den vollen Kopf+Reiter-Block.
   Als <button> gerendert (Tastatur-bedienbar per Enter/Space);
   border/background/font sind hier vollstaendig deklariert statt
   von .todo-detail-header uebernommen (eigenstaendige, kompaktere
   Optik -- eine editierbare 1.15rem-Titelzeile ZUSAETZLICH zu der
   der Unteraufgabe direkt darunter waere verwirrend). flex-shrink:0
   haelt sie in .todo-detail-main (display:flex;flex-direction:column)
   auf ihrer natuerlichen Hoehe, die Unteraufgaben-Box darunter
   (flex:1) nimmt den Rest. */
.todo-detail-parent-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.45rem 0.65rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-primary);
  font: inherit;
  text-align: left;
  cursor: pointer;
  flex-shrink: 0;
  min-width: 0;
  transition: background var(--transition), border-color var(--transition);
}
.todo-detail-parent-bar:hover,
.todo-detail-parent-bar:focus-visible {
  background: var(--bg-secondary);
  border-color: var(--accent);
}
.todo-detail-parent-bar:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.todo-detail-parent-bar-icon {
  display: flex;
  color: var(--text-tertiary);
  flex-shrink: 0;
  transition: color var(--transition);
}
.todo-detail-parent-bar:hover .todo-detail-parent-bar-icon,
.todo-detail-parent-bar:focus-visible .todo-detail-parent-bar-icon {
  color: var(--accent);
}
.todo-detail-parent-bar-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-secondary);
}
.todo-detail-parent-bar-title.done-text {
  text-decoration: line-through;
  color: var(--text-tertiary);
}

/* Ticketnummer per Klick kopieren (Ticket 3.163.6, Punkt B, 2026-08-09)
   — Opt-in-Modifier statt Aenderung an .ds-ticket-badge selbst (die
   Basisklasse steht app-weit an mehreren unverdrahteten Stellen, z.B.
   dashboard-widgets.js/ds-todo-backlog.js/ds-todo-timeline-row.js, als
   reiner Text -- ein globaler Cursor/Hover ohne Klick-Handler waere
   dort eine falsche Zusage). Als <button> gerendert; border/margin
   zurueckgesetzt, Farbe/Groesse/Pill-Hintergrund kommen unveraendert
   von .ds-ticket-badge/--lg weiter (Autor-Deklarationen dort schlagen
   die Button-UA-Defaults ohnehin, unabhaengig vom Element-Typ). Neu
   daher komponentenlokal statt in _core.css (dieselbe Begruendung wie
   .todo-detail-parent-bar oben) — bei einem zweiten Konsumenten
   (z.B. ds-todo-item.js) dorthin heben. */
.ds-ticket-badge--copyable {
  display: inline-flex;
  align-items: center;
  border: none;
  margin: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: color var(--transition), background var(--transition);
}
.ds-ticket-badge--copyable:hover,
.ds-ticket-badge--copyable:focus-visible {
  color: var(--accent);
  background: var(--accent-light);
}
.ds-ticket-badge--copyable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Aufgeklappte Unteraufgabe (E4/T8) — eigene Statusleiste + Formular
   unterhalb der Zeile, "an Ort und Stelle". */
/* Aufgeklappte Unteraufgabe (Nachschaerfung Punkt 1/2) — fuellt seither
   ALS GANZES .todo-detail-main (s. _renderContent()) statt inline
   unter einer Zeile zu hängen: flex:1/min-height:0/overflow:hidden
   machen die Karte zum Scroll-Container-Rahmen für den Tab-Inhalt
   (.todo-subtask-expand-body trägt das eigentliche Scrollen, analog
   .todo-detail-tab-content/.todo-detail-tab-scroll der Hauptaufgabe
   -- Kopfbereich+Werkzeugleiste bleiben dadurch fix sichtbar). */
.todo-subtask-expand {
  margin: 0;
  padding: 0.75rem 0.85rem 0.85rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  cursor: default;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
/* Etwas knapperer Abstand zwischen Topline/Header/Werkzeugleiste/Body
   NUR auf Mobile (Ticket 3.163.14, Akzeptanzkriterium 3: Inhalt
   beginnt <=285px) — drei Luecken × 0.5rem/8px sind auf Desktop
   unveraendert richtig, auf Mobile bringt die kompaktere
   Werkzeugleiste (s.u.) schon den Hauptgewinn, dieser Rest schafft
   zusaetzlich Sicherheitsabstand zur Grenze. */
@media (max-width: 900px) {
  .todo-subtask-expand { gap: 0.4rem; }
}
.todo-subtask-expand-loading {
  color: var(--text-tertiary);
  font-size: 0.82rem;
  padding: 0.4rem 0;
}
/* Ticketnummer-Zeile ueber Checkbox+Titel (Nachschaerfung Punkt 2,
   analog .todo-detail-topbar-left der Hauptaufgabe). Traegt seit dem
   Nachtrag 09.08.2026 zusaetzlich das Zuklappen-Kreuz rechtsbuendig
   (s. .todo-subtask-expand-close unten) -- immer genau zwei moegliche
   Kinder (Ticketnummer-Badge optional, Kreuz immer), daher reicht
   margin-left:auto auf dem Kreuz statt justify-content:space-between
   (funktioniert auch OHNE Badge -- ein einzelnes Flex-Kind mit
   space-between bliebe sonst links statt rechts). */
.todo-subtask-expand-topline { display: flex; align-items: center; }
/* Blaetter-Pfeile in der Ticketnummer-Zeile (Ticket 3.163.14) —
   NUR auf Mobile sichtbar (auf Desktop bleiben sie in der
   Werkzeugleiste, s. .todo-subtask-expand-toolbar-desktop unten).
   margin-left:auto auf DIESEM Wrapper (statt weiterhin auf dem
   Kreuz) zieht Pfeile+Kreuz gemeinsam nach rechts -- haetten BEIDE
   margin-left:auto, würde CSS den freien Platz auf beide Margins
   AUFTEILEN (grosse Luecke zwischen Pfeilen und Kreuz statt eng
   beieinander). Das Kreuz bekommt daher auf Mobile stattdessen
   einen festen kleinen Abstand (Adjacent-Sibling-Selektor unten). */
.todo-subtask-expand-topline-nav { display: none; }
@media (max-width: 900px) {
  .todo-subtask-expand-topline-nav {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    margin-left: auto;
  }
  .todo-subtask-expand-topline-nav + .todo-subtask-expand-close {
    margin-left: 0.35rem;
  }
}
.todo-subtask-expand-toolbar { flex-wrap: wrap; }
/* Zwei Geschwister-Gruppen (Ticket 3.163.14) — CSS zeigt je Breite
   nur eine (s. Klassendoc bei _renderExpandedSubtask()). Desktop-
   Gruppe ist standardmaessig sichtbar (unveraendertes Bestands-
   verhalten inkl. eigenem flex-wrap für schmalere Panel-Breiten),
   Mobile-Gruppe standardmaessig display:none. */
.todo-subtask-expand-toolbar-desktop {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  flex: 1;
  min-width: 0;
  flex-wrap: wrap;
}
.todo-subtask-expand-toolbar-mobile { display: none; }
@media (max-width: 900px) {
  .todo-subtask-expand-toolbar-desktop { display: none; }
  .todo-subtask-expand-toolbar-mobile {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 1;
    min-width: 0;
  }
  /* Knapperes vertikales Padding NUR auf Mobile (Akzeptanzkriterium
     1: Werkzeugleiste <= 48px) -- .ds-panel-toolbar bringt
     .5rem/8px, mit dem 32px hohen Inhalt (Segment/Save-Icon) plus
     1px border-bottom waeren das 49px. Diese Regel liegt in der
     Media-Query und greift daher nur unterhalb 900px -- Desktop
     bleibt unveraendert bei .5rem. */
  .todo-subtask-expand-toolbar { padding: 0.4rem 0.75rem; }
}
/* Reiter-Segment auf Mobile (Ticket 3.163.14) — reused
   .contact-status-segment/.contact-status-seg-btn (_core.css,
   dasselbe Muster wie das "Typ"-Feld der Sidebar oben), aber mit
   eigener Groesse statt der generischen Mobile-Vollbreiten-Variante
   (_core.css setzt dort width:100%/height:40px -- das würde diese
   Zeile alleine fuellen und "Speichern" in eine zweite Zeile
   zwingen). Hoehe 32px = identisch zu .ds-toolbar-item (Desktop-
   Pendant), haelt die gesamte Werkzeugleiste bei <=48px (32 Inhalt +
   2×8px Padding von .ds-panel-toolbar, Akzeptanzkriterium 1).
   min-width:0 + Label als eigener <span> mit Ellipsis: der lange
   Text "Kommentare" darf bei sehr schmalen Screens abschneiden,
   ohne dass Segment/Zeile insgesamt ueberläuft — das Zaehl-Badge
   sitzt ausserhalb des Label-<span> und bleibt daher IMMER
   sichtbar (Akzeptanzkriterium 5). */
.todo-subtask-expand-toolbar-mobile .contact-status-segment {
  width: auto;
  flex: 1;
  min-width: 0;
}
.todo-subtask-expand-toolbar-mobile .contact-status-seg-btn {
  flex: 1;
  min-width: 0;
  height: 32px;
  padding: 0 0.35rem;
  font-size: 0.72rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
}
.todo-subtask-expand-seg-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Zaehl-Badge (Ticket 3.163.14) — flex-shrink:0, damit es NIE mit
   dem Label um Platz konkurriert (der Label-<span> schrumpft
   zuerst, s.o.). */
.todo-subtask-expand-toolbar-mobile .contact-status-seg-btn .badge { flex-shrink: 0; }
/* Icon-only "Speichern" auf Mobile (Ticket 3.163.14) — derselbe
   Handler wie der Textknopf der Desktop-Gruppe (_saveExpSubNow()),
   nur die Beschriftung wird zum Symbol (title+aria-label tragen
   weiterhin den Text). 32px = wie die Segment-Buttons daneben, damit
   kein Zeilenversatz entsteht (Akzeptanzkriterium 2). */
.todo-subtask-expand-save-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  transition: background var(--transition);
}
.todo-subtask-expand-save-icon:hover { background: var(--accent-dark); }
/* 🔒 Nachtrag 09.08.2026: umgezogen aus der Werkzeugleiste in die
   Ticketnummer-Zeile (s.o.) -- min-width/min-height 44px = App-
   Konvention für Touch-Trefferflaechen (frontend.md „Mobile"), die
   Ticketnummer-Zeile ist schmaler als eine Werkzeugleiste und braucht
   dafür eine explizite Mindestgroesse (das Icon selbst bleibt 12px,
   padding+min-width/-height schaffen die Trefferflaeche drumherum). */
.todo-subtask-expand-close {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  margin-left: auto;
  flex-shrink: 0;
  padding: 0.3rem;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
}
.todo-subtask-expand-close:hover { color: var(--text-primary); background: var(--bg-tertiary); }
/* Vor-/Zurueck-Navigation (Nachschaerfung Punkt 4) — reused
   .ds-toolbar-item--icon-only (bestehende Klasse, _core.css), nur der
   deaktivierte Zustand ist hier neu (app-weit bisher ungenutzt, daher
   bewusst modul-lokal statt in _core.css gescoped, P-8 "neues CSS nur
   mit Begruendung": kein bestehender Konsument, keine Nebenwirkung). */
.todo-subtask-expand-nav-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.todo-subtask-expand-nav-btn:disabled:hover { background: var(--bg-primary); }
/* Scroll-Container für den aktiven Reiter-Inhalt — Kopfbereich +
   Werkzeugleiste bleiben davor fix (s. Kommentar bei .todo-subtask-expand). */
.todo-subtask-expand-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
/* Beschreibungs-Editor der Unteraufgabe (Nachtrag zu Punkt 2/6, per
   Domenico-Meldung "immer die gleiche Hoehe bleibt drin"): fruehere
   Fassung (Ticket 3.163.6 Erstumsetzung) deckelte hier fest auf
   200px -- ein Rest aus der ALTEN, engen Inline-Aufklappung unter der
   Zeile. Seit diesem Umbau lebt der Editor in .todo-subtask-expand-body
   (voller Hauptbereich, s.o.), genau wie der Beschreibungs-Editor des
   Haupt-Tickets in .todo-detail-ticket-body -- daher hier 1:1 dasselbe
   Wachsen+Scrollen-Muster (P-5): .ds-rich-editor selbst wird zum
   flex:1-Spalten-Item, das den Rest der verfuegbaren Hoehe fuellt und
   NUR IN SICH SELBST scrollt (.ql-container), statt in einer kleinen
   Fixbox abzuschneiden. Vergleiche .todo-desc-wrap ds-rich-editor /
   .todo-desc-body .ds-rich-editor-body / .todo-desc-body .ql-container
   weiter oben (identische drei Regeln, andere Klasse). */
.todo-subtask-expand-desc {
  width: 100%;
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* 🔒 Ohne diese Regel wuchs die Box bei langem Inhalt ueber ihren
   Rahmen hinaus (gefunden + gefixt beim Funktionstest dieses
   Nachtrags): <ds-rich-editor> ist Light-DOM und rendert INTERN
   selbst noch einen Wrapper-Div mit Klasse ".ds-rich-editor" ZWISCHEN
   dem Custom-Element und ".ds-rich-editor-body" (s. Kommentar bei
   .todo-desc-body weiter oben). Ohne min-height:0 auf DIESEM inneren
   Wrapper bricht die flex:1/min-height:0-Kette dort ab -- der Editor
   waechst dann mit seinem Inhalt statt zu klemmen+intern zu scrollen.
   Identisch zur Regel ".todo-desc-wrap ds-rich-editor, .todo-desc-wrap
   .ds-rich-editor" weiter oben (P-5, dort werden beide Ebenen bereits
   in einer Regel erfasst). */
.todo-subtask-expand-desc .ds-rich-editor {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.todo-subtask-expand-desc .ds-rich-editor-body {
  flex: 1;
  min-height: 0;
  max-height: none;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.todo-subtask-expand-desc .ql-container {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
/* Metadaten-Reiter (Nachschaerfung Punkt 5) — Feld-Optik 1:1 aus der
   echten Sidebar (.sidebar-field/.sb-popover/…), s. Klassendoc bei
   _renderExpandedSubtaskMeta(). max-width haelt die Spalte so schmal
   wie die echte 300px-Sidebar ("genauso aussehen wie in der Sidebar
   des Haupt-Tickets"), obwohl der Metadaten-Reiter in der breiten
   Hauptspalte lebt. */
.todo-subtask-expand-meta {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  max-width: 320px;
}
/* Der Datum-Popover trägt bewusst KEINE eigene Karten-Optik (kein
   .sb-popover -- <ds-todo-datepicker> bringt schon eine vollstaendige
   Oberflaeche mit, ein zusaetzlicher Rahmen waere "ein Fenster im
   Fenster", identische Begruendung wie bei der echten Sidebar,
   s. Kommentar bei .todo-detail-datepicker-anchor). Da der Metadaten-
   Reiter (anders als die Sidebar) kein position:fixed nutzt, braucht
   er hier zusaetzlich etwas Abstand nach oben zum Ausloeser-Feld.  */
.todo-subtask-expand-meta .todo-detail-datepicker-anchor { margin-top: 0.35rem; }

/* Unteraufgaben-Reihenfolge per Drag & Drop (Ticket 3.19, Paket B3) --
   Optik 1:1 aus ds-todo-board-view.js uebernommen (P-5), hier komponen-
   tenlokal definiert (Light-DOM: <style> gilt global, s. mail.md-Muster
   .mail-compose-editor-wrap .ds-rich-editor-body). Eigener Indikator-
   ID/-Klassenname (__subtask_dnd_indicator__/.subtask-dnd-drop-indicator)
   statt Board-Namen, um keine Kollision mit einer gleichzeitig
   gerenderten Board-Spalte zu riskieren. */
.subtask-list-body { display: flex; flex-direction: column; }
.subtask-dnd-drop-indicator {
  height: 2px;
  background: var(--accent);
  border-radius: 1px;
  margin: 0 4px 0.4rem;
  pointer-events: none;
  flex-shrink: 0;
  position: relative;
}
.subtask-dnd-drop-indicator::before {
  content: '';
  position: absolute;
  left: -4px;
  top: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

/* Comments */
.comment-row {
  display: flex;
  gap: 0.625rem;
  padding: 0.5rem 0;
}
.comment-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--accent-light);
  color: var(--accent);
  font-size: 0.7rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.comment-body { flex: 1; min-width: 0; }
.comment-meta { display: flex; align-items: baseline; gap: 0.5rem; margin-bottom: 0.2rem; }
.comment-author { font-size: 0.8rem; font-weight: 600; color: var(--text-primary); }
.comment-time   { font-size: 0.72rem; color: var(--text-tertiary); }
.comment-text   { font-size: 0.83rem; color: var(--text-secondary); line-height: 1.5; }

/* Comment input row with avatar */
.comment-input-row {
  display: flex;
  gap: 0.625rem;
  align-items: flex-start;
  margin-top: 0.75rem;
}
.comment-input-row .comment-input-field {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.3rem 0.75rem;
}
.comment-input-row textarea {
  flex: 1;
  border: none;
  outline: none;
  resize: none;
  background: transparent;
  font-family: inherit;
  font-size: 0.85rem;
  color: var(--text-primary);
  min-height: 28px;
  line-height: 1.4;
  padding: 0.2rem 0;
}
.comment-send-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  padding: 0.25rem;
  display: flex;
}
.comment-send-btn:hover:not(:disabled) { color: var(--accent); }
.comment-send-btn:disabled { opacity: 0.4; cursor: not-allowed; }

/* ── Sidebar field rows ────────────────────────────────── */
.sidebar-field { display: flex; flex-direction: column; gap: 0.35rem; }
.sidebar-field-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
  padding: 0.1rem 0;
  border-radius: var(--radius-sm);
  transition: color var(--transition);
}
.sidebar-field-header:hover { color: var(--text-primary); }
.sidebar-field-header.no-toggle { cursor: default; }
.sidebar-field-header.no-toggle:hover { color: var(--text-secondary); }
.sidebar-field-header .add-btn,
.sidebar-field-header .clear-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  padding: 0.15rem 0.2rem;
  display: flex;
  align-items: center;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
  pointer-events: none;
}
.sidebar-field-header .clear-btn { pointer-events: auto; }
.sidebar-field-header:hover .add-btn { color: var(--text-primary); }
.sidebar-field-header .clear-btn:hover {
  color: var(--coral);
  background: var(--coral-light);
}
.sidebar-field-header .deadline-label { color: var(--coral); }

/* Typ-Feld (Aufgabe/Fehler, Ticket 3.123.1 / T1) — reused
   .contact-status-segment/.contact-status-seg-btn (_core.css), nur
   innerhalb .sidebar-field gescoped (kein globaler Eingriff in die
   Basisklasse, s. design-system.md "Aktiv/Inaktiv-Control"). Icon
   braucht Flex-Ausrichtung, die Basisklasse selbst hat keine. */
.sidebar-field .contact-status-seg-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
}
.sidebar-field .contact-status-seg-btn.is-bug-active {
  background: var(--coral-light);
  color: var(--coral);
}
/* Epic (Ticket 3.261-Nachtrag, 2026-08-17) — dritter Wert desselben
   Segmented-Control, analog is-bug-active. */
.sidebar-field .contact-status-seg-btn.is-epic-active {
  background: var(--accent-light);
  color: var(--accent);
}
/* Gesperrtes Epic MIT verlinkten Tickets (s. Kommentar bei _renderSidebar()
   in ds-todo-detail.js): Aufgabe/Fehler sind hier deaktiviert statt
   entfernt -- derselbe Umschalter bleibt in allen vier Zustaenden sichtbar. */
.sidebar-field .contact-status-seg-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
/* 🔒 Ohne diese Regel bleibt die generische Hover-Regel der Basisklasse
   (.contact-status-seg-btn:hover, _core.css) auf einem deaktivierten Button
   wirksam -- ein natives disabled-Attribut blockt zwar den Klick, aber
   nicht automatisch die :hover-Pseudoklasse. Gemessen (Puppeteer,
   computed style): Hover auf "Aufgabe" bei gesperrtem Epic aenderte
   Hintergrund UND Textfarbe trotz opacity:.45 + cursor:not-allowed --
   wirkte dadurch wie ein bedienbarer Button. Setzt bewusst dieselben Werte
   wie der unbeeinflusste Grundzustand (nicht "unset"), damit KEINE
   sichtbare Reaktion mehr auftritt. */
.sidebar-field .contact-status-seg-btn:disabled:hover {
  background: var(--bg-primary);
  color: var(--text-secondary);
}
/* Bei drei Segmenten im schmalen Mobile-Metadaten-Drawer (max. 320px breit,
   s. .ds-drawer) weicht zuerst die Beschriftung, NIE das Symbol -- das
   title-Attribut auf dem Button bleibt als Ersatz (Domenico-Vorgabe,
   Ticket 3.261-Nachtrag). Nur .todo-type-segment betroffen, nicht die
   generische .contact-status-segment (Kontakte/Firmen behalten ihre 2
   Beschriftungen).
   🔒 Breakpoint bewusst identisch zum bestehenden isMobile()-Schwellwert
   (900px, s. frontend.md "Mobile"), NICHT enger: .ds-drawer deckelt seine
   Breite bei JEDEM Viewport ab ~372px hart auf max-width:320px (86vw
   greift erst darunter) -- die Sidebar liegt fuer JEDEN Screen ≤900px im
   selben 320px-Drawer, nie im breiteren Desktop-Split. Gemessen (Puppeteer,
   Chrome-Font-Metriken): bei voller Beschriftung summieren sich die drei
   Button-Breiten bei 390px Viewport auf ~285px bei nur 288px verfuegbarem
   Platz -- 3px Toleranz, die "Aufgabe" als laengstes Wort mangels
   min-width:0 nicht unterschreiten kann (Flex-Item schrumpft nicht unter
   seine Inhalts-Mindestbreite). Unterhalb 372px (echte 86vw-Schrumpfung)
   ueberschreitet die Summe die verfuegbare Breite bereits sichtbar. Eine
   engere Media-Query (z.B. nur ≤400px) liesse dieselbe Enge auf jedem
   groesseren Mobilgeraet bis 900px unangetastet -- das waere keine
   Verbesserung, nur eine zufaellige Grenze. */
@media (max-width: 900px) {
  .sidebar-field .todo-type-segment .todo-type-seg-label {
    display: none;
  }
  .sidebar-field .todo-type-segment .contact-status-seg-btn {
    padding: 0 0.4rem;
  }
}

.sidebar-value {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.6rem;
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  font-size: 0.82rem;
  color: var(--text-primary);
  cursor: pointer;
  border: 1px solid var(--border);
  transition: background var(--transition);
  max-width: 100%;
}
.sidebar-value:hover { background: var(--bg-tertiary); }
.sidebar-value .val-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
}
.sidebar-value .val-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* Ticket 3.206.4: rein informativer, nicht anklickbarer Sidebar-Wert
   (z.B. erfasste Zeit) — Basis .sidebar-value ist standardmaessig
   cursor:pointer für editierbare Felder, dieser Modifier daempft
   das für reine Anzeige-Werte. Neue Klasse statt der im Bestand
   mehrfach wiederholten Inline-Style-Kopie (style="cursor:default;
   opacity:0.7"), s. frontend.md "CSS: Klassen statt Inline-Styles". */
.sidebar-value--readonly {
  cursor: default;
  opacity: 0.85;
}
.sidebar-value--readonly:hover { background: var(--bg-secondary); }

.sidebar-chip-wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}
.sidebar-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.2rem 0.5rem 0.2rem 0.55rem;
  border-radius: 999px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  font-size: 0.78rem;
  color: var(--text-primary);
}
.sidebar-chip .chip-x {
  background: none;
  border: none;
  color: var(--text-tertiary);
  cursor: pointer;
  display: flex;
  align-items: center;
  padding: 0;
}
.sidebar-chip .chip-x:hover { color: var(--coral); }

/* Popovers inline (kein position:absolute mehr → kein Überlagern anderer Felder) */
.sb-popover-wrap { position: relative; }
.sb-popover {
  margin-top: 0.35rem;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 0.35rem;
  max-height: 360px;
  overflow-y: auto;
  width: 100%;
}
.sb-popover-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 0.25rem 0.25rem;
  margin: -0.15rem -0.1rem 0.25rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-tertiary);
}
.sb-popover-close {
  background: none;
  border: none;
  padding: 0.15rem 0.25rem;
  cursor: pointer;
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
  border-radius: var(--radius-sm);
}
.sb-popover-close:hover { color: var(--coral); background: var(--coral-light); }
/* Overlay-Variante für hohen Inhalt (Datepicker) – liegt über Folgefeldern */
.sb-popover.sb-popover--overlay {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  z-index: 250;
  margin-top: 0;
  max-height: 480px;
}
/* Feinschliff-Fix: Datum/Start-Ende werden am Ausloeser-Feld verankert
   (direkt darunter, linksbuendig) statt zentriert ueber dem ganzen
   Panel zu schweben (vorherige Version, Nutzer-Feedback: "Aufklapper
   fliegen frei im Panel herum"). position:fixed statt absolute, weil
   die scrollende Sidebar (.todo-detail-sidebar, overflow-y:auto) auch
   absolut positionierte Nachfahren abschneiden würde, unabhaengig
   vom containing block -- nur position:fixed (Viewport-relativ) bzw.
   ein Rendern AUSSERHALB des scrollenden Astes (wie hier, Geschwister
   von .todo-detail-split) entkommt dem. Koordinaten kommen aus
   _positionAnchoredPopover() (JS, getBoundingClientRect des Feldes)
   als CSS-Custom-Properties -- der einzige erlaubte dynamische Fall.
   Bei Sidebar-Scroll/Fenster-Resize schliesst der Popover (s.
   _onScrollOrResizeClose) statt live nachzuwandern -- ein an falscher
   Stelle stehender Popover waere schlimmer als ein geschlossener. */
.sb-popover--anchored {
  position: fixed;
  top: var(--anchor-top, 0px);
  left: var(--anchor-left, 0px);
  margin-top: 0;
  z-index: 260;
}
.sb-popover.sb-popover--anchored {
  width: var(--anchor-width, 300px);
  max-width: calc(100vw - 16px);
  max-height: calc(100vh - 16px);
  box-shadow: var(--shadow-lg);
}
/* Start/Ende brauchte etwas mehr Innenabstand als die Standard-
   Auswahl-Popover (vorher Inline-Style, jetzt Klasse — Regel
   "Klassen statt Inline-Styles", frontend.md). */
.sb-popover--schedule { padding: 0.5rem; }
/* Datum: <ds-todo-datepicker> bringt bereits eine vollstaendige,
   elegante Kartenoberflaeche mit (eigener Rahmen/Radius/Schatten,
   s. ds-todo-datepicker.js .datepicker-wrap) -- ein zusaetzlicher
   .sb-popover-Rahmen DARUM waere "ein Fenster im Fenster" (Nutzer-
   Feedback). Dieser Wrapper trägt daher NUR Positionierung + das
   Layout für den optionalen "Datum entfernen"-Link darunter, keine
   eigene Karten-Optik (kein Rahmen/Schatten/Padding/Hintergrund). */
.todo-detail-datepicker-anchor {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.3rem;
}
.todo-detail-datepicker-remove {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 0.78rem;
  color: var(--text-tertiary);
  padding: 0.25rem 0.4rem;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
}
.todo-detail-datepicker-remove:hover { color: var(--coral); background: var(--coral-light); }
.sb-popover-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.55rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.82rem;
  color: var(--text-primary);
}
.sb-popover-item:hover { background: var(--bg-secondary); }
.sb-popover-item.selected { color: var(--accent); font-weight: 600; }
.sb-popover-item.hl { background: var(--accent-light); color: var(--accent); }
/* Leerer/informativer Popover-Eintrag, nicht klickbar (Ticket 3.261.2,
   Epics P2) -- Modifier statt Inline-Style. Muss NACH .sb-popover-item:hover
   stehen (gleiche Spezifität 0,2,0 -- Quellreihenfolge entscheidet). */
.sb-popover-item--empty { color: var(--text-tertiary); cursor: default; }
.sb-popover-item--empty:hover { background: none; }
.sb-popover-sep {
  height: 1px;
  background: var(--border);
  margin: 0.25rem 0;
}
.sb-input {
  width: 100%;
  font-size: 0.82rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-primary);
  outline: none;
}
.sb-input:focus { border-color: var(--accent); }
/* Start/Ende-Popover-Zeilen (Punkt 4.3 — ersetzt vorherige Inline-Styles).
   🔒 Ticket 3.88 Feinschliff: Label über statt NEBEN dem Feld -- die
   vorherige nebeneinander-Anordnung (Label fix 3.2rem + Input flex:1) ließ
   dem nativen datetime-local-Eingabefeld in der 300px-Popover-Breite (bzw.
   der 320px-Sidebar-Spalte der aufgeklappten Unteraufgabe, s.
   _renderExpandedSubtaskMeta()) zu wenig Raum -- die letzte Ziffer der
   Uhrzeit wurde vom Browser abgeschnitten (Chrome kürzt den rechtesten
   Abschnitt des Steuerelements, statt zu umbrechen, wenn die Box zu schmal
   ist). Gestapelt gewinnt das Feld die volle Popover-Breite zurück. */
.sb-schedule-row {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.25rem;
  margin-bottom: 0.5rem;
  font-size: 0.8rem;
}
.sb-schedule-label { color: var(--text-secondary); }
.sb-schedule-input { width: 100%; }
/* Auswählen/Abbrechen-Fußbereich des Start/Ende-Popovers (Ticket 3.88
   Feinschliff) -- app-weite Standard-Bauform für Bestätigen/Verwerfen
   (.btn-secondary/.btn-primary-Paar, identisch zu Modal.confirm()/
   Modal.prompt() in components.js), kein neues Muster. */
.sb-popover-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}


/* ── Todo Status Select (shared from _todo-status.js) — Regeln stehen im
   Abschnitt "aus _todo-status.js" weiter oben (Zeile ~126), s. Hinweis im
   Sektionskopf oben. */
/* Status-Zeile-Baustein — Punkt 4.5: Status (todos.status) und
   Spalte (Board-Sektion) sind fachlich zwei verschiedene Dinge, die bei
   gleichnamiger Sektion optisch identisch aussehen koennen. Kleine
   vorangestellte Labels machen den Unterschied sichtbar, ohne die
   Felder zusammenzulegen (mehrere Spalten teilen sich denselben Status).
   🔒 Ticket 3.197.4: die HAUPTAUFGABEN-Nutzung dieser Klasse (Reiter
   „Ticket", erste Zeile unter dem Titel) ist entfallen -- Status+Spalte
   liegen seither als bare Pillen direkt in der Reiter-Leiste
   (_renderMainTabs(), s. dort), in JEDEM Reiter sichtbar statt nur im
   Ticket-Tab. Die Klasse bleibt in Benutzung fuer die AUFGEKLAPPTE
   UNTERAUFGABE (.todo-subtask-expand-body, s. _renderExpandedSubtask())
   -- dort weiterhin MIT Label (kein Platzdruck, eigene Leiste bleibt
   unveraendert). Nicht entfernen. */
/* Kein margin-top hier (Bugfix-Erbe): war urspruenglich noetig, weil
   die Zeile im Ticket-Tab das erste Flex-Kind von .todo-detail-ticket-
   body -> .todo-detail-tab-content war (Letzteres hat overflow:hidden
   -- ein negativer margin-top auf dem ERSTEN Kind haette den oberen
   Rand abgeschnitten). Gilt als generelle Vorsicht, falls die Klasse
   erneut als erstes Kind eines overflow:hidden-Vorfahren landet. */
.todo-detail-status-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  flex-shrink: 0;
}
.todo-status-row-item {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.todo-status-row-label {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
}

/* ── Reiter Ticket/Unteraufgaben/Kommentare (Spec 20260730 P6) ── */
.todo-detail-tabs {
  margin: -0.25rem -1.25rem 0;
  flex-shrink: 0;
  /* .ds-panel-toolbar bringt eigenes Padding/Border/BG mit — negative
     Randbreite gleicht das seitliche Panel-Padding aus, damit die
     Leiste bis an die Panel-Kante reicht statt eingerückt zu wirken. */
}
/* Status+Spalte-Pillen rechts von den Reitern (Ticket 3.197.4,
   _renderMainTabs()) — bare .todo-status-sel-Pillen (--sm, ohne
   Label-Zeile: die 32px-Toolbar traegt bereits Speichern + 3 Reiter,
   s. Ticket-Vorgabe „kuerzere Beschriftung oder nur der Wert mit
   Statusfarbe"). .ds-toolbar-spacer davor gruppiert sie sichtbar
   getrennt vom Reiter-Block. Neue Modifier-Klasse fuer die
   Spalte-Pille statt eines Inline-Styles: .todo-status-sel setzt
   background-image (Chevron, Pflicht-Pfeil laut design-system.md) —
   ein Inline-style="background:…" (Shorthand) wuerde dieses Bild
   mit-ueberschreiben, background-color allein nicht. */
.todo-status-sel--neutral {
  color: var(--text-secondary);
  border-color: var(--border);
  background-color: var(--bg-secondary);
}
/* Ticket 3.198.1 -- Status-/Spalten-Pille an die Nachbarn DIESER Leiste
   angleichen (Domenico: "wirken in der Navigation ein wenig wie ein
   Fremdkoerper"). Gemessen: die Pillen standen mit 19px Hoehe + 999px-
   Vollkreis-Radius + 10.88px-Schrift neben 32px hohen, 8px-radius,
   12.8px-Schrift .ds-toolbar-item-Buttons (Speichern/Ticket/Unteraufgaben/
   Kommentare) derselben Zeile. Angeglichen: Eckenradius (var(--radius-sm),
   identisch zu .ds-toolbar-item), Schriftgroesse (.75rem, nah an dessen
   .8rem) + Innenabstand-Rhythmus. Hoehe bewusst 28px statt exakt 32px --
   .ds-toolbar-item--sm (_core.css, "Kompakter Save-Button in Invoicing-
   Toolbars") ist bereits die im Design-System etablierte kompakte
   Toolbar-Groesse; ein exaktes 32px+grosszuegiges Padding sprengte die
   536px breite Leiste in eine zweite Zeile (Panel-Breite ist fix, kein
   Platz fuer 4 Reiter + 2 Pillen bei voller Toolbar-Groesse -- gemessen,
   nicht geraten). Die Statusfarbe bleibt Traeger der Bedeutung (inline
   style aus renderTodoStatusSelect(), von dieser Regel unberuehrt), nur
   die FORM wird angeglichen.
   🔒 Bewusst NUR innerhalb von .todo-detail-tabs gescoped (Spec-Auflage,
   s. .claude/rules/modules/todos.md): renderTodoStatusSelect() in
   _todo-status.js ist die geteilte Render-Funktion fuer Board-Karte,
   Listen-Zeile, Backlog-Zeile, Epic-Tickets-Reiter UND diese Leiste (P-5,
   EINE Definition) -- die Basisklasse .todo-status-sel bleibt fuer alle
   anderen Verwendungen UNVERAENDERT (kompakte Pille passend zur jeweiligen
   Karte/Zeile). Eine Aenderung an der Basisklasse haette dort ungewollt
   mitgewirkt. */
.todo-detail-tabs .todo-status-sel {
  height: 28px;
  border-radius: var(--radius-sm);
  font-size: .75rem;
  font-weight: 600;
  padding: 0 1.4rem 0 .5rem;
  line-height: normal;
  background-position: right .4rem center;
  background-size: 8px;
  max-width: 7rem;
}
/* Punkt 9: fuellt den Rest von .todo-detail-main, uebernimmt selbst
   kein Scrollen mehr (das macht der jeweilige Tab-Inhalt darunter) —
   damit bleiben Titel/Status/Tabs immer sichtbar, nur der Tab-Inhalt
   (Beschreibung / Unteraufgaben-Liste / Kommentare) wandert. */
.todo-detail-tab-content {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* Unteraufgaben/Kommentare: eigener Scroll-Container für den ganzen
   Tab-Inhalt (einfacher Fall, keine fixen Teilbereiche noetig). */
.todo-detail-tab-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
/* Ticket-Tab: Status-Zeile + Kontakt/Firma-Pills bleiben fix (flex-
   shrink:0 an ihren eigenen Regeln), nur die Beschreibung (flex:1)
   waechst + scrollt intern. */
.todo-detail-ticket-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.todo-detail-tab-empty {
  color: var(--text-tertiary);
  font-size: 0.85rem;
  padding: 0.25rem 0;
}

/* ── Mobile Fixes (≤900px) ── */
@media (max-width: 900px) {
  /* Reiter nie umbrechen — notfalls horizontal scrollbar (wie .tab-filter) */
  .todo-detail-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .todo-detail-tabs::-webkit-scrollbar { display: none; }
  .todo-detail-tabs .ds-toolbar-item { flex-shrink: 0; }
  /* Ticket 3.197.4: Status/Spalte-Pillen duerfen im horizontalen
     Scroll ebenfalls nicht schrumpfen (sonst wirkt der Text der
     gewaehlten Option gequetscht/abgeschnitten). */
  .todo-detail-tabs .todo-status-sel { flex-shrink: 0; }

  /* Fix 5a: Sidebar-Felder — kein Page-Overflow durch schmale Viewport */
  .sidebar-field { min-width: 0; }

  /* Fix 5b: Chip-Wrap — kein horizontaler Page-Overflow */
  .sidebar-chip-wrap {
    overflow-x: hidden;
    max-width: 100%;
  }

  /* Fix 5c: Comment-Textarea Touch-Target ≥44px */
  .comment-input-row .comment-input-field {
    min-height: 44px;
    align-items: center;
  }
  .comment-input-row textarea {
    min-height: 44px;
  }

  /* Feinschliff Punkt 9: das Flex-Fill/Split-Scroll-Layout ist ein
     Desktop-Pattern (2-Spalten-Grid mit fester Panel-Hoehe). Auf Mobile
     stapelt .todo-detail-split einspaltig — hier lieber normaler
     Dokument-Scroll über den ganzen gestapelten Inhalt statt
     verschachtelter Scroll-Container (Touch-Scroll-Traps vermeiden). */
  .todo-detail-split { overflow-y: auto; }
  /* Belegte Korrektur (Spec 20260730): min-height:0 nahm der Grid-
     Zeile ihre Mindestgroesse, wodurch sie unter ihre Inhaltshoehe
     gedrueckt wurde (369px Box gegen 880px Inhalt gemessen) -- der
     Ueberhang lief bei overflow:visible sichtbar UNTER die Sidebar-
     Zeile. min-height:auto lässt die Zeile auf ihre echte
     Inhaltshoehe wachsen (Box == Inhalt, 0px Ueberlappung gemessen).
     NUR hier in der Mobile-Query -- in der Desktop-Basisregel bleibt
     min-height:0 noetig, damit die Flex-Spalte ihre inneren Scroll-
     Container schrumpfen lassen kann. */
  .todo-detail-main {
    overflow: visible;
    min-height: auto;
  }
  .todo-detail-tab-content {
    flex: none;
    overflow: visible;
  }
  .todo-detail-tab-scroll {
    flex: none;
    overflow: visible;
  }
  .todo-detail-ticket-body { flex: none; }
  .todo-desc-wrap { flex: none; align-items: flex-start; }
  .todo-desc-body { min-height: 200px; }
  .todo-desc-body .ds-rich-editor-body {
    flex: none;
    max-height: none;
    overflow: visible;
    display: block;
  }
  .todo-desc-body .ql-container {
    flex: none;
    overflow: visible;
  }
  /* Breite/Position brauchen weiterhin KEINEN Media-Query-Override:
     _positionAnchoredPopover() (JS) klemmt beides bereits gegen
     window.innerWidth -- ein einziger Rechenweg für alle Viewport-
     Groessen statt CSS- + JS-Logik doppelt zu pflegen.
     z-index dagegen MUSS hier auf Mobile angehoben werden (Spec
     20260730): der Ausloeser (Sidebar-Feld) lebt jetzt im
     .ds-drawer--right-Portal (page-todos.js, z-index 1200) -- ohne
     die Anhebung würde der Popover-KOERPER, der weiterhin innerhalb
     von .todos-detail-panel (page-todos.js, transform-Vorfahre,
     z-index 300) rendert, HINTER dem eigenen Drawer verschwinden. */
  .sb-popover--anchored { z-index: 1210; }
}


/* ── aus ds-todo-list-view.js (3.85 Paket 7) ───────────────────────────────
   Projekt-/Listen-Ansicht: Kopfzeile (Titel/Suche/Filter), Ansichts-
   Umschalter, "Neu"-Split-Button, Projekt-Hierarchie (Epic/Meilenstein/
   Gruppen), Ladezustand-Leiste + Erstlade-Skeleton. Komplett literales CSS
   im ursprünglichen Block (keine ${}-Interpolation) -- reine Verschiebung,
   Reihenfolge unveraendert. */
/* Ticket 3.215.2/3.215.3-Nachfund — Custom Elements ohne eigenes
   display sind per Default "inline". Light-DOM-Style-Blöcke gelten
   global (kein Shadow-Scoping), daher hier zulässig gesetzt: als
   "inline"-Box mit block-level Inhalt (.page-header/.todo-list-wrap)
   trug der Host sonst einen zusätzlichen, unsichtbaren Rand-Abstand
   aus dem umgebenden Inline-Formatierungskontext mit (~32px "Rest"
   unter .todos-content auf Mobile, s. ds-todo-board-view.js
   für dieselbe Ursache/denselben Fix bei der Board-Ansicht). */
ds-todo-list-view { display: block; }
.todo-list-wrap { padding: 0 0 2rem; }
.todo-section { margin-bottom: 0.5rem; }
.todo-section-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.25rem;
  color: var(--text-secondary);
  font-size: 0.82rem;
  font-weight: 600;
  user-select: none;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.25rem;
}
.todo-section-header:hover { color: var(--text-primary); }
.todo-section-chevron {
  transition: transform var(--transition);
  display: flex;
  align-items: center;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: inherit;
  flex-shrink: 0;
}
.todo-section-chevron.collapsed { transform: rotate(-90deg); }
.todo-count-badge {
  font-size: 0.7rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: var(--bg-tertiary);
  color: var(--text-tertiary);
}
.todo-quick-add-trigger {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.75rem;
  font-size: 0.82rem;
  color: var(--text-tertiary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: color var(--transition), background var(--transition);
  user-select: none;
  background: none;
  border: none;
  width: 100%;
  text-align: left;
}
.todo-quick-add-trigger:hover {
  color: var(--accent);
  background: var(--accent-light);
}
.todo-empty-state {
  text-align: center;
  padding: 3rem 2rem;
  color: var(--text-tertiary);
}
.todo-empty-state svg {
  margin-bottom: 1rem;
  opacity: 0.4;
}
.btn.active {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 600;
}
.todo-section-header .section-menu-btn {
  opacity: 0;
  transition: opacity var(--transition);
}
.todo-section-header:hover .section-menu-btn {
  opacity: 1;
}

/* Kopfzeilen-Layout (Ticket 3.163.5, T3): .page-header bekommt eine
   DRITTE Spalte (Suche+Filter) zwischen Titelbereich und
   Ansichtsumschalter/„Neue Aufgabe" — die generische .page-header-CSS
   (layout.css, display:flex; justify-content:space-between) bleibt
   unangetastet, die drei Spalten steuern ihre Breite selbst. */
.todo-header-titlecol {
  display: flex;
  flex-direction: column;
  gap: .125rem;
  min-width: 0;
  flex: 0 1 auto;
}
/* Ticket 3.253 — Domenico: „Wenn wir die zwei Icons settings und board view
   in diese Leiste [.ds-mobile-navbar, page-todos.js] packen und das hejdesk
   und DRICH.CONSULTING entfernen … gewinnen wir 1 Zeile." Titel-<h1> +
   Firmenzeile + der (jetzt in .ds-mobile-navbar umgezogene) Einstellungen-/
   Ansichten-Ausloeser leben unveraendert in dieser Spalte — auf Mobile
   komplett ausgeblendet statt umgebaut (DOM-Struktur bleibt, Desktop
   unberuehrt). Projekt-/Etikett-Name + -Farbpunkt stehen mobil bereits in
   .ds-mobile-navbar-context (s. page-todos.js::_renderMobileNavBar()). */
@media (max-width: 900px) {
  .todo-header-titlecol { display: none; }
}
/* Ticket 3.253.1 -- .todo-header-titlecol ist mobil IMMER ausgeblendet (s.o.)
   und .todo-header-searchcol meist eingeklappt -- die app-weite Basisregel
   .page-header{margin-bottom:1rem/1.5rem} (layout.css) reservierte dafuer
   trotzdem IMMER Platz, obwohl in den meisten Ansichten NICHTS mehr im Kopf
   steht (Domenico-Screenshot: 58px Luecke zur mobilen Sub-Nav-Leiste, s.a.
   .todos-content oben). Kollabiert auf 0, sobald WEDER die aufgeklappte
   Suchzeile NOCH ein sichtbarer Header-Action-Button (Reporting-Umschalter
   bei Posteingang/„Alle Todos") als Nachfahre steht -- reine :has()-
   Praesenzpruefung auf bereits vorhandenen Zustandsklassen, kein zweiter
   JS-State (P-5). Der View-Switcher-Button (--actions-Modifier) ist mobil
   ohnehin IMMER display:none (s.u.) und daher explizit ausgenommen, sonst
   wuerde seine bloße Anwesenheit im DOM die Kollaps-Erkennung dauerhaft
   blockieren. Klappt der Nutzer die Suche auf, verliert .todo-header-
   searchcol seine --collapsed-Klasse -- die :has()-Bedingung greift dann
   nicht mehr und der Abstand kehrt automatisch zurueck (Domenico: "Platz
   erweitert sich beim Aufklappen ... verkleinert sich beim Zuklappen").
   Nur mobil -- Desktop-Abstand bleibt unveraendert (layout.css). */
@media (max-width: 900px) {
  ds-todo-list-view .page-header:not(:has(.todo-header-searchcol:not(.todo-header-searchcol--collapsed))):not(:has(.page-header-actions > button:not(.todo-header-view-switcher-btn--actions))) {
    margin-bottom: 0;
  }
}
/* Ticket 3.253.1 -- vierter, urspruenglich nicht mitgemessener Beitrag zur
   58px-Luecke: die geteilte .ds-mobile-navbar-Basisregel (_core.css, auch
   von pages/notes.js genutzt) traegt ein eigenes margin-bottom:.5rem NACH
   ihrer eigenen Border-Linie -- 8px reine Leerflaeche, zusaetzlich zu (und
   unabhaengig von) der .page-header-Kollaps-Regel oben und dem reduzierten
   .todos-content-padding-top. Scoped auf page-todos (NICHT die Basisregel
   selbst aendern) -- Notizen behaelt seinen Abstand unveraendert. Die
   Navbar hat bereits 8px EIGENES padding-bottom VOR ihrer Border-Linie
   (s. .ds-mobile-navbar-Basisregel) -- die Trennung zur Leiste bleibt also
   ueber Padding+Border weiterhin sichtbar, nur die zusaetzliche Leerflaeche
   DANACH entfaellt. Gemessen (Pixel 5, Projekt 1, Board-Ansicht,
   eingeklappte Suche): 26px -> 18px Rest-Luecke bis zum Spaltenkopf. */
page-todos .ds-mobile-navbar { margin-bottom: 0; }
.todo-header-searchcol {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .25rem;
  flex: 1 1 220px;
  min-width: 0;
  padding: 0 .5rem;
}
.todo-header-searchbar-row {
  display: flex;
  align-items: center;
  gap: .4rem;
  width: 100%;
  max-width: 380px;
}

/* Modul-Suche im Projektkopf (Ticket 3.84.17, Kopfzeile umgebaut in
   3.163.5) — kompakte Variante von .search-bar (_core.css) statt der
   vollen 44px-Listenseiten-Suchleiste. Basis-Klasse liefert
   Border/Radius/Farben (Light+Dark automatisch ueber CSS-Variablen). */
.todo-header-search {
  flex: 1;
  min-width: 0;
  min-height: 30px;
  padding: 0 .55rem;
  margin: 0;
}
.todo-header-search input { font-size: .8125rem; }
.todo-header-search svg { width: 13px; height: 13px; }
/* Natives WebKit-/Blink-Clear-X unterdrücken — dieses Feld hat ein eigenes
   .todo-header-search-clear (sonst Doppel-X bei Inhalt in Chrome/Safari),
   analog .mail-search-input in _core.css (Ticket 3.219). */
.todo-header-search input::-webkit-search-cancel-button,
.todo-header-search input::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
}
.todo-header-search-clear {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  padding: 2px;
  border-radius: var(--radius-sm);
}
.todo-header-search-clear:hover {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}
.todo-header-search-hint {
  margin: 0;
  font-size: .75rem;
  color: var(--text-tertiary);
  align-self: flex-start;
}
.todo-header-search-hint--warn {
  color: var(--amber);
  font-weight: 600;
}

/* Ticket 3.362 -- "fremde Änderungen"-Hinweis (vormals Ticket 3.215.1)
   ist seither IMMER sichtbar (grau, nur Symbol) statt nur bei erkannter
   Änderung -- Domenico wollte ihn dauerhaft griffbereit neben dem
   Filter-Knopf haben. Ruhezustand-Optik 1:1 an .todo-filter-btn
   angelehnt (gleiche Nachbar-Gruppe, s. u.) -- quadratisch, nur Symbol
   (P-5, keine neue Graustufe erfunden). `.is-active` färbt ihn blau,
   solange eine fremde Änderung vorliegt. Die frühere Breiten-
   Platzreservierung (konstante Breite bei Sichtbarkeits-Toggle,
   Ticket 3.215.1) ist mit dem Dauer-sichtbar-Zustand überflüssig
   geworden und entfällt ersatzlos. */
.todo-changes-indicator {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 30px;
  min-width: 30px;
  padding: 0 .5rem;
  box-sizing: border-box;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--bg-primary);
  color: var(--text-secondary);
  cursor: pointer;
  flex-shrink: 0;
  transition: all var(--transition);
}
.todo-changes-indicator:hover { background: var(--bg-tertiary); color: var(--text-primary); }
.todo-changes-indicator.is-active {
  border-color: transparent;
  background: var(--accent-light);
  color: var(--accent-dark);
}
.todo-changes-indicator.is-active:hover { background: var(--accent); color: #fff; }
.todo-changes-indicator svg { flex-shrink: 0; }

/* Nachbesserung zu Ticket 3.253 — eigenstaendiger mobiler Ausloeser fuer
   denselben Hinweis (s. ds-todo-list-view.js::_renderMobileChangesIndicator()),
   lebt in .ds-mobile-navbar-icons (page-todos.js). Anders als
   .todo-changes-indicator oben (seit Ticket 3.362 IMMER sichtbar) bleibt
   dieser mobile Ausloeser bewusst NUR bei vorliegender Aenderung im DOM –
   die Methode gibt bei !_remoteChangesAvailable '' zurueck, das Icon nimmt
   dann in der knappen Leiste buchstaeblich keinen Platz ein.
   🔒 Ticket 3.253.1 -- Domenico (Screenshot-Feedback): "einfach als blauer
   Spinning Button". Die zart getoente --accent-light-Pille von 3.253 wirkte
   auf Mobile zu unauffaellig neben den umrandeten Nachbar-Icons
   (Zahnrad/Lupe — seit Ticket 3.253.2 die einzigen Geschwister in dieser
   Gruppe, der Ansichten-Wechsler steht seither separat rechts, s.
   ds-todo-list-view.js::renderMobileViewSwitcher()). Jetzt VOLL gefuellt
   (var(--accent)) mit weissem Symbol statt nur umrandet -- sticht dadurch
   bewusst aus der sonst neutralen .ds-mobile-navbar-icon-Familie heraus
   ("hier ist etwas zu tun", dringlicher als ein reiner Hover-Zustand).
   Groesse/Rundung bleiben die geteilten 32px-.ds-mobile-navbar-icon-
   Basiswerte (_core.css) -- nur Farbe weicht ab. Rotation waehrend des
   Nachladens: s. `.spin` (_core.css, app-weite Klasse) am `<svg>` selbst,
   s. Docblock in ds-todo-list-view.js. */
.ds-mobile-navbar-icon--changes {
  border-color: transparent;
  background: var(--accent);
  color: #fff;
}
.ds-mobile-navbar-icon--changes:hover,
.ds-mobile-navbar-icon--changes:focus-visible {
  background: var(--accent-dark);
  color: #fff;
}

/* Filter-Symbol + Zaehler-Badge — analog .contact-filter-btn/-badge
   (_core.css), hier aber auf die kompakte 30px-Suchzeile skaliert
   (Groessenmismatch zur 44px-Kontakte-Variante waere unschoen). */
.todo-filter-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .3rem;
  height: 30px;
  min-width: 30px;
  padding: 0 .5rem;
  box-sizing: border-box;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--bg-primary);
  color: var(--text-secondary);
  cursor: pointer;
  flex-shrink: 0;
  transition: all var(--transition);
}
.todo-filter-btn:hover { background: var(--bg-tertiary); color: var(--text-primary); }
.todo-filter-btn.is-active {
  background: var(--accent-light);
  color: var(--accent-dark);
  border-color: transparent;
}
.todo-filter-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 99px;
  background: var(--accent);
  color: #fff;
  font-size: .625rem;
  font-weight: 700;
  line-height: 1;
}

/* Desktop: ausklappende Filterleiste unter der Kopfzeile (standard-
   maessig eingeklappt, s. _renderDesktopFilterBar()). */
.todo-filter-bar-desktop {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  padding: .5rem 0;
  margin: -.25rem 0 .75rem;
  border-bottom: 1px solid var(--border);
}
.todo-filter-field { min-width: 0; }
.todo-filter-bar-desktop .todo-filter-field {
  height: 30px;
  min-height: 30px;
  padding: 0 1.75rem 0 .55rem;
  font-size: .8125rem;
  width: auto;
}
.todo-filter-reset-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--coral);
  font-size: .78rem;
  padding: .2rem .4rem;
}
.todo-filter-reset-btn:hover { text-decoration: underline; }

/* Mobile: Filter-Drawer-Inhalt (.ds-drawer--right, s. _renderFilterDrawer()) */
.todo-filter-drawer-body {
  display: flex;
  flex-direction: column;
  gap: .875rem;
  padding: 1rem;
}
.todo-filter-drawer-body .todo-filter-field { width: 100%; }

/* Ticket 3.215.3 -- Etikett-Filter als durchsuchbare Selectbox
   (.ss-wrap, s. _renderFilterFields()). Die innere .ss-trigger trägt
   die generische .input-Basisklasse (min-height:44px, width:100% —
   _core.css) — dieselbe Kompaktierung wie die nativen
   .todo-filter-field-Selects direkt darüber, nur auf .ss-trigger
   statt einem select-Element angewendet. */
.todo-filter-field-ss { width: 160px; flex-shrink: 0; }
.todo-filter-bar-desktop .todo-filter-field-ss .ss-trigger {
  height: 30px;
  min-height: 30px;
  padding: 0 .55rem;
  font-size: .8125rem;
}
.todo-filter-drawer-body .todo-filter-field-ss { width: 100%; }

@media (max-width: 900px) {
  .todo-header-searchcol { flex: 1 1 100%; width: 100%; }
  .todo-header-searchbar-row { max-width: none; }
  /* Der Desktop-Bar-JS-Toggle setzt auf Mobile nie _filterBarOpen —
     diese Regel ist reine Verteidigung in der Tiefe (Resize-Kante). */
  .todo-filter-bar-desktop { display: none; }
  /* Ticket 3.253 — Suchzeile mobil standardmaessig eingeklappt (0 Hoehe),
     aufklappbar ueber das Lupen-Icon in .ds-mobile-navbar
     (ds-todo-list-view.js::renderMobileNavExtras()/_isMobileSearchVisible()).
     Klasse wird nur mobil ausgewertet — auf Desktop bleibt die Suche IMMER
     sichtbar, unabhaengig davon ob die Klasse im Markup steht. */
  .todo-header-searchcol.todo-header-searchcol--collapsed { display: none; }
}

/* Kopfzeilen-Menü-Auslöser + Ansichten-Dropdown-Auslöser (Ticket 3.234,
   Ansichten ausgelagert 3.234.2) — ersetzt die vorherigen vier Einzel-Icons
   (Zahnrad/Schloss/Auge/Haus) + den separaten 4-Button-Ansichts-Umschalter
   (.todo-project-view-switcher, ENTFERNT) im Projektkopf. Projekteinstellungen
   + Abschnitte sperren + die beiden Toggles + der "Ausgeblendete Spalten"-
   Rückweg leben im linken ContextMenu (ds-todo-list-view.js::
   _buildHeaderMenuItems()). Backlog/Board/Timeline/Reporting leben seit
   3.234.2 in einem EIGENEN ContextMenu rechts (.todo-header-view-switcher-btn,
   s. _buildViewSwitcherItems()) — der Auslöser trägt dabei das Icon der
   jeweils aktiven Ansicht statt eines festen Symbols. */
.todo-header-title-row {
  display: flex;
  align-items: center;
  gap: .375rem;
  min-width: 0;
}
/* Ticket 3.251 -- lange Projekt-/Etiketten-Namen ("Federated Data
   Governance Framework (1006433)") sprengten die Kopfzeile: der <h1>
   brach mehrzeilig um statt zu kuerzen. Einzeilig + Ellipsis, wie
   .ss-display/.activity-meta (_core.css) -- min-width:0 ist hier
   Pflicht (Standard-Flex-Item-Minimum ist sonst der ungekuerzte
   Text, s. frontend.md-Aehnliches ueber flex-basis-Fallstricke): ohne
   min-width:0 wuerde der Text NIE unter seine Content-Breite
   schrumpfen und text-overflow bliebe wirkungslos. Der volle Name
   steht als natives title-Attribut (Tooltip) am <h1> selbst.

   🔒 NACHTRAG (Ticket 3.251, zweiter Anlauf, 2026-08-17) -- die obige
   Fassung kuerzte NIE auf Desktop. Ursache per getComputedStyle+
   scrollWidth/clientWidth belegt: .todo-header-titlecol/-title-row
   tragen "flex: 0 1 auto" (flex-basis:auto = Inhaltsbreite). Chromes
   Flex-Algorithmus schrumpft ein Item mit flex-basis:auto NUR, wenn
   die Summe der Inhaltsbreiten ALLER Geschwister in .page-header
   (Titel + .todo-header-searchcol + .page-header-actions) den
   verfuegbaren Platz UEBERSTEIGT -- bei "Federated Data Governance
   Framework" (528px Text) und ueblichen Desktop-Fensterbreiten (>=1100px
   .page-header) ist immer genug Platz frei, der Browser schrumpft also
   nie, obwohl text-overflow korrekt gesetzt ist (scrollWidth===
   clientWidth=528 gemessen, kein Overflow -> Ellipsis bleibt wirkungslos
   MANGELS Overflow, nicht wegen einer falschen Eigenschaft). .ss-display/
   .activity-meta (s.o.) funktionieren nur, weil sie in einem Container
   MIT bekannter/fixer Breite leben -- .page-header hat keine, seine
   Breite ist einfach "wie breit ist das Browserfenster gerade". Fix
   analog .quick-add-project-btn (Zeile ~258, selbes Ticket): fixes
   max-width erzwingt die Kuerzung unabhaengig vom frei verfuegbaren
   Platz. Kein @media noetig -- .todo-header-titlecol ist unterhalb
   900px ohnehin komplett display:none (s.u.), der Mobile-Projektname
   laeuft ueber ein ANDERES Element (.ds-mobile-navbar-context, s.
   "Mobiler Kopfbereich" in modules/todos.md) mit eigener, bereits
   funktionierender Kuerzung -- diese Aenderung beruehrt Mobile nicht. */
.todo-header-title {
  min-width: 0;
  max-width: 420px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Ticket 3.234.3 — Domenico (Screenshot-Review): "Sieht das View-Switch
   jetzt sehr verloren aus. […] Der Kontrast, gerade im Dunklen Modus, ist
   sehr schlecht. Ggfs die beiden Icons mit einem runden Kreis/Border
   umkreisen." Vorher reine opacity:.7-Abdaempfung ohne eigenen Rahmen —
   auf dunklem Hintergrund kaum vom Text unterscheidbar (Pixel-Sample
   verifiziert, s. Ticket-Report). Jetzt kreisrunder Rahmen mit eigenem
   Hintergrund, volle Textfarbe statt gedaempfter Deckkraft — Kontrast in
   Light UND Dark automatisch ueber die theme-aware CSS-Variablen. */
.todo-header-menu-trigger,
.todo-header-view-switcher-btn {
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
}
.todo-header-menu-trigger:hover,
.todo-header-view-switcher-btn:hover {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}
.todo-header-menu-trigger:focus-visible,
.todo-header-view-switcher-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Icon-Ausrichtung im Reporting-Symbol — das Reporting-Symbol ist bewusst
   ein SVG (design-system.md „Icons = SVG, niemals Emojis"); vertical-align
   gleicht den sonst tiefer sitzenden SVG-Baseline-Versatz gegenüber
   Text-Präfixen benachbarter Buttons aus (Posteingang/„Alle Todos"-
   Reporting-Umschalter, der weiterhin Text+Icon kombiniert). */
.todo-view-switch-icon { vertical-align: -2px; margin-right: 2px; }
/* Mobile (≤900px): der Kopfzeilen-Menü-Auslöser lebt seit Ticket 3.253 in
   .ds-mobile-navbar (page-todos.js, ausserhalb dieser Komponente — s.
   renderMobileNavExtras()) und bleibt dadurch immer erreichbar, unabhängig
   vom Zustand von .todo-header-titlecol (jetzt @media(max-width:900px)
   komplett ausgeblendet, s.o.). Der ehemals HIER in .todo-header-title-row
   gerenderte Zahnrad-Button (@click=_openHeaderMenu) existiert im DOM
   weiterhin (Desktop-Nutzung, s. render()), ist auf Mobile aber nur noch
   ein toter Zwilling seines Parents — kein Sonderfall noetig. Der
   Posteingang/„Alle Todos"-Reporting-Umschalter sitzt in .page-header-
   actions, das per globaler Regel auf Mobile display:none bekommt (FAB
   ersetzt dort sonst den "Neu"-Button) — dieser Override macht sie wieder
   sichtbar. Höhere Selektor-Spezifität gewinnt automatisch, kein
   !important nötig. Die "Neue Aufgabe"-Split-Taste bleibt ausgeblendet (FAB
   übernimmt das Anlegen auf Mobile) — nur explizit dafür wieder versteckt,
   weil der Parent jetzt sichtbar ist. Desktop-Optik unverändert (Regel gilt
   nur unterhalb des Breakpoints). */
@media (max-width: 900px) {
  ds-todo-list-view .page-header-actions {
    display: flex;
  }
  ds-todo-list-view .todo-newmenu-wrap {
    display: none;
  }
}
/* Ticket 3.234.3 — Sichtbarkeits-Steuerung der zwei Einhänge-Punkte des
   GETEILTEN Ansichten-Auslösers (ein Template, zwei Renderorte, P-5, s.
   _renderViewSwitcherTrigger() in ds-todo-list-view.js). Desktop zeigt ihn
   in .page-header-actions (rechts, wie bisher). Die --inline-Instanz
   (Titelzeile) bleibt aus historischen Gruenden hier geregelt, ist aber seit
   Ticket 3.253 auf Mobile ohne sichtbare Wirkung: ihr Vorfahre
   .todo-header-titlecol traegt dort display:none (s.o.) — ein
   display:inline-flex auf einem Kind eines display:none-Elements bleibt
   unsichtbar. Die dritte, seither mobil tatsaechlich genutzte Instanz lebt
   in .ds-mobile-navbar-icon (ds-todo-list-view.js::renderMobileViewSwitcher(),
   seit Ticket 3.253.2 ein eigenstaendiges Template getrennt von
   renderMobileNavExtras() — von page-todos.js per Methodenaufruf gepullt und
   INNERHALB von .ds-mobile-navbar-context platziert, eigene CSS-Klasse
   weiter oben in _core.css). */
.todo-header-view-switcher-btn--inline { display: none; }
@media (max-width: 900px) {
  .todo-header-view-switcher-btn--inline { display: inline-flex; }
  .todo-header-view-switcher-btn--actions { display: none; }
}

/* Split-Button + Dropdown für „Neu" (Fix 2A) */
.todo-newmenu-wrap {
  position: relative;
  display: inline-flex;
}
.todo-newmenu-main {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.todo-newmenu-chev {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  border-left: 1px solid color-mix(in srgb, var(--accent-dark) 40%, transparent);
  padding: 0 .5rem;
  min-width: 28px;
}
.todo-newmenu-dropdown {
  position: absolute;
  top: calc(100% + 4px); right: 0;
  z-index: 100;
  min-width: 180px;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: .25rem;
  display: flex;
  flex-direction: column;
}
.todo-newmenu-item {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .5rem .6rem;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  font-size: .88rem;
  color: var(--text-primary);
  text-align: left;
}
.todo-newmenu-item:hover { background: var(--bg-tertiary); }
.todo-newmenu-icon {
  width: 18px; text-align: center;
  font-size: 1rem; line-height: 1;
}

/* Projekt-Hierarchie (Spec Teil 6) */
.group-block            { margin-bottom: .5rem; }
.group-header {
  display: flex; align-items: center; gap: .5rem;
  padding: .4rem .25rem; user-select: none;
  border-radius: var(--radius-sm);
}
.group-header .section-menu-btn { opacity: 0; }
.group-header:hover .section-menu-btn { opacity: 1; }

.group-epic-header {
  background: var(--accent-light);
  color: var(--text-primary);
  font-weight: 700;
  font-size: .95rem;
  border-left: 3px solid var(--accent);
  padding: .5rem .5rem;
}
.group-milestone-header {
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-primary);
  border-bottom: 1px solid var(--border);
  margin-top: .25rem;
}
.group-ungrouped-header {
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border);
  margin-top: .25rem;
  padding: .5rem .5rem;
}
.group-type-label {
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  padding: .1rem .4rem;
  border-radius: 3px;
  background: var(--accent);
  color: #fff;
  flex-shrink: 0;
}
.group-type-label.milestone {
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.group-ungrouped-header .group-type-label {
  background: var(--bg-tertiary);
  color: var(--text-tertiary);
}
.group-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.group-progress {
  display: flex; align-items: center; gap: .5rem;
  flex-shrink: 0;
}
.group-progress-bar {
  width: 120px; height: 6px;
  background: rgba(0,0,0,.08);
  border-radius: 3px; overflow: hidden;
}
.group-progress-bar.small { width: 80px; height: 4px; }
.group-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--teal));
  transition: width .2s ease;
}
.group-progress-text {
  font-size: .75rem; color: var(--text-secondary); font-variant-numeric: tabular-nums;
  min-width: 32px; text-align: right;
}
.group-body { padding-top: .25rem; padding-bottom: .25rem; }

/* T1 (Ticket 3.163.1, Befund B1) — additiver Ladezustand. Die Leiste
   ist IMMER im DOM (gleicher Call-Site bei jedem render(), egal ob
   this._loading true/false ist) — nur ihre Optik wechselt ueber eine
   Klasse. Reservierte Hoehe (2px) verhindert jeden Layout-Sprung beim
   Ein-/Ausblenden; kein Remount irgendeiner Kindkomponente moeglich,
   weil sich an der Template-STRUKTUR nichts aendert. */
.todo-list-loadbar {
  height: 2px;
  overflow: hidden;
  position: relative;
  background: transparent;
}
.todo-list-loadbar.is-active { background: var(--accent-light); }
.todo-list-loadbar.is-active::after {
  content: '';
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 35%;
  background: var(--accent);
  border-radius: 2px;
  animation: todo-loadbar-sweep 1.1s ease-in-out infinite;
}
@keyframes todo-loadbar-sweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(385%); }
}

/* Erstlade-Skeleton (T1) — dieser Zweig kann ausschliesslich VOR dem
   allerersten abgeschlossenen _load()-Aufruf erscheinen
   (this._hasLoadedOnce ist monoton false→true, nie zurueck) — es gibt
   an dieser Stelle noch keine Kindkomponente mit State, der verloren
   gehen koennte. */
.todo-initial-skeleton     { padding: .25rem .25rem 0; display: flex; flex-direction: column; gap: .55rem; }
.todo-initial-skeleton-row { display: flex; align-items: center; gap: .6rem; padding: .5rem .25rem; }

/* Ticket 3.362 -- der vormalige Icon-only-Override fuer schmale Fenster
   (Ticket 3.215.1, Auflage 4) ist entfallen: .todo-changes-indicator
   rendert seit jeher NIE unterhalb von 900px (_renderChangesIndicator()
   gibt bei isMobile() '' zurueck, derselbe 900px-Schwellwert) -- der
   Block traf also nie zu. Mit der Entfernung des Text-Labels (Ticket
   3.362) ist der Knopf ohnehin app-weit icon-only, ein Override ist
   damit obsolet. */

/* ── aus _todo-section-delete.js (Ticket 3.241 Teil 2) ────────────────────
   Wahl-Dialog beim Loeschen einer gefuellten Spalte -- "In andere Spalte
   verschieben" (vorausgewaehlt) vs. "Aufgaben mitloeschen". Rendert
   innerhalb von window.Modal.open() (rohes HTML, kein Lit-Template) --
   eigene, gescopte Klassen statt Wiederverwendung von .dup-member-pick
   (Kontakt-Zusammenfuehrung, _core.css): unterschiedlicher Kontext, eine
   spaetere Anpassung an einem der beiden Dialoge soll den anderen nicht
   mitreissen. Radio-Styling folgt demselben Muster (accent-color statt
   eigener Custom-Radio-Component). */
.todo-section-del-intro {
  margin: 0 0 .875rem;
  color: var(--text-secondary);
  font-size: .875rem;
}
.todo-section-del-explain {
  margin: 0;
  color: var(--text-secondary);
  font-size: .875rem;
}
.todo-section-del-choices {
  display: flex;
  flex-direction: column;
  gap: .625rem;
}
.todo-section-del-choice {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
  padding: .625rem .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease;
}
.todo-section-del-choice:hover { border-color: var(--accent); }
.todo-section-del-choice:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-light);
}
.todo-section-del-choice input[type="radio"] {
  margin-top: .1875rem;
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}
.todo-section-del-choice-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .375rem;
  font-size: .875rem;
  color: var(--text-primary);
}
.todo-section-del-choice-body strong { font-weight: 600; }
.todo-section-del-target { width: 100%; }
.todo-section-del-target:disabled { opacity: .5; cursor: not-allowed; }
.todo-section-del-hint {
  margin: .875rem 0 0;
  padding: .625rem .75rem;
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: .8125rem;
}
