/* MitaBase Pro — a product of ETMITA · https://etmita.com
   Copyright © ETMITA. All rights reserved. */
/* Inter + Vazirmatn — self-hosted woff2 in /fonts/. Were loading via
   @import from Google Fonts, but that triggered the CSP connect-src
   violation in the console. Latin + latin-ext for Inter (covers German
   umlauts) and arabic + latin + latin-ext for Vazirmatn. */
@font-face { font-family: "Inter"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("/fonts/Inter-400-latin.woff2") format("woff2"),
       url("/fonts/Inter-400-latin-ext.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("/fonts/Inter-500-latin.woff2") format("woff2"),
       url("/fonts/Inter-500-latin-ext.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("/fonts/Inter-700-latin.woff2") format("woff2"),
       url("/fonts/Inter-700-latin-ext.woff2") format("woff2"); }

body {
  font-family: "Yekan Bakh", "Vazirmatn", "Inter", -apple-system, "Segoe UI", sans-serif;
  background-color: #f8fafc;
  transition:
    background-color 0.3s,
    color 0.3s;
  overscroll-behavior-y: none;
}

html[dir="ltr"] body {
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}

.text-brand {
  color: #e11d48;
}
.bg-brand {
  background-color: #e11d48;
}

/* 🟢 کانتینر اصلی بورد */
/* Board scroll container. The old Kanban needed horizontal scrolling
   across driver columns; the new row layout (.dr-board) scrolls
   VERTICALLY through driver rows. The fixed calc(100dvh - …) height
   was a desktop bug — it left the rail clipped at the wrong line on
   panels with a taller toolbar (e.g. when the date strip wraps) and
   broke vertical scrolling because the container thought it was at
   the bottom of its content. Now we just fill the flex parent's
   remaining space with height:100% so the page math always works. */
.kanban-container {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 0;       /* required so flex children can shrink + scroll */
  overflow-y: auto;
  overflow-x: hidden;
  padding-bottom: 2rem;
  -webkit-overflow-scrolling: touch;
}

.unassigned-col {
  width: 320px;
  min-width: 320px;
  flex-shrink: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: #edf2f7;
  border: 1px dashed #cbd5e1;
  border-radius: 1.25rem;
}

.drivers-wrapper {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 1rem;
  height: 100%;
  overflow-y: auto;
  align-content: start;
  padding-bottom: 2rem;
  padding-left: 5px;
}

.kanban-col {
  display: flex;
  flex-direction: column;
  height: 60vh;
  min-height: 400px;
  background: #edf2f7;
  border-radius: 1.25rem;
  border: 1px solid #e2e8f0;
}

.sortable-list {
  flex: 1;
  overflow-y: auto;
  padding: 0.75rem;
  padding-bottom: 60px;
}

/* 🟢 استایل کارت‌ها */
.task-card {
  border-right: 4px solid #e2e8f0;
  transition: all 0.2s;
  cursor: grab;
  background: white;
  border-radius: 12px;
  padding: 14px;
  margin-bottom: 12px;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
}
html[dir="ltr"] .task-card {
  border-right: none;
  border-left: 4px solid #e2e8f0;
}
html[dir="ltr"] .task-card:hover {
  border-left-color: #e11d48;
}
.task-card:hover {
  border-right-color: #e11d48;
  transform: translateY(-2px);
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.05);
}
.task-card:active {
  cursor: grabbing;
  transform: scale(0.98);
}
.task-card[data-status="draft"] {
  border-style: dashed;
  border-right-style: solid;
  border-right-color: #94a3b8;
  background-color: #f8fafc;
}
.task-card[data-status="completed"] {
  border-right-color: #10b981;
  background-color: #f0fdf4;
}

.sortable-ghost {
  opacity: 0.4;
  background-color: #f1f5f9;
  border: 2px dashed #94a3b8;
}

/* 🟢 اسکرول بار */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background: #cbd5e1;
  border-radius: 10px;
}

/* 🟢 تب‌ها و کامپوننت‌های متفرقه */
.tab-btn {
  color: #64748b;
  border-bottom: 3px solid transparent;
  transition: all 0.3s;
  white-space: nowrap;
}
.tab-btn.active {
  color: #e11d48;
  border-bottom-color: #e11d48;
  background: #fff1f2;
  border-radius: 0.5rem 0.5rem 0 0;
}

.big-marker {
  background: #e11d48;
  border: 3px solid white;
  border-radius: 50%;
  box-shadow: 0 0 20px rgba(225, 29, 72, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 14px;
  font-weight: bold;
  width: 30px !important;
  height: 30px !important;
  margin-left: -15px !important;
  margin-top: -15px !important;
}

.fade-in {
  animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(5px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.modal-overlay {
  backdrop-filter: blur(4px);
}
.toast-show {
  top: 24px !important;
}
/* Severity tints. `.toast-info` keeps the default slate. */
#toast-container.toast-success {
  background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
  border-color: rgba(255, 255, 255, 0.18) !important;
  color: #ffffff !important;
}
#toast-container.toast-warning {
  background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%) !important;
  border-color: rgba(255, 255, 255, 0.18) !important;
  color: #ffffff !important;
}
#toast-container.toast-error {
  background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%) !important;
  border-color: rgba(255, 255, 255, 0.18) !important;
  color: #ffffff !important;
}
#toast-container.toast-success #toast-icon,
#toast-container.toast-warning #toast-icon,
#toast-container.toast-error   #toast-icon {
  color: #ffffff !important;
}

.pay-badge {
  padding: 4px 10px;
  border-radius: 8px;
  font-size: 11px;
  font-weight: 800;
}
.pay-privat {
  background: #fef3c7;
  color: #92400e;
  border: 1px solid #f59e0b;
}
.pay-befreit {
  background: #dbeafe;
  color: #1e40af;
  border: 1px solid #3b82f6;
}
.pay-paid {
  background: #d1fae5;
  color: #065f46;
  border: 1px solid #10b981;
}
.pay-nicht {
  background: #fee2e2 !important;
  color: #991b1b !important;
  border: 1px solid #ef4444 !important;
}

/* 🟢 دکمه‌های Art */
.art-btn {
  transition: all 0.2s;
  border: 1px solid #e2e8f0;
  background-color: #f8fafc;
  color: #64748b;
  border-radius: 0.5rem;
  padding: 0.5rem 0.25rem;
  font-size: 0.75rem;
  font-weight: bold;
  cursor: pointer;
}
.art-btn:hover {
  background-color: #f1f5f9;
  border-color: #cbd5e1;
}
.art-btn.selected {
  background-color: #e11d48 !important;
  border-color: #be123c !important;
  color: white !important;
  box-shadow: 0 4px 6px -1px rgba(225, 29, 72, 0.3);
}

/* 🟢 تم تاریک (Dark Mode) */
body.dark {
  background-color: #0f172a;
  color: #f8fafc;
}
body.dark .bg-white {
  background-color: #1e293b !important;
  border-color: #334155 !important;
}
body.dark .bg-slate-50,
body.dark .bg-slate-100 {
  background-color: #0f172a !important;
  border-color: #334155 !important;
}
body.dark .text-slate-800 {
  color: #f8fafc !important;
}
body.dark .text-slate-700 {
  color: #e2e8f0 !important;
}
body.dark .text-slate-600 {
  color: #cbd5e1 !important;
}
body.dark .text-slate-500 {
  color: #94a3b8 !important;
}
body.dark .border-slate-200,
body.dark .border-slate-100 {
  border-color: #334155 !important;
}
body.dark .kanban-col {
  background-color: #0f172a;
  border-color: #334155;
}
body.dark .task-card {
  background-color: #1e293b;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.5);
}
body.dark input,
body.dark select,
body.dark textarea {
  background-color: #0f172a !important;
  color: #f8fafc !important;
  border-color: #334155 !important;
}
body.dark .tab-btn {
  color: #94a3b8;
}
body.dark .task-card[data-status="draft"] {
  background-color: #0f172a;
}
body.dark .task-card[data-status="completed"] {
  background-color: #064e3b;
  border-right-color: #34d399;
}
body.dark .pay-privat {
  background: #78350f;
  color: #fde68a;
}
body.dark .pay-befreit {
  background: #1e3a8a;
  color: #bfdbfe;
}
body.dark .pay-paid {
  background: #064e3b;
  color: #a7f3d0;
}
body.dark .pay-nicht {
  background: #450a0a !important;
  color: #fca5a5 !important;
  border-color: #7f1d1d !important;
}
body.dark .art-btn {
  border-color: #334155;
  background-color: #1e293b;
  color: #94a3b8;
}
body.dark .art-btn:hover {
  background-color: #0f172a;
  border-color: #475569;
}

/* 🟢 استایل‌های دراور (لیست انتظار کشویی) */
.drawer-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.5);
  z-index: 99990 !important; /* فیکس تداخل لایه */
  backdrop-filter: blur(3px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s;
}
.drawer-overlay.open {
  opacity: 1;
  pointer-events: auto;
}

.unassigned-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 340px;
  max-width: 85vw;
  background: #f8fafc;
  z-index: 99995 !important; /* فیکس تداخل لایه در موبایل */
  transform: translateX(100%);
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  display: flex;
  flex-direction: column;
  box-shadow: -10px 0 25px -5px rgba(0, 0, 0, 0.1);
  border-left: 1px solid #cbd5e1;
}
html[dir="ltr"] .unassigned-drawer {
  right: auto;
  left: 0;
  transform: translateX(-100%);
  box-shadow: 10px 0 25px -5px rgba(0, 0, 0, 0.1);
  border-left: none;
  border-right: 1px solid #cbd5e1;
}
.unassigned-drawer.open {
  transform: translateX(0);
  z-index: 99999 !important;
}
/* Specificity fix: html[dir="ltr"] .unassigned-drawer is (0,2,1) which
   beats .unassigned-drawer.open (0,2,0), so without this rule the LTR
   off-screen transform keeps the drawer hidden even after `.open` is
   toggled on. This explicit LTR+open rule wins at (0,3,1). */
html[dir="ltr"] .unassigned-drawer.open {
  transform: translateX(0) !important;
}
body.dark .unassigned-drawer {
  background: #0f172a;
  border-color: #334155;
}

/* 🟢 🟢 🟢 مدیا کوئری یکپارچه و بهینه‌شده برای موبایل 🟢 🟢 🟢 */
@media (max-width: 768px) {
  .kanban-container {
    height: 100%;       /* new row layout scrolls vertically too */
    overflow-x: hidden;
    overflow-y: auto;
    scroll-snap-type: none;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 12px;
  }

  .drivers-wrapper {
    /* 🔴 باگ display: contents حذف شد */
    display: flex;
    flex-direction: row;
    width: max-content;
    height: 100%;
    gap: 0.75rem;
  }

  .unassigned-col,
  .kanban-col {
    width: 88vw;
    min-width: 88vw;
    height: 100%;
    scroll-snap-align: center;
    flex-shrink: 0;
    margin-left: 2px;
  }

  input,
  select,
  textarea {
    font-size: 16px !important; /* جلوگیری از زوم خودکار در آیفون */
  }

  header {
    margin-bottom: 4px !important;
    padding-bottom: 4px !important;
  }

  /* 🟢 فیکس اصلی منوهای هدر: اجازه Wrap شدن */
  header > div:nth-child(2) {
    flex-wrap: wrap !important;
    overflow: visible !important;
    padding-bottom: 2px;
  }
  header > div:nth-child(2) button {
    flex-shrink: 0;
  }

  .stat-card {
    padding: 0.35rem;
    flex-direction: column;
    text-align: center;
    justify-content: center;
    gap: 0px;
  }
  .stat-card h2 {
    font-size: 1rem;
    line-height: 1;
    margin-top: 2px;
  }
  .stat-card p {
    font-size: 0.55rem;
    white-space: normal;
    line-height: 1.1;
  }
  .stat-icon-wrapper {
    width: 18px;
    height: 18px;
    margin: 0 auto;
    order: -1;
  }
  .stat-icon-wrapper i {
    font-size: 0.6rem;
  }
  .tab-btn {
    padding: 0.35rem 0.5rem !important;
    font-size: 0.7rem !important;
  }
}

/* 🟢 Phones in LANDSCAPE — when width goes above 768px on rotation but
   the device height drops below ~500px, the desktop layout kicks in
   with cramped vertical space and the header eats half the screen.
   Catch this with an explicit height-based query. */
@media (max-height: 500px) and (orientation: landscape) {
  .kanban-container {
    /* fill parent — same logic as desktop, just less header chrome */
    height: 100%;
  }
  header {
    margin-bottom: 2px !important;
    padding: 4px 6px !important;
  }
  header > div:nth-child(2) {
    flex-wrap: nowrap !important;
    overflow-x: auto !important;
    scrollbar-width: none;
  }
  header > div:nth-child(2)::-webkit-scrollbar {
    display: none;
  }
  .stat-card {
    padding: 0.25rem 0.4rem;
    transform: scale(0.85);
    transform-origin: top right;
  }
  .tab-btn {
    padding: 0.25rem 0.5rem !important;
    font-size: 0.7rem !important;
  }
  .kanban-col,
  .unassigned-col {
    height: 100% !important;
  }
  /* There was a `.modal-content { max-height: 92dvh }` here, meant to
     compact modals on landscape phones. `.modal-content` does not
     exist anywhere in this project — not in index.html, not in app.js,
     not in js/. It was the only rule in the whole stylesheet that
     mentioned a modal at a breakpoint, so its presence read as "mobile
     modal CSS exists". It did nothing. Removed rather than left as a
     decoy; the real per-modal mobile rules live with .dispo-advisor. */
}

/* 🟢 جلوگیری از تداخل تاچ درگ با اسکرول افقی در موبایل */
.sortable-list,
.task-card,
.col-header {
  touch-action: pan-y pan-x manipulation;
}
/* 🟢 حذف پس‌زمینه مزاحم هنگام باز بودن کشوی لیست انتظار */
.drawer-overlay {
  display: none !important;
}

/* 🟢 اطمینان از اسکرول و درگ نرم در موبایل.
   `manipulation` همان هدف اولیه را دارد (جلوگیری از double-tap
   zoom) ولی برخلاف `pan-y` کلیک روی دکمه‌های فرزند را روی
   iOS Safari مختل نمی‌کند. اسکرول عمودی همچنان کار می‌کند. */
.sortable-list {
  touch-action: manipulation !important;
}
.task-card {
  touch-action: manipulation !important;
}
.col-header {
  touch-action: manipulation !important;
}

/* ── Mobile drag-drop: kill scroll-snap during drag ───────────────
   The board uses scroll-snap-type: x mandatory so each driver column
   sits centered on mobile. That snap fights Sortable's auto-scroll —
   every time autoscroll nudges the board to reveal the next column,
   snap pulls it back. Sortable adds the drag class via JS (onStart). */
body.dragging-task .kanban-container {
  scroll-snap-type: none !important;
  scroll-behavior: auto !important;
}
/* Highlight empty driver columns so it's obvious you can drop there. */
body.dragging-task .sortable-list {
  outline: 2px dashed transparent;
  outline-offset: -8px;
  border-radius: 12px;
  transition: outline-color 0.15s, background-color 0.15s;
}
body.dragging-task .sortable-list:not(:has(.task-card)) {
  background: rgba(225, 29, 72, 0.06);
  outline-color: rgba(225, 29, 72, 0.4);
}
body.dark.dragging-task .sortable-list:not(:has(.task-card)) {
  background: rgba(225, 29, 72, 0.12);
}

/* ════════════════════════════════════════════════════════════════════
   DISPOSITION (Operations Board) — ROW LAYOUT v2
   ════════════════════════════════════════════════════════════════════ */

/* The board is now a vertical stack of "driver rows". Each row has a
   sticky "cockpit" on the start side (avatar + name + vehicle + KPIs)
   and a horizontal task strip on the rest. On <768 px the cockpit
   stacks above the strip and the strip wraps. */

.dr-board {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 4px;
}

.dr-row {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  gap: 0;
  background: linear-gradient(135deg, #ffffff 0%, #fafbff 100%);
  border: 1px solid #e2e8f0;
  border-radius: 22px;
  box-shadow: 0 1px 0 rgba(15,23,42,0.02), 0 8px 22px rgba(15,23,42,0.05);
  overflow: hidden;
  transition: box-shadow 0.18s, transform 0.18s;
}
.dr-row:hover { box-shadow: 0 1px 0 rgba(15,23,42,0.02), 0 12px 30px rgba(15,23,42,0.09); }
body.dark .dr-row {
  background: linear-gradient(135deg, #1e293b 0%, #18243a 100%);
  border-color: #334155;
}
.dr-row-suspended {
  background: linear-gradient(135deg, #fef2f2 0%, #ffffff 100%);
  border-color: #fca5a5;
}
body.dark .dr-row-suspended {
  background: linear-gradient(135deg, rgba(127,29,29,0.20) 0%, #1e293b 100%);
  border-color: #7f1d1d;
}

/* ───── Driver cockpit (left/start side) ───── */
.dr-info {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 12px;
  align-items: start;
  padding: 16px 14px;
  background: linear-gradient(180deg, rgba(255,255,255,0.85) 0%, rgba(255,255,255,0) 100%);
  border-inline-end: 1px solid #e2e8f0;
  position: relative;
}
body.dark .dr-info {
  background: linear-gradient(180deg, rgba(15,23,42,0.30) 0%, rgba(15,23,42,0) 100%);
  border-inline-end-color: #334155;
}
.dr-avatar { position: relative; flex-shrink: 0; }
.dr-avatar-img, .dr-avatar-fallback {
  width: 52px; height: 52px;
  border-radius: 16px;
  border: 2px solid #fff;
  box-shadow: 0 4px 12px rgba(15,23,42,0.12);
  object-fit: cover;
}
.dr-avatar-fallback {
  background: linear-gradient(135deg, #be123c, #e11d48);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 900; font-size: 20px;
}
body.dark .dr-avatar-img, body.dark .dr-avatar-fallback { border-color: #1e293b; }
.dr-live-dot {
  position: absolute;
  bottom: -2px; inset-inline-end: -2px;
  width: 14px; height: 14px;
  border-radius: 999px;
  background: #10b981;
  border: 2.5px solid #fff;
  box-shadow: 0 0 0 3px rgba(16,185,129,0.35);
  animation: kc-pulse 1.5s ease-in-out infinite;
}
body.dark .dr-live-dot { border-color: #1e293b; }
.dr-id { min-width: 0; flex: 1; }
.dr-name {
  font-weight: 900; font-size: 15px;
  color: #1e293b;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  letter-spacing: -0.2px;
}
body.dark .dr-name { color: #f1f5f9; }
.dr-sub {
  font-size: 11px; font-weight: 700;
  color: #94a3b8;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  margin-top: 3px;
}
.dr-sub i { color: #cbd5e1; font-size: 10px; margin-inline-end: 4px; }
body.dark .dr-sub { color: #64748b; }
body.dark .dr-sub i { color: #475569; }

.dr-kpis { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }
.dr-kpi {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px;
  border-radius: 8px;
  font-size: 12px; font-weight: 800;
  letter-spacing: -0.1px;
  white-space: nowrap;     /* "مأموریت‌های فعال" was wrapping on iPhone */
}
.dr-kpi i { font-size: 10px; }
.dr-kpi-lbl { font-weight: 700; opacity: 0.75; font-size: 10px; white-space: nowrap; }
.dr-kpi-open  { background: #fef3c7; color: #b45309; }
.dr-kpi-done  { background: #d1fae5; color: #047857; }
.dr-kpi-live  { background: #dcfce7; color: #15803d; }
.dr-kpi-live i { color: #16a34a; animation: kc-pulse 1.5s ease-in-out infinite; }
body.dark .dr-kpi-open { background: rgba(245,158,11,0.20); color: #fcd34d; }
body.dark .dr-kpi-done { background: rgba(16,185,129,0.20); color: #6ee7b7; }
body.dark .dr-kpi-live { background: rgba(34,197,94,0.20); color: #86efac; }

.dr-actions { display: flex; flex-direction: column; gap: 6px; }
.dr-iconbtn {
  width: 32px; height: 32px;
  border-radius: 10px;
  background: #f1f5f9;
  color: #94a3b8;
  border: none;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px;
  transition: all 0.12s;
}
.dr-iconbtn:hover { background: #fee2e2; color: #dc2626; transform: scale(1.06); }
.dr-iconbtn-on { background: #d1fae5; color: #047857; }
.dr-iconbtn-on:hover { background: #10b981; color: #fff; }
body.dark .dr-iconbtn { background: rgba(51,65,85,0.5); color: #94a3b8; }
body.dark .dr-iconbtn:hover { background: rgba(127,29,29,0.45); color: #fca5a5; }
body.dark .dr-iconbtn-on { background: rgba(6,95,70,0.35); color: #6ee7b7; }

/* ───── Task strip (right/end side) ───── */
.dr-tasks {
  display: flex;
  gap: 12px;
  padding: 16px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.dr-tasks::-webkit-scrollbar { height: 6px; }
.dr-tasks::-webkit-scrollbar-track { background: transparent; }
.dr-tasks::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 3px; }

.dr-empty {
  flex: 1;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 24px;
  color: #94a3b8;
  font-size: 13px;
  font-weight: 700;
  font-style: italic;
  border: 1px dashed #e2e8f0;
  border-radius: 14px;
  min-height: 110px;
}
.dr-empty i { font-size: 18px; color: #cbd5e1; }
body.dark .dr-empty { color: #64748b; border-color: #334155; }
body.dark .dr-empty i { color: #475569; }

/* ───── Task "ticket" cards ───── */
.tk-card {
  display: grid;
  /* Wider body column so the dispatcher reads the full pickup +
     dropoff address (incl. Station). Was: 220-280px → cramped.
     Now: 340-440px and the route lines wrap to 2 lines below.

     The 340px floor is why the strip needs at least ~430px per ticket.
     Below 767px the rule further down re-flows the card, but between
     768 and ~900px — tablets, and any phone in landscape — neither
     applied: the ticket kept its floor, the strip overflowed, and
     there was no scrollbar or any other sign that it could be dragged.
     The band is handled just below this rule. */
  grid-template-columns: 78px minmax(340px, 440px) auto;
  gap: 12px;
  background: #fff;
  border: 1px solid #e2e8f0;
  border-radius: 16px;
  padding: 12px;
  flex-shrink: 0;
  scroll-snap-align: start;
  transition: transform 0.12s, box-shadow 0.12s, border-color 0.12s;
  position: relative;
}

/* 768-900px: give the ticket a smaller floor so it fits, and make the
   strip's horizontal scroll visible instead of silent. */
@media (min-width: 768px) and (max-width: 900px) {
  .tk-card { grid-template-columns: 70px minmax(200px, 1fr) auto; gap: 8px; }
  .dr-tasks { scrollbar-width: thin; }
  .dr-tasks::-webkit-scrollbar { height: 6px; }
  .dr-tasks::-webkit-scrollbar-track { background: transparent; }
  .dr-tasks::-webkit-scrollbar-thumb {
    background: rgba(2, 6, 23, 0.18); border-radius: 999px;
  }
  body.dark .dr-tasks::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.22); }
}
/* A stale open task (dated before today) is unmistakable on the board: the
   whole card is re-tinted amber, and a bold diagonal sash — top-right to
   bottom-left — is struck across it carrying "Auftrag von gestern / von vor
   N Tagen". Applies to both the per-driver tiles (.tk-card) and the
   unassigned-pool cards (.task-card). */
.tk-card.is-stale,
.task-card.is-stale {
  background: #fffbeb !important;
  border-color: #f59e0b !important;
  position: relative;
}
body.dark .tk-card.is-stale,
body.dark .task-card.is-stale {
  background: rgba(245, 158, 11, 0.14) !important;
  border-color: #b45309 !important;
}
.tk-diag {
  position: absolute;
  inset: 0;
  overflow: hidden;          /* the overlay clips the sash — the card keeps its overflow */
  border-radius: inherit;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;      /* never blocks the card's hover buttons */
  z-index: 2;
}
.tk-diag span {
  width: 175%;
  text-align: center;
  transform: rotate(-16deg);
  background: rgba(217, 119, 6, 0.92);
  color: #fff;
  font-weight: 900;
  font-size: 12px;
  letter-spacing: 0.3px;
  padding: 4px 0;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.28);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.tk-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(15,23,42,0.08);
  border-color: #cbd5e1;
}
/* Whole-card colour cues driven by Erledigt + AI verdict so the
   dispatcher can scan the board without reading any text.
   Green: task complete AND AI accepted (or admin approved).
   Yellow: AI says needs_review or rejected — manual check needed,
   even if the driver already pressed Erledigt. */
.tk-card.tk-card-ok {
  background: #f0fdf4;
  border-color: #86efac;
  box-shadow: 0 0 0 1px rgba(134, 239, 172, 0.5) inset;
}
.tk-card.tk-card-ok:hover { border-color: #4ade80; }
.tk-card.tk-card-review {
  background: #fefce8;
  border-color: #fde047;
  box-shadow: 0 0 0 1px rgba(253, 224, 71, 0.6) inset;
}
.tk-card.tk-card-review:hover { border-color: #facc15; }
body.dark .tk-card.tk-card-ok {
  background: rgba(34,197,94,0.10);
  border-color: rgba(74,222,128,0.4);
}
body.dark .tk-card.tk-card-review {
  background: rgba(234,179,8,0.10);
  border-color: rgba(250,204,21,0.4);
}
.tk-review-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  font-size: 10px;
  font-weight: 700;
  background: #facc15;
  color: #422006;
  border-radius: 9999px;
  cursor: pointer;
  border: none;
  margin-inline-start: 6px;
}
.tk-review-btn:hover { background: #eab308; }
.tk-archive-btn {
  background: #d1fae5;
  color: #047857;
}
.tk-archive-btn:hover { background: #6ee7b7 !important; color: #064e3b !important; }
.tk-return-btn {
  background: #fef3c7;
  color: #b45309;
}
.tk-return-btn:hover { background: #fcd34d !important; color: #78350f !important; }

/* Station / Zimmer / Bett highlight inside an address. <mark> tag
   so screen readers announce it, custom style so it isn't yellow. */
.addr-station {
  background: linear-gradient(180deg, #fdf4ff 0%, #fae8ff 100%);
  color: #6b21a8;
  padding: 1px 6px;
  margin: 0 2px;
  border-radius: 6px;
  font-weight: 900;
  font-style: normal;
  letter-spacing: 0.2px;
  white-space: nowrap;
  border: 1px solid #e9d5ff;
}
body.dark .addr-station {
  background: rgba(168, 85, 247, 0.18);
  color: #e9d5ff;
  border-color: rgba(168, 85, 247, 0.35);
}
body.dark .tk-card { background: #1e293b; border-color: #334155; }
body.dark .tk-card:hover { border-color: #475569; }

.tk-time {
  text-align: center;
  border-inline-end: 1px dashed #e2e8f0;
  padding-inline-end: 12px;
}
body.dark .tk-time { border-inline-end-color: #334155; }
.tk-time-hm {
  font-weight: 900;
  font-size: 18px;
  color: #e11d48;
  letter-spacing: -0.5px;
  white-space: nowrap;
}
.tk-time-hm i { font-size: 11px; margin-inline-end: 3px; }
.tk-time-date {
  margin-top: 3px;
  font-size: 10px;
  font-weight: 800;
  color: #6366f1;
  background: #eef2ff;
  border-radius: 6px;
  padding: 2px 6px;
  display: inline-block;
}
body.dark .tk-time-date { background: rgba(99,102,241,0.20); color: #a5b4fc; }
.tk-id {
  margin-top: 6px;
  font-size: 10px;
  font-weight: 800;
  color: #94a3b8;
  font-family: ui-monospace, monospace;
}

.tk-body { min-width: 0; }
.tk-head {
  display: flex; justify-content: space-between; align-items: start; gap: 8px;
  margin-bottom: 8px;
}
.tk-patient {
  font-weight: 900;
  font-size: 14px;
  color: #1e293b;
  line-height: 1.2;
  min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body.dark .tk-patient { color: #f1f5f9; }
.tk-status {
  font-size: 10px;
  font-weight: 900;
  padding: 3px 8px;
  border-radius: 6px;
  white-space: nowrap;
  flex-shrink: 0;
  letter-spacing: 0.1px;
}
.tk-status.tk-sent       { background: #dbeafe; color: #1d4ed8; }
.tk-status.tk-acked      { background: #d1fae5; color: #047857; }
.tk-status.tk-progress   { background: #ede9fe; color: #6d28d9; }
.tk-status.tk-done       { background: #d1fae5; color: #047857; }
.tk-status.tk-draft      { background: #e2e8f0; color: #475569; }
.tk-status.tk-draft-alert{ background: #fef3c7; color: #b45309; border: 1px solid #fcd34d; animation: kc-pulse 1.5s ease-in-out infinite; }
body.dark .tk-status.tk-sent { background: rgba(59,130,246,0.20); color: #93c5fd; }
body.dark .tk-status.tk-acked { background: rgba(16,185,129,0.20); color: #6ee7b7; }
body.dark .tk-status.tk-progress { background: rgba(124,58,237,0.20); color: #c4b5fd; }
body.dark .tk-status.tk-done { background: rgba(16,185,129,0.20); color: #6ee7b7; }
body.dark .tk-status.tk-draft { background: rgba(100,116,139,0.30); color: #cbd5e1; }
body.dark .tk-status.tk-draft-alert { background: rgba(245,158,11,0.25); color: #fcd34d; }

.tk-route {
  display: flex; align-items: flex-start; gap: 8px;
  font-size: 12px; font-weight: 600;
  color: #475569;
  margin-bottom: 8px;
  min-width: 0;
}
/* Allow up to two lines per from/to address so the dispatcher
   sees the full street + city + Station instead of being
   truncated with a tooltip. */
.tk-route span {
  min-width: 0; flex: 1;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.35;
  word-break: break-word;
}
.tk-route i { font-size: 10px; color: #94a3b8; margin-inline-end: 4px; flex-shrink: 0; margin-top: 3px; }
.tk-route-from i { color: #10b981; }
.tk-route-to   i { color: #e11d48; }
.tk-route-arrow { color: #cbd5e1; font-size: 11px !important; flex-shrink: 0; }
body.dark .tk-route { color: #cbd5e1; }
body.dark .tk-route i { color: #64748b; }
body.dark .tk-route-arrow { color: #475569; }

.tk-meta {
  display: flex; flex-wrap: wrap; gap: 6px;
  font-size: 11px;
}
.tk-art {
  font-weight: 800;
  color: #4338ca;
}
.tk-art i { font-size: 9px; margin-inline-end: 3px; }
body.dark .tk-art { color: #a5b4fc; }
.tk-codriver {
  background: #f5f3ff;
  color: #6d28d9;
  padding: 2px 7px;
  border-radius: 6px;
  font-weight: 700;
}
.tk-codriver i { font-size: 9px; margin-inline-end: 3px; }
body.dark .tk-codriver { background: rgba(124,58,237,0.20); color: #c4b5fd; }
.tk-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  border-radius: 6px;
  cursor: pointer;
}
.tk-chip.tk-chip-info { background: #f1f5f9; color: #475569; }
.tk-chip.tk-chip-ok   { background: #d1fae5; color: #047857; }
.tk-chip.tk-chip-warn { background: #fef3c7; color: #b45309; animation: kc-pulse 1.5s ease-in-out infinite; }

.tk-actions {
  display: flex; flex-direction: column; gap: 4px;
  opacity: 0;
  transition: opacity 0.12s;
}
.tk-card:hover .tk-actions { opacity: 1; }
/* Touch devices have no real :hover. The "sticky hover" trick (tap
   once to reveal, twice to actually press) makes the edit/move/delete
   icons feel broken — especially on tablets where the <767px mobile
   stack doesn't kick in. Force the action row visible whenever the
   primary pointer is coarse (touch screens), regardless of viewport
   width. Also bump the touch targets — 26px is below Apple's HIG
   (44px) and Material's recommendation (48dp).

   Round 1 of this fix (ce7ae19) only covered .tk-actions, the
   per-driver column cards. Three components in the panel render
   task cards with hover-to-reveal action buttons:
     (1) .tk-actions / .tk-action     — dispatch.js per-driver columns
     (2) .task-card .opacity-0        — createCardHtml unassigned drawer
     (3) .tp-task-actions / .tp-task-act — tagesplan planning tab
   Round 2 (this rule) covers all three. */
@media (hover: none) and (pointer: coarse) {
  /* (1) per-driver column cards */
  .tk-actions { opacity: 1 !important; }
  .tk-action  { width: 36px; height: 36px; font-size: 13px; }

  /* (2) unassigned drawer cards — Tailwind opacity-0
     group-hover:opacity-100 never fires on touch. Scope to
     .task-card so we don't reveal unrelated opacity-0 elements. */
  .task-card .opacity-0        { opacity: 1 !important; }
  .task-card .opacity-0 button { width: 36px; height: 36px; }

  /* (3) tagesplan task pills — same pattern, 22px buttons too tiny. */
  .tp-task-actions { opacity: 1 !important; }
  .tp-task-act     { width: 32px; height: 32px; font-size: 12px; }
}
.tk-action {
  width: 26px; height: 26px;
  border-radius: 7px;
  border: none;
  background: #f1f5f9;
  color: #64748b;
  cursor: pointer;
  font-size: 10px;
  transition: all 0.12s;
}
.tk-action:hover { background: #cbd5e1; color: #1e293b; transform: scale(1.05); }
.tk-action-danger:hover { background: #fee2e2; color: #b91c1c; }
body.dark .tk-action { background: rgba(51,65,85,0.5); color: #94a3b8; }
body.dark .tk-action:hover { background: #475569; color: #f1f5f9; }

/* ───── Mobile: stack the row ───── */
@media (max-width: 767px) {
  .dr-row {
    grid-template-columns: 1fr;
    border-radius: 18px;
  }
  .dr-info {
    border-inline-end: none;
    border-bottom: 1px solid #e2e8f0;
    padding: 12px;
    grid-template-columns: auto 1fr auto;
  }
  body.dark .dr-info { border-bottom-color: #334155; }
  /* Drop the secondary text label inside KPI pills on small screens —
     icon + number stays, the Persian/German label takes too much
     width and pushes the cockpit to wrap. */
  .dr-kpis { gap: 4px; margin-top: 8px; }
  .dr-kpi { padding: 3px 7px; font-size: 11px; }
  .dr-kpi-lbl { display: none; }
  .dr-avatar-img, .dr-avatar-fallback { width: 44px; height: 44px; border-radius: 12px; }
  .dr-name { font-size: 14px; }
  .dr-tasks {
    flex-direction: column;
    overflow-x: visible;
    padding: 10px;
    gap: 8px;
  }
  .tk-card {
    grid-template-columns: 64px 1fr;
    grid-template-areas:
      "time body"
      "actions actions";
    padding: 10px;
    width: 100%;
  }
  .tk-card .tk-time    { grid-area: time;    border-inline-end: 1px dashed #e2e8f0; padding-inline-end: 8px; }
  .tk-card .tk-body    { grid-area: body; }
  .tk-card .tk-actions { grid-area: actions; opacity: 1; flex-direction: row; justify-content: flex-end; gap: 6px; padding-top: 6px; border-top: 1px dashed #e2e8f0; margin-top: 2px; }
  body.dark .tk-card .tk-actions { border-top-color: #334155; }
  .tk-time-hm { font-size: 16px; }
  .tk-route   { font-size: 11px; flex-wrap: wrap; }
}


/* Idle strip — chips above the board for drivers without active
   tasks (default hidden so the rail stays compact). */
.kc-idle-strip {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  margin: 0 0 12px;
  background: linear-gradient(90deg, #fff7ed 0%, #fff 100%);
  border: 1px solid #fed7aa;
  border-radius: 16px;
  flex-wrap: wrap;
}
body.dark .kc-idle-strip {
  background: linear-gradient(90deg, rgba(245,158,11,0.10) 0%, rgba(15,23,42,0.5) 100%);
  border-color: rgba(245,158,11,0.30);
}
.kc-idle-strip-compact { background: transparent; border: none; padding: 6px 4px; margin-bottom: 8px; }
.kc-idle-label {
  display: inline-flex; align-items: center; gap: 6px;
  font-weight: 800; font-size: 12px; color: #b45309;
}
body.dark .kc-idle-label { color: #fcd34d; }
.kc-idle-count {
  background: #fb923c; color: #fff;
  font-size: 10px; font-weight: 900;
  padding: 2px 7px; border-radius: 999px;
  margin-inline-start: 2px;
}
.kc-idle-chips {
  display: flex; flex-wrap: wrap; gap: 6px;
  flex: 1; min-width: 0;
}
/* Mobile: kill the avatar wall — collapse to a single "Anzeigen"
   button on the right of the label. The drivers themselves are one
   tap away. */
@media (max-width: 767px) {
  .kc-idle-chips .kc-idle-chip { display: none; }
  .kc-idle-strip { padding: 8px 12px; }
  .kc-idle-label { font-size: 11px; }
}
.kc-idle-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 4px;
  background: #fff;
  border: 1px solid #e2e8f0;
  border-radius: 999px;
  font-size: 11px; font-weight: 700;
  color: #475569;
  cursor: pointer;
  transition: all 0.12s;
}
.kc-idle-chip:hover {
  border-color: #fb923c;
  color: #1e293b;
  transform: translateY(-1px);
}
body.dark .kc-idle-chip { background: rgba(51,65,85,0.5); border-color: #334155; color: #cbd5e1; }
.kc-idle-chip img, .kc-idle-chip span:first-child {
  width: 22px; height: 22px;
  border-radius: 999px;
  object-fit: cover;
  background: linear-gradient(135deg, #be123c, #e11d48);
  color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 900; font-size: 10px;
  flex-shrink: 0;
}
.kc-idle-show-all {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px;
  background: transparent;
  border: 1px dashed #94a3b8;
  border-radius: 999px;
  font-size: 11px; font-weight: 800;
  color: #475569;
  cursor: pointer;
  transition: all 0.12s;
  white-space: nowrap;
  flex-shrink: 0;
}
.kc-idle-show-all:hover { background: #f1f5f9; color: #0f172a; }
body.dark .kc-idle-show-all { color: #cbd5e1; }
body.dark .kc-idle-show-all:hover { background: rgba(51,65,85,0.6); color: #fff; }

/* Driver column — hero header with avatar, name, vehicle, KPI pills */
.kc-col {
  border-radius: 20px;
  background: linear-gradient(180deg, #ffffff 0%, #fafbff 100%);
  border: 1px solid #e2e8f0;
  box-shadow: 0 1px 0 rgba(15, 23, 42, 0.02), 0 6px 16px rgba(15,23,42,0.04);
  transition: transform 0.15s, box-shadow 0.15s;
  overflow: hidden;
}
.kc-col:hover {
  box-shadow: 0 1px 0 rgba(15,23,42,0.02), 0 10px 24px rgba(15,23,42,0.08);
}
body.dark .kc-col {
  background: linear-gradient(180deg, #1e293b 0%, #18243a 100%);
  border-color: #334155;
}
.kc-col-suspended {
  background: linear-gradient(180deg, #fef2f2 0%, #ffffff 100%);
  border-color: #fca5a5;
}
body.dark .kc-col-suspended {
  background: linear-gradient(180deg, rgba(127,29,29,0.18) 0%, #1e293b 100%);
  border-color: #7f1d1d;
}

.kc-header {
  padding: 14px 14px 10px !important;
  border-bottom: 1px solid #e2e8f0;
  background: transparent !important;
  border-radius: 20px 20px 0 0 !important;
  cursor: default !important;
  display: flex; flex-direction: column; gap: 10px;
}
body.dark .kc-header { border-bottom-color: #334155; }
.kc-head-top {
  display: flex; align-items: center; gap: 10px;
}
.kc-avatar { position: relative; flex-shrink: 0; }
.kc-avatar-img,
.kc-avatar-fallback {
  width: 44px; height: 44px;
  border-radius: 14px;
  border: 2px solid #fff;
  box-shadow: 0 4px 12px rgba(15,23,42,0.10);
  ring: 1px solid #e2e8f0;
  object-fit: cover;
}
.kc-avatar-fallback {
  background: linear-gradient(135deg, #be123c, #e11d48);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 900; font-size: 18px;
}
body.dark .kc-avatar-img,
body.dark .kc-avatar-fallback { border-color: #1e293b; }
.kc-live-dot {
  position: absolute;
  bottom: -2px; inset-inline-end: -2px;
  width: 12px; height: 12px;
  border-radius: 999px;
  background: #10b981;
  border: 2px solid #fff;
  box-shadow: 0 0 0 2px rgba(16,185,129,0.35);
  animation: kc-pulse 1.5s ease-in-out infinite;
}
body.dark .kc-live-dot { border-color: #1e293b; }
@keyframes kc-pulse {
  0%,100% { transform: scale(1); }
  50%     { transform: scale(1.15); }
}
.kc-id { flex: 1; min-width: 0; }
.kc-name {
  font-weight: 900; font-size: 14px;
  color: #1e293b;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  letter-spacing: -0.2px;
}
body.dark .kc-name { color: #f1f5f9; }
.kc-sub {
  font-size: 11px; font-weight: 700;
  color: #94a3b8;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  margin-top: 2px;
}
.kc-sub i { color: #cbd5e1; font-size: 10px; margin-inline-end: 4px; }
body.dark .kc-sub { color: #64748b; }
body.dark .kc-sub i { color: #475569; }

.kc-iconbtn {
  width: 30px; height: 30px;
  border-radius: 10px;
  background: #f1f5f9;
  color: #94a3b8;
  border: none;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px;
  transition: all 0.12s;
  flex-shrink: 0;
}
.kc-iconbtn:hover { background: #fee2e2; color: #dc2626; transform: scale(1.05); }
.kc-iconbtn-on   { background: #d1fae5; color: #047857; }
.kc-iconbtn-on:hover { background: #10b981; color: #fff; }
body.dark .kc-iconbtn { background: rgba(51,65,85,0.5); color: #94a3b8; }
body.dark .kc-iconbtn:hover { background: rgba(127,29,29,0.45); color: #fca5a5; }
body.dark .kc-iconbtn-on { background: rgba(6,95,70,0.35); color: #6ee7b7; }

.kc-kpi-strip {
  display: flex; gap: 6px; flex-wrap: wrap;
}
.kc-kpi {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px;
  border-radius: 8px;
  font-size: 11px; font-weight: 800;
  letter-spacing: -0.1px;
}
.kc-kpi i { font-size: 10px; }
.kc-kpi-open   { background: #fef3c7; color: #b45309; }
.kc-kpi-done   { background: #d1fae5; color: #047857; }
.kc-kpi-live   { background: #dcfce7; color: #15803d; position: relative; }
.kc-kpi-live i { color: #16a34a; animation: kc-pulse 1.5s ease-in-out infinite; }
body.dark .kc-kpi-open { background: rgba(245,158,11,0.20); color: #fcd34d; }
body.dark .kc-kpi-done { background: rgba(16,185,129,0.20); color: #6ee7b7; }
body.dark .kc-kpi-live { background: rgba(34,197,94,0.20); color: #86efac; }

.kc-empty {
  padding: 24px 12px;
  text-align: center;
  font-size: 12px;
  font-weight: 600;
  color: #94a3b8;
  font-style: italic;
  border: 1px dashed #e2e8f0;
  border-radius: 14px;
  margin: 8px 12px;
}
.kc-empty i { display: block; font-size: 20px; color: #cbd5e1; margin-bottom: 6px; }
body.dark .kc-empty { color: #64748b; border-color: #334155; }
body.dark .kc-empty i { color: #475569; }

.kc-day-empty {
  width: 100%;
  text-align: center;
  padding: 60px 20px;
  color: #94a3b8;
  font-size: 14px;
  font-weight: 600;
}
.kc-day-empty i { display: block; font-size: 42px; margin-bottom: 14px; color: #cbd5e1; }
.kc-day-empty .kc-link {
  display: inline-block;
  margin-top: 12px;
  color: #e11d48;
  font-weight: 800;
  text-decoration: underline;
  background: none; border: none;
  cursor: pointer;
  font-size: 13px;
}
body.dark .kc-day-empty { color: #64748b; }
body.dark .kc-day-empty i { color: #334155; }

/* ════════════════════════════════════════════════════════════════════
   ADMIN PANEL — SIDEBAR LAYOUT (replaces the old top nav)
   Sidebar sits on the start-side (right in RTL, left in LTR).
   Desktop ≥ 1024px: sidebar always visible.
   Mobile < 1024px: sidebar becomes a slide-in drawer + topbar.
   ════════════════════════════════════════════════════════════════════ */
.layout-shell {
  display: flex;
  flex-direction: column;
  flex: 1;
  height: 100%;
  min-height: 0;
  overflow: hidden;
}
.layout-body {
  flex: 1;
  display: flex;
  /* row + document direction = the shell mirrors properly in RTL
     (operator restored full mirroring, 2026-08-21). */
  flex-direction: row;
  min-height: 0;
  position: relative;
}

/* The shell visuals (navbar + sidebar) live in /navbar.css and
   /sidebar.css — standalone components, see public/js/shell/. */

/* ── Content column: navbar on top, main below — the sidebar owns the
   full height of the start side and the navbar never sits above it. */
.layout-col {
  flex: 1; display: flex; flex-direction: column;
  min-width: 0; min-height: 0;
}

/* ── Main content area ── */
.layout-main {
  flex: 1; display: flex; flex-direction: column;
  min-width: 0; min-height: 0; overflow: hidden;
  background: #f8fafc;
}
body.dark .layout-main { background: #020617; }
.layout-main > [id^="tab-"] {
  padding: 12px;
}

@media (max-width: 1023px) {
  .layout-main > [id^="tab-"] { padding: 8px; }
}

/* ── Command palette (⌘K) ──────────────────────────────────────────
   Shell v2 (2026-09-02): rows, groups, highlight and the empty state
   are painted by /js/shell/palette.js. The shell carries mt-scope:
   backdrop + card surface come from dispatch.css (.mt-scope.modal-shell);
   everything inside is styled HERE off the overview-tokens scope.
   Row markup: .palette-head-row / .pres-row (.pres-icon .pres-body
   .pres-title .pres-sub .kbd-hint .pres-go). */
.palette {
  width: min(680px, 100%);
  max-height: 72vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 18px;
  font-family: var(--font-ui, var(--mb-font-sans));
  animation: palette-in 200ms var(--mb-ease-out);
}
@keyframes palette-in {
  from { opacity: 0; transform: translateY(-8px) scale(0.985); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
.palette-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-subtle, var(--mb-hairline));
}
.palette-lens { color: var(--accent-text, var(--mb-lime-text)); flex: none; }
.palette-head input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  color: var(--text-body);
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
}
.palette-head input::placeholder { color: var(--text-muted, var(--mb-muted)); font-weight: 500; }
.palette-esc, .palette-foot kbd, .kbd-hint {
  font-family: var(--mb-font-mono);
  font-size: 10.5px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 6px;
  border: 1px solid var(--border-subtle, var(--mb-line));
  color: var(--text-muted, var(--mb-muted));
  background: var(--surface-alt, var(--mb-alt));
  flex: none;
}
.palette-results {
  list-style: none;
  margin: 0;
  padding: 6px;
  overflow-y: auto;
  scrollbar-width: thin;
  min-height: 0;
}
.palette-head-row {
  padding: 10px 12px 4px;
  font-family: var(--mb-font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted, var(--mb-muted));
}
.pres-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 46px;
  padding: 7px 10px;
  border-radius: 11px;
  cursor: pointer;
  color: var(--text-body);
  transition: background var(--mb-dur-fast), transform var(--mb-dur-base) var(--mb-ease-out);
}
.pres-row.active {
  background: var(--accent-soft, var(--mb-lime-50));
  transform: translateX(2px);
}
html[dir="rtl"] .pres-row.active { transform: translateX(-2px); }
.pres-icon {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 9px;
  background: var(--surface-alt, var(--mb-row));
  color: var(--text-secondary, var(--mb-body));
  flex: none;
  transition: background var(--mb-dur-fast), color var(--mb-dur-fast);
}
.pres-row.active .pres-icon { background: var(--mb-ink); color: var(--mb-lime); }
.pres-k-page .pal-ic { stroke-width: 1.8; }
svg.pal-ic { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.pres-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.pres-title { font-size: 13.5px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pres-title mark { background: transparent; color: var(--accent-text, var(--mb-lime-text)); text-decoration: underline; text-decoration-color: var(--mb-lime); text-underline-offset: 2px; }
.pres-sub { font-size: 11.5px; color: var(--text-muted, var(--mb-muted)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pres-go { opacity: 0; color: var(--text-muted, var(--mb-muted)); transition: opacity var(--mb-dur-fast); }
.pres-go .pal-ic { width: 14px; height: 14px; }
.pres-row.active .pres-go { opacity: 1; }
.palette-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 34px 20px;
  text-align: center;
  color: var(--text-body);
}
.palette-empty.hidden { display: none !important; }
.palette-empty-ic { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; border-radius: 12px; background: var(--surface-alt, var(--mb-row)); color: var(--text-muted, var(--mb-muted)); margin-bottom: 6px; }
.palette-empty-t { font-size: 14px; font-weight: 700; }
.palette-empty-s { font-size: 12px; color: var(--text-muted, var(--mb-muted)); max-width: 380px; }
.palette-foot {
  display: flex;
  gap: 16px;
  padding: 9px 16px;
  border-top: 1px solid var(--border-subtle, var(--mb-hairline));
  font-size: 11px;
  color: var(--text-muted, var(--mb-muted));
}
.palette-foot span { display: flex; align-items: center; gap: 6px; }
.palette-foot-end { margin-inline-start: auto; }
@media (max-width: 640px) {
  #palette-shell { padding-top: 6vh !important; }
  .palette { max-height: 84vh; }
  .pres-sub { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .palette, .pres-row { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

@keyframes pulse-once {
  0%   { background-color: rgba(225, 29, 72, 0.18); }
  100% { background-color: transparent; }
}
.pulse-once { animation: pulse-once 0.8s ease-out 1; }

/* ── Focused task card — Alt+M opens Move menu. Outline keeps the
   focus ring visible inside the glass-backed kanban. */
.tk-card:focus-visible {
  outline: 2px solid #e11d48;
  outline-offset: 2px;
  border-radius: 12px;
}

/* ════════════════════════════════════════════════════════════════════
   Phase-9 Stage-F — Dark-first command-center splash
   ════════════════════════════════════════════════════════════════════
   The driver-v2 design language taught us: dark canvas + amplified
   mesh + glass chrome reads as a focused tool. Apply the same here
   so the admin actually looks like a Leitstand on first sight.
   ════════════════════════════════════════════════════════════════════ */

/* Amplified mesh on dark — fourth radial gradient (cyan) keeps the
   canvas from feeling empty in the corners. Bumped alphas across
   the board for visibility on a true graphite canvas. */
body.dark::before {
  background:
    radial-gradient(55% 45% at 12% 0%,
      rgba(244, 63, 94, 0.22),
      transparent 70%),
    radial-gradient(45% 40% at 100% 14%,
      rgba(167, 139, 250, 0.18),
      transparent 70%),
    radial-gradient(45% 40% at 28% 88%,
      rgba(45, 212, 191, 0.10),
      transparent 70%),
    radial-gradient(40% 35% at 80% 100%,
      rgba(251, 191, 36, 0.14),
      transparent 70%);
}

/* Deeper canvas in dark — was rgba in Phase-8; pin to a single
   solid so the mesh sits cleanly on top. */
body.dark {
  background: #0a0f1c !important;
}

/* (dark topbar glass retired with the topbar) */

/* (.sidebar-palette-cta retired — it never had markup) */

/* Subtle noise on dark canvas — makes the giant flat colour feel
   alive without competing with the content. 64×64 procedural
   data-URL so no extra HTTP request. */
body.dark::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.025;
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='64' height='64' viewBox='0 0 64 64'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.6 0'/></filter><rect width='64' height='64' filter='url(%23n)'/></svg>");
  background-size: 64px 64px;
}
@media (prefers-reduced-transparency: reduce) {
  body.dark::after { display: none; }
}

/* ════════════════════════════════════════════════════════════════════
   Phase-9 Stage-G — Per-tab visual polish (driver-v2 language)
   ════════════════════════════════════════════════════════════════════
   Markup unchanged. New CSS lifts the dark theme to match the
   driver-v2 design: brand-tinted FAB icons on KPI tiles, hairline
   glass on panels, brand-rose hover on tables, tabular-nums on
   numbers, soft warmth on the otherwise-neutral graphite. */

/* KPI tiles on the dashboard — convert the existing 4 Tailwind
   cards into the driver-v2 chip aesthetic. The cards keep their
   Tailwind classes; we override the look with structural rules. */
body.dark #ov-kpi-done,
body.dark #ov-kpi-income,
body.dark #ov-kpi-drivers,
body.dark #ov-kpi-open {
  font-variant-numeric: tabular-nums;
}

/* The four overview KPI cards each have a unique container in HTML.
   Hit them by the rounded-2xl + KPI id structure so we don't have
   to touch markup. */
body.dark .panel {
  background: rgba(15, 23, 42, 0.55) !important;
  border-color: rgba(255, 255, 255, 0.08) !important;
  box-shadow:
    0 1px 3px rgba(0, 0, 0, 0.3),
    0 8px 24px rgba(0, 0, 0, 0.22),
    inset 0 1px 0 rgba(255, 255, 255, 0.06) !important;
}

body.dark .pay-paid {
  background: rgba(16, 185, 129, 0.16) !important;
  color: #6ee7b7 !important;
  border-color: rgba(16, 185, 129, 0.30) !important;
}
body.dark .pay-privat {
  background: rgba(245, 158, 11, 0.16) !important;
  color: #fcd34d !important;
  border-color: rgba(245, 158, 11, 0.30) !important;
}
body.dark .pay-befreit {
  background: rgba(59, 130, 246, 0.16) !important;
  color: #93c5fd !important;
  border-color: rgba(59, 130, 246, 0.30) !important;
}
body.dark .pay-nicht {
  background: rgba(239, 68, 68, 0.16) !important;
  color: #fca5a5 !important;
  border-color: rgba(239, 68, 68, 0.30) !important;
}

/* Dispatch board — driver card row gets the brand-tinted left edge
   so the colour cascades through the page hierarchy. */
body.dark .dr-row {
  background: linear-gradient(135deg, rgba(15, 23, 42, 0.72), rgba(15, 23, 42, 0.55)) !important;
  border-color: rgba(255, 255, 255, 0.08) !important;
  border-inline-start: 3px solid rgba(225, 29, 72, 0.55) !important;
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.3),
    0 8px 24px rgba(0, 0, 0, 0.18),
    inset 0 1px 0 rgba(255, 255, 255, 0.04) !important;
}
body.dark .dr-row:hover {
  border-inline-start-color: #fb7185 !important;
}

/* Task / dispatch cards — soft glass on dark, brand-rose hover. */
body.dark .tk-card {
  background: rgba(255, 255, 255, 0.03) !important;
  border-color: rgba(255, 255, 255, 0.08) !important;
}
body.dark .tk-card:hover {
  background: rgba(255, 255, 255, 0.06) !important;
  border-color: rgba(225, 29, 72, 0.25) !important;
}
body.dark .tk-card .text-brand {
  color: #fb7185 !important;
}

/* Personal cards / vehicle cards / doc cards — clean dark chrome. */

/* Database sub-nav buttons get a brand-rose active state. */

/* Section titles + count badges — small icon chip + heading. */
body.dark .section-title,
body.dark h2 {
  color: #ffffff;
}

/* Toast on dark — glass treatment matches the driver-v2 toast. */
body.dark #toast-container {
  background: rgba(15, 23, 42, 0.78) !important;
  color: #ffffff !important;
  border-color: rgba(255, 255, 255, 0.12) !important;
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  backdrop-filter:         blur(18px) saturate(150%);
  box-shadow:
    0 10px 32px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.10) !important;
}

/* Input fields on dark — neutral graphite, brand-rose focus ring. */
body.dark input[type="text"],
body.dark input[type="email"],
body.dark input[type="password"],
body.dark input[type="number"],
body.dark input[type="date"],
body.dark input[type="time"],
body.dark input[type="tel"],
body.dark input[type="search"],
body.dark textarea,
body.dark select {
  background: rgba(255, 255, 255, 0.05) !important;
  border-color: rgba(255, 255, 255, 0.10) !important;
  color: #ffffff !important;
}
body.dark input:focus,
body.dark textarea:focus,
body.dark select:focus {
  border-color: #fb7185 !important;
  box-shadow: 0 0 0 3px rgba(225, 29, 72, 0.18) !important;
  outline: none;
}

/* Buttons — brand-rose primary + secondary glass. */
body.dark .btn-secondary,
body.dark .btn-primary {
  font-weight: 800;
}
body.dark button.bg-emerald-500:hover { background-color: #047857 !important; }
body.dark button.bg-rose-500:hover { background-color: #be123c !important; }

/* Tabular nums on every number-bearing surface. */
body.dark #ov-kpi-done,
body.dark #ov-kpi-income,
body.dark #ov-kpi-drivers,
body.dark #ov-kpi-open,
body.dark #live-clock,
body.dark #total-drivers,
body.dark #live-count,
body.dark .pay-badge {
  font-variant-numeric: tabular-nums;
}

/* Activity feed row — pulse-once already handled by Phase-8;
   here we just tune the dark look so freshly arrived entries
   read clearly. */
body.dark #ov-feed > div {
  background: transparent !important;
}
body.dark #ov-feed > div:hover {
  background: rgba(255, 255, 255, 0.04) !important;
}
body.dark .pulse-once {
  animation: pulse-once-dark 0.8s ease-out 1;
}
@keyframes pulse-once-dark {
  0%   { background-color: rgba(244, 63, 94, 0.30); }
  100% { background-color: transparent; }
}


/* Keyboard shortcut hint chips inside the palette + tooltips. */
.kbd-hint {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: ui-monospace, monospace;
  font-size: 10px;
  font-weight: 800;
  padding: 2px 6px;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.15);
  color: rgba(255, 255, 255, 0.85);
}
body:not(.dark) .kbd-hint {
  background: rgba(2, 6, 23, 0.06);
  border-color: rgba(2, 6, 23, 0.12);
  color: var(--text);
}

/* KPI skeleton — show a shimmering placeholder for the four
   dashboard tiles until the first /api/status response lands so
   the user sees motion instead of "—". */
.kpi-skeleton {
  display: inline-block;
  min-width: 48px;
  height: 1em;
  background:
    linear-gradient(90deg,
      rgba(255, 255, 255, 0.05) 25%,
      rgba(255, 255, 255, 0.12) 50%,
      rgba(255, 255, 255, 0.05) 75%);
  background-size: 200% 100%;
  border-radius: 6px;
  animation: kpi-skel-shimmer 1.4s ease-in-out infinite;
  vertical-align: middle;
}
@keyframes kpi-skel-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* Custom scrollbars on dark — WebKit gets a thinner brand-tinted
   scrollbar matching the canvas. Firefox gets the modern scrollbar
   width/color API. Light theme keeps the OS default so it doesn't
   feel unusual. */
body.dark {
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.20) transparent;
}
body.dark *::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
body.dark *::-webkit-scrollbar-track {
  background: transparent;
}
body.dark *::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
body.dark *::-webkit-scrollbar-thumb:hover {
  background: rgba(225, 29, 72, 0.45);
  background-clip: padding-box;
}

/* Print stylesheet — when ops print an accounting / history /
   timesheet page, strip the chrome (sidebar, palette, ⌘K chip,
   bottom nav etc.) and force a black-on-white surface. */
@media print {
  /* Hide everything that's interactive UI. */
  .sidebar,
  .topbar-mobile,
  .bottom-nav,
  #toast-container,
  #palette-shell,
  .sidebar-palette-cta,
  .modal-shell,
  .drawer-overlay {
    display: none !important;
  }
  body {
    background: #fff !important;
    color: #0f172a !important;
  }
  body::before,
  body::after { display: none !important; }
  .panel,
  .glass,
  .glass-card,
  table,
  th, td {
    background: #fff !important;
    color: #0f172a !important;
    border-color: #cbd5e1 !important;
    box-shadow: none !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  /* Avoid splitting a single row across two pages where possible. */
  tr { page-break-inside: avoid; }
  a[href]::after { content: ""; } /* don't print URL after every link */
}

/* ════════════════════════════════════════════════════════════════════
   Phase-9 polish — Settings modal (4-tab modal at index.html:2432)
   ════════════════════════════════════════════════════════════════════
   The modal already has 4-tab structure (company / security / admins
   / system) and a JS handler at app.js:5806. This block adds the
   dark glass treatment + brand-rose active state + better section
   hierarchy. Markup stays the same. */

/* Modal shell — glass treatment on dark. */
body.dark #settings-modal > div {
  background: rgba(15, 23, 42, 0.85) !important;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow:
    0 1px 3px rgba(0, 0, 0, 0.35),
    0 30px 90px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(225, 29, 72, 0.10),
    inset 0 1px 0 rgba(255, 255, 255, 0.08) !important;
  -webkit-backdrop-filter: blur(22px) saturate(150%);
  backdrop-filter:         blur(22px) saturate(150%);
}
body.dark #settings-modal > div > div:first-child {
  background: rgba(15, 23, 42, 0.55) !important;
  border-bottom-color: rgba(255, 255, 255, 0.08) !important;
}
body.dark #settings-modal h2,
body.dark #settings-modal h2 span {
  color: #ffffff !important;
}

/* Left sidebar (tab nav) — glass treatment + brand accents. */
body.dark #settings-modal .flex.flex-col.md\:flex-row > div:first-child {
  background: rgba(15, 23, 42, 0.40) !important;
  border-color: rgba(255, 255, 255, 0.06) !important;
}

/* Settings tab buttons — driver-v2 ghost / brand-rose active. */
body.dark .settings-tab-btn {
  color: rgba(255, 255, 255, 0.62) !important;
  background: transparent !important;
  border-color: rgba(255, 255, 255, 0.06) !important;
}
body.dark .settings-tab-btn:hover {
  background: rgba(255, 255, 255, 0.04) !important;
  color: #ffffff !important;
}
body.dark .settings-tab-btn i {
  color: rgba(255, 255, 255, 0.50) !important;
}
body.dark .settings-tab-btn:hover i {
  color: #fb7185 !important;
}
body.dark .settings-tab-btn.active,
body.dark .settings-tab-btn.active:hover {
  background: linear-gradient(135deg, #fb7185, #be123c) !important;
  color: #ffffff !important;
  border-color: rgba(225, 29, 72, 0.40) !important;
  box-shadow:
    0 8px 22px rgba(225, 29, 72, 0.40),
    inset 0 1px 0 rgba(255, 255, 255, 0.15) !important;
}
body.dark .settings-tab-btn.active i,
body.dark .settings-tab-btn.active:hover i {
  color: #ffffff !important;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.30));
}

/* Right content area — matte panel on dark glass. */
body.dark #settings-modal .flex.flex-col.md\:flex-row > div:last-child {
  background: rgba(15, 23, 42, 0.30) !important;
}

/* Section headings inside settings tabs — get a small icon-chip
   feel (left border accent + hairline divider). */
body.dark .settings-tab-content h3 {
  color: #ffffff !important;
  border-bottom-color: rgba(255, 255, 255, 0.08) !important;
  position: relative;
  padding-inline-start: 12px !important;
}
body.dark .settings-tab-content h3::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 4px;
  bottom: 12px;
  width: 3px;
  background: linear-gradient(180deg, #fb7185, #be123c);
  border-radius: 999px;
}

/* Info banners inside settings (indigo / success / etc.) — dark
   equivalents so they read as semantic chips. */
body.dark #settings-modal .bg-indigo-50 {
  background: rgba(99, 102, 241, 0.12) !important;
  border-color: rgba(99, 102, 241, 0.30) !important;
}
body.dark #settings-modal .text-indigo-700 {
  color: #a5b4fc !important;
}

/* Danger zone in System tab — make it visually distinct so a
   trigger-happy admin can't miss it. */
body.dark #settings-modal #danger-zone {
  background: rgba(239, 68, 68, 0.06) !important;
}
body.dark #settings-modal h3[data-i18n="set_danger_title"],
body.dark #settings-modal h3 span[data-i18n="set_danger_title"] {
  color: #fca5a5 !important;
}
body.dark #settings-modal h3[data-i18n="set_danger_title"]::before,
body.dark #settings-modal h3:has(span[data-i18n="set_danger_title"])::before {
  background: linear-gradient(180deg, #ef4444, #b91c1c) !important;
}

/* Inputs / textarea inside settings inherit the global dark form
   field treatment from Stage G. Just tighten a few specific cases. */
body.dark #settings-modal label {
  color: rgba(255, 255, 255, 0.75) !important;
}
body.dark #settings-modal p {
  color: rgba(255, 255, 255, 0.62) !important;
}

/* Footer save button row — brand-rose primary stays the same. */
body.dark #settings-modal .bg-emerald-500 {
  background-color: #059669 !important;
}
body.dark #settings-modal .bg-emerald-500:hover {
  background-color: #047857 !important;
}

/* Admin / staff list rows inside settings tab — rgba-04 ghost. */
body.dark #settings-modal .bg-slate-100,
body.dark #settings-modal .bg-slate-50 {
  background: rgba(255, 255, 255, 0.04) !important;
  border-color: rgba(255, 255, 255, 0.08) !important;
}


/* ════════════════════════════════════════════════════════════════════
   TASK EDIT-HISTORY MODAL (.teh-*)
   Triggered by the amber clock-rotate pill on a board card. Shows
   every recorded edit with the fields that changed and the editor.
   ════════════════════════════════════════════════════════════════════ */
.teh-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.55);
  backdrop-filter: blur(8px);
  z-index: 100200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  animation: tehFadeIn 0.18s ease-out;
}
@keyframes tehFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
.teh-modal {
  width: 100%;
  max-width: 520px;
  max-height: 80vh;
  background: #ffffff;
  border-radius: 22px;
  box-shadow:
    0 24px 60px rgba(15, 23, 42, 0.25),
    0 6px 16px rgba(15, 23, 42, 0.10);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: tehPop 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
@keyframes tehPop {
  from { opacity: 0; transform: translateY(12px) scale(0.97); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
body.dark .teh-modal {
  background: rgb(15, 23, 42);
  box-shadow:
    0 24px 60px rgba(0, 0, 0, 0.55),
    0 6px 16px rgba(0, 0, 0, 0.30);
}
.teh-modal-head {
  padding: 18px 22px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid rgba(226, 232, 240, 0.7);
  gap: 12px;
}
body.dark .teh-modal-head { border-bottom-color: rgba(51, 65, 85, 0.5); }
.teh-title {
  font-size: 15px;
  font-weight: 900;
  color: rgb(15, 23, 42);
  letter-spacing: -0.015em;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
body.dark .teh-title { color: #ffffff; }
.teh-sub {
  font-size: 11.5px;
  font-weight: 700;
  color: rgb(100, 116, 139);
  margin-top: 4px;
}
.teh-close {
  width: 32px;
  height: 32px;
  border-radius: 10px;
  border: none;
  background: rgba(148, 163, 184, 0.12);
  color: rgb(100, 116, 139);
  font-size: 14px;
  cursor: pointer;
  transition: all 0.12s ease;
}
.teh-close:hover {
  background: rgba(225, 29, 72, 0.15);
  color: rgb(225, 29, 72);
}
.teh-body {
  padding: 14px 22px 22px 22px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.teh-entry {
  background: rgba(248, 250, 252, 0.7);
  border: 1px solid rgba(226, 232, 240, 0.7);
  border-radius: 14px;
  padding: 14px;
}
body.dark .teh-entry {
  background: rgba(30, 41, 59, 0.4);
  border-color: rgba(51, 65, 85, 0.5);
}
.teh-entry-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
  font-size: 11.5px;
  font-weight: 800;
}
.teh-when {
  color: rgb(15, 23, 42);
  letter-spacing: -0.005em;
}
body.dark .teh-when { color: #ffffff; }
.teh-by {
  color: rgb(100, 116, 139);
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.teh-changes {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.teh-change {
  display: grid;
  grid-template-columns: minmax(80px, 90px) 1fr;
  gap: 10px;
  align-items: start;
}
.teh-field {
  font-size: 10.5px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: rgb(100, 116, 139);
  padding-top: 4px;
}
.teh-diff {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  font-weight: 700;
}
.teh-from {
  background: rgba(225, 29, 72, 0.08);
  color: rgb(190, 18, 60);
  padding: 4px 10px;
  border-radius: 8px;
  text-decoration: line-through;
  text-decoration-color: rgba(190, 18, 60, 0.5);
  max-width: 100%;
  word-break: break-word;
}
.teh-to {
  background: rgba(16, 185, 129, 0.10);
  color: rgb(5, 150, 105);
  padding: 4px 10px;
  border-radius: 8px;
  max-width: 100%;
  word-break: break-word;
}
.teh-arrow {
  font-size: 10px;
  color: rgb(148, 163, 184);
}
html[dir="rtl"] .teh-arrow { transform: rotate(180deg); }
.teh-modal-foot {
  padding: 14px 22px;
  border-top: 1px solid rgba(226, 232, 240, 0.7);
  background: rgba(248, 250, 252, 0.5);
  font-size: 12px;
  font-weight: 800;
}
body.dark .teh-modal-foot {
  border-top-color: rgba(51, 65, 85, 0.5);
  background: rgba(15, 23, 42, 0.5);
}
.teh-foot-flag {
  color: rgb(180, 83, 9);
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
body.dark .teh-foot-flag { color: rgb(252, 211, 77); }
.teh-foot-ok {
  color: rgb(5, 150, 105);
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
body.dark .teh-foot-ok { color: rgb(52, 211, 153); }

/* ════════════════════════════════════════════════════════════════════
   MT-TOGGLE — RTL-aware pill switch
   The Tailwind peer-checked pattern used translate-x which is fixed
   LTR — the handle slid the wrong way on the RTL admin panel. This
   custom toggle uses logical inset-inline-start/end so the handle
   always slides toward the "on" edge of the pill regardless of dir.
   ════════════════════════════════════════════════════════════════════ */
.mt-toggle {
  position: relative;
  display: inline-block;
  width: 52px;
  height: 30px;
  flex-shrink: 0;
  cursor: pointer;
}
.mt-toggle input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.mt-toggle-slider {
  position: absolute;
  inset: 0;
  background: rgb(203, 213, 225);
  border-radius: 999px;
  transition: background-color 0.22s cubic-bezier(0.32, 0.72, 0, 1);
  box-shadow: inset 0 1px 2px rgba(15, 23, 42, 0.10);
}
body.dark .mt-toggle-slider {
  background: rgb(51, 65, 85);
}
.mt-toggle-slider::after {
  content: "";
  position: absolute;
  top: 3px;
  inset-inline-start: 3px;
  width: 24px;
  height: 24px;
  background: #ffffff;
  border-radius: 50%;
  box-shadow:
    0 2px 6px rgba(15, 23, 42, 0.16),
    0 1px 2px rgba(15, 23, 42, 0.10);
  transition:
    inset-inline-start 0.22s cubic-bezier(0.32, 0.72, 0, 1),
    transform 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
.mt-toggle input:checked + .mt-toggle-slider {
  background: linear-gradient(135deg, rgb(16, 185, 129), rgb(5, 150, 105));
  box-shadow:
    inset 0 1px 2px rgba(5, 150, 105, 0.25),
    0 0 0 1px rgba(5, 150, 105, 0.15);
}
.mt-toggle input:checked + .mt-toggle-slider::after {
  inset-inline-start: 25px;
}
.mt-toggle input:focus-visible + .mt-toggle-slider {
  outline: 2px solid rgb(225, 29, 72);
  outline-offset: 2px;
}
.mt-toggle:hover .mt-toggle-slider::after {
  transform: scale(1.06);
}
.mt-toggle:active .mt-toggle-slider::after {
  transform: scale(0.94);
}

/* ════════════ Dispatch sub-tabs (Live / Tagesplan) ════════════ */
.dst-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: rgb(241, 245, 249);
  color: rgb(71, 85, 105);
  padding: 8px 14px;
  border-radius: 14px;
  font-weight: 900;
  font-size: 12px;
  border: 1px solid rgb(226, 232, 240);
  transition: background 0.15s, color 0.15s, transform 0.05s;
}
.dst-btn:hover { background: rgb(226, 232, 240); }
.dst-btn:active { transform: scale(0.97); }
.dst-btn-on {
  background: linear-gradient(135deg, rgb(225, 29, 72), rgb(190, 18, 60));
  color: #fff;
  border-color: transparent;
  box-shadow: 0 4px 14px -3px rgba(225, 29, 72, 0.45);
}
.dst-btn-on:hover { background: linear-gradient(135deg, rgb(225, 29, 72), rgb(190, 18, 60)); }
body.dark .dst-btn { background: rgb(51, 65, 85); color: rgb(203, 213, 225); border-color: rgb(71, 85, 105); }
body.dark .dst-btn:hover { background: rgb(71, 85, 105); }

/* ════════════ Tagesplan grid ════════════ */
/* CSS grid: time column + N driver columns. RTL outer flow is fine
 * because the grid itself uses `dir="ltr"` on its container, so the
 * time column visually sits on the LEFT of the grid for both locales;
 * the user's spec asks for it on the right in RTL, which is the
 * default browser behaviour when we keep grid-template-columns as
 * time-first and the grid stays LTR — RTL chrome (toolbar, day strip)
 * keeps its own RTL flow at the wrapper level. */
.tp-grid {
  display: grid;
  grid-auto-rows: minmax(64px, auto);
  min-width: 100%;
  width: max-content;
  font-size: 12px;
  color: rgb(30, 41, 59);
}
body.dark .tp-grid { color: rgb(226, 232, 240); }

/* Sticky header row */
.tp-corner,
.tp-col-head {
  position: sticky;
  top: 0;
  z-index: 3;
  background: rgb(248, 250, 252);
  border-bottom: 2px solid rgb(226, 232, 240);
}
body.dark .tp-corner,
body.dark .tp-col-head { background: rgb(15, 23, 42); border-bottom-color: rgb(51, 65, 85); }
.tp-corner { border-right: 1px solid rgb(226, 232, 240); }
body.dark .tp-corner { border-right-color: rgb(51, 65, 85); }

.tp-col-head {
  padding: 10px 12px;
  border-right: 1px solid rgb(226, 232, 240);
  min-height: 64px;
}
body.dark .tp-col-head { border-right-color: rgb(51, 65, 85); }
.tp-col-head-top { display: flex; align-items: center; gap: 8px; }
.tp-avatar {
  width: 36px;
  height: 36px;
  border-radius: 12px;
  background: linear-gradient(135deg, rgb(225, 29, 72), rgb(190, 18, 60));
  color: #fff;
  flex-shrink: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 900;
}
.tp-avatar img { width: 100%; height: 100%; object-fit: cover; }
.tp-avatar-fallback { font-size: 16px; }
.tp-col-head-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.tp-col-name { font-size: 13px; font-weight: 900; color: rgb(15, 23, 42); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
body.dark .tp-col-name { color: rgb(241, 245, 249); }
.tp-col-veh {
  font-size: 10px;
  font-weight: 700;
  color: rgb(100, 116, 139);
  background: rgb(241, 245, 249);
  padding: 2px 8px;
  border-radius: 6px;
  width: fit-content;
  cursor: pointer;
  transition: background 0.12s;
}
.tp-col-veh:hover { background: rgb(254, 226, 226); color: rgb(190, 18, 60); }
body.dark .tp-col-veh { background: rgb(51, 65, 85); color: rgb(148, 163, 184); }
body.dark .tp-col-veh:hover { background: rgb(127, 29, 29); color: rgb(252, 165, 165); }

/* Sticky time column (still LTR, so this is the *first* grid column —
 * which renders on the LEFT. For RTL operator preference we'd flip
 * grid-template-columns later; Stage A keeps LTR-only for the grid
 * body to match the German content. */
.tp-time {
  position: sticky;
  left: 0;
  z-index: 2;
  background: rgb(248, 250, 252);
  color: rgb(100, 116, 139);
  font-weight: 800;
  text-align: center;
  padding: 6px 4px;
  border-right: 1px solid rgb(226, 232, 240);
  border-bottom: 1px solid rgb(241, 245, 249);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  font-size: 11px;
}
.tp-time-hour {
  color: rgb(15, 23, 42);
  background: rgb(241, 245, 249);
  font-weight: 900;
  font-size: 12px;
}
body.dark .tp-time { background: rgb(15, 23, 42); color: rgb(148, 163, 184); border-right-color: rgb(51, 65, 85); border-bottom-color: rgb(30, 41, 59); }
body.dark .tp-time-hour { color: rgb(241, 245, 249); background: rgb(30, 41, 59); }

/* Empty + task cells */
.tp-cell {
  border-right: 1px solid rgb(241, 245, 249);
  border-bottom: 1px solid rgb(241, 245, 249);
  padding: 4px;
  cursor: pointer;
  transition: background 0.12s;
  min-height: 64px;
}
.tp-cell:hover { background: rgb(254, 242, 242); }
body.dark .tp-cell { border-right-color: rgb(30, 41, 59); border-bottom-color: rgb(30, 41, 59); }
body.dark .tp-cell:hover { background: rgba(127, 29, 29, 0.18); }
.tp-cell-empty { background: transparent; }
.tp-cell-empty:hover { background: rgb(254, 242, 242); }

.tp-task {
  background: #fff;
  border: 1.5px solid rgb(226, 232, 240);
  border-radius: 10px;
  padding: 7px 9px;
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto;
  line-height: 1.35;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  transition: border-color 0.12s, box-shadow 0.12s, transform 0.05s;
  white-space: pre-wrap;
  word-break: break-word;
  cursor: pointer;
}
.tp-task + .tp-task { margin-top: 5px; }
.tp-task:hover {
  border-color: rgb(225, 29, 72);
  box-shadow: 0 4px 14px -4px rgba(225, 29, 72, 0.35);
}
.tp-task:active { transform: scale(0.99); }
body.dark .tp-task { background: rgb(30, 41, 59); border-color: rgb(51, 65, 85); }
body.dark .tp-task:hover { border-color: rgb(244, 63, 94); }

.tp-line-head {
  font-size: 9px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: rgb(100, 116, 139);
  margin-bottom: 1px;
}
.tp-line { font-size: 11px; color: rgb(30, 41, 59); }
body.dark .tp-line { color: rgb(226, 232, 240); }
.tp-line-time {
  font-size: 12px;
  font-weight: 900;
  color: rgb(225, 29, 72);
  font-variant-numeric: tabular-nums;
}
.tp-line-note {
  font-size: 10px;
  color: rgb(180, 83, 9);
  background: rgb(254, 243, 199);
  padding: 2px 5px;
  border-radius: 4px;
  margin-top: 3px;
  display: block;
}
body.dark .tp-line-note { color: rgb(252, 211, 77); background: rgba(120, 53, 15, 0.35); }

/* Vehicle picker card buttons */
.tp-veh-pick {
  background: rgb(248, 250, 252);
  border: 1.5px solid rgb(226, 232, 240);
  border-radius: 12px;
  padding: 10px 12px;
  text-align: start;
  font-weight: 800;
  color: rgb(30, 41, 59);
  transition: background 0.12s, border-color 0.12s, transform 0.05s;
}
.tp-veh-pick:hover { background: rgb(254, 242, 242); border-color: rgb(225, 29, 72); }
.tp-veh-pick:active { transform: scale(0.98); }
.tp-veh-pick-on {
  background: linear-gradient(135deg, rgb(225, 29, 72), rgb(190, 18, 60));
  color: #fff;
  border-color: transparent;
  box-shadow: 0 4px 14px -3px rgba(225, 29, 72, 0.45);
}
.tp-veh-pick-on:hover {
  background: linear-gradient(135deg, rgb(225, 29, 72), rgb(190, 18, 60));
  border-color: transparent;
}
body.dark .tp-veh-pick { background: rgb(30, 41, 59); border-color: rgb(51, 65, 85); color: rgb(226, 232, 240); }
body.dark .tp-veh-pick:hover { background: rgba(127, 29, 29, 0.25); border-color: rgb(244, 63, 94); }

/* Column reorder arrows in the Tagesplan header */
.tp-col-head-top { position: relative; }
.tp-col-arrows {
  position: absolute;
  top: -2px;
  inset-inline-end: -2px;
  display: flex;
  gap: 2px;
}
.tp-arrow {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  background: rgb(241, 245, 249);
  color: rgb(100, 116, 139);
  font-size: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgb(226, 232, 240);
  transition: background 0.12s, color 0.12s, transform 0.05s;
}
.tp-arrow:hover {
  background: linear-gradient(135deg, rgb(225, 29, 72), rgb(190, 18, 60));
  color: #fff;
  border-color: transparent;
}
.tp-arrow:active { transform: scale(0.94); }
.tp-arrow-off {
  opacity: 0.3;
  cursor: not-allowed;
  pointer-events: none;
}
body.dark .tp-arrow { background: rgb(51, 65, 85); color: rgb(148, 163, 184); border-color: rgb(71, 85, 105); }
body.dark .tp-arrow:hover { background: linear-gradient(135deg, rgb(225, 29, 72), rgb(190, 18, 60)); color: #fff; }

/* Drag-and-drop visuals (Stage D) */
.tp-task[draggable="true"] { cursor: grab; }
.tp-task[draggable="true"]:active { cursor: grabbing; }
.tp-task-dragging { opacity: 0.5; }
.tp-cell-drop {
  background: rgb(254, 226, 226) !important;
  outline: 2px dashed rgb(225, 29, 72);
  outline-offset: -3px;
}
body.dark .tp-cell-drop {
  background: rgba(127, 29, 29, 0.35) !important;
  outline-color: rgb(244, 63, 94);
}

/* Column "send to driver" button + green ribbon when all sent */
.tp-col-send {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 8px;
  background: linear-gradient(135deg, rgb(79, 70, 229), rgb(67, 56, 202));
  color: #fff;
  padding: 6px 10px;
  border-radius: 10px;
  font-size: 10px;
  font-weight: 900;
  width: 100%;
  justify-content: center;
  box-shadow: 0 2px 8px -2px rgba(79, 70, 229, 0.45);
  transition: background 0.12s, transform 0.05s, opacity 0.12s;
}
.tp-col-send:hover { background: linear-gradient(135deg, rgb(67, 56, 202), rgb(55, 48, 163)); }
.tp-col-send:active { transform: scale(0.98); }
.tp-col-send:disabled { opacity: 0.6; pointer-events: none; }
.tp-col-head-sent {
  background: linear-gradient(180deg, rgba(16, 185, 129, 0.18) 0%, rgba(16, 185, 129, 0.05) 100%) !important;
  border-bottom: 2px solid rgb(16, 185, 129) !important;
}
body.dark .tp-col-head-sent {
  background: linear-gradient(180deg, rgba(16, 185, 129, 0.22) 0%, rgba(16, 185, 129, 0.05) 100%) !important;
}
.tp-col-sent-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 8px;
  background: rgb(220, 252, 231);
  color: rgb(21, 128, 61);
  padding: 6px 10px;
  border-radius: 10px;
  font-size: 10px;
  font-weight: 900;
  width: 100%;
  justify-content: center;
}
body.dark .tp-col-sent-badge {
  background: rgba(6, 95, 70, 0.45);
  color: rgb(110, 231, 183);
}

/* Per-task edit / delete icons */
.tp-task { position: relative; }
.tp-task-actions {
  position: absolute;
  top: 4px;
  inset-inline-end: 4px;
  display: flex;
  gap: 2px;
  opacity: 0;
  transition: opacity 0.12s;
}
.tp-task:hover .tp-task-actions { opacity: 1; }
.tp-task-act {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.92);
  color: rgb(100, 116, 139);
  font-size: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgb(226, 232, 240);
  transition: background 0.12s, color 0.12s;
}
.tp-task-act:hover { background: rgb(225, 29, 72); color: #fff; border-color: transparent; }
.tp-task-act-del:hover { background: rgb(220, 38, 38); }
body.dark .tp-task-act { background: rgba(30, 41, 59, 0.92); color: rgb(148, 163, 184); border-color: rgb(51, 65, 85); }
.tp-task-sent {
  position: absolute;
  top: 4px;
  inset-inline-start: 4px;
  background: rgb(16, 185, 129);
  color: #fff;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  box-shadow: 0 2px 4px rgba(16, 185, 129, 0.35);
}

/* Unassigned-tasks tray (above the grid) */
.tp-unass {
  background: #fff;
  border: 1.5px solid rgb(252, 211, 77);
  border-radius: 12px;
  padding: 8px 10px;
  min-width: 220px;
  max-width: 280px;
  font-size: 11px;
  cursor: grab;
  transition: border-color 0.12s, box-shadow 0.12s;
  position: relative;
}
.tp-unass:hover {
  border-color: rgb(217, 119, 6);
  box-shadow: 0 4px 12px -4px rgba(217, 119, 6, 0.4);
}
.tp-unass:active { cursor: grabbing; }
body.dark .tp-unass { background: rgb(30, 41, 59); border-color: rgb(180, 83, 9); }
body.dark .tp-unass:hover { border-color: rgb(252, 211, 77); }
.tp-unass-head {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 3px;
}
.tp-unass-time {
  font-variant-numeric: tabular-nums;
  font-weight: 900;
  color: rgb(180, 83, 9);
  flex: 1;
}
body.dark .tp-unass-time { color: rgb(252, 211, 77); }
.tp-unass-act {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: rgb(254, 243, 199);
  color: rgb(180, 83, 9);
  font-size: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgb(252, 211, 77);
}
.tp-unass-act:hover {
  background: rgb(217, 119, 6);
  color: #fff;
  border-color: transparent;
}
.tp-unass-del:hover { background: rgb(220, 38, 38); }
body.dark .tp-unass-act { background: rgba(180, 83, 9, 0.25); color: rgb(252, 211, 77); border-color: rgb(180, 83, 9); }
.tp-unass-name { font-weight: 900; color: rgb(30, 41, 59); }
body.dark .tp-unass-name { color: rgb(241, 245, 249); }
.tp-unass-route, .tp-unass-art {
  color: rgb(100, 116, 139);
  font-size: 10px;
  margin-top: 2px;
}
body.dark .tp-unass-route, body.dark .tp-unass-art { color: rgb(148, 163, 184); }

/* ════════════ Tagesplan print stylesheet (Stage H) ════════════ */
@media print {
  body.tp-printing #sidebar,
  body.tp-printing #dispatch-stats,
  body.tp-printing #dispatch-subtabs,
  body.tp-printing #planner-controls,
  body.tp-printing #dispatch-mode-live,
  body.tp-printing #tp-toolbar,
  body.tp-printing #tp-day-strip,
  body.tp-printing #tp-empty,
  body.tp-printing .tp-col-arrows {
    display: none !important;
  }
  body.tp-printing .tp-cell-empty { background: transparent !important; }
  body.tp-printing {
    background: #fff !important;
    color: #000 !important;
  }
  body.tp-printing #tp-grid {
    color: #000 !important;
    font-size: 9pt;
    width: 100% !important;
  }
  body.tp-printing .tp-task {
    page-break-inside: avoid;
    border: 1pt solid #000 !important;
    background: #fff !important;
    box-shadow: none !important;
    color: #000 !important;
  }
  body.tp-printing .tp-cell {
    border-right: 0.5pt solid #999 !important;
    border-bottom: 0.5pt solid #999 !important;
  }
  body.tp-printing .tp-time,
  body.tp-printing .tp-col-head,
  body.tp-printing .tp-corner {
    background: #f3f4f6 !important;
    color: #000 !important;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  body.tp-printing .tp-line-time { color: #000 !important; }
  body.tp-printing .tp-line-note {
    background: #fef9c3 !important;
    color: #000 !important;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  @page { size: A4 landscape; margin: 10mm; }
}

/* Lightbox stage (admin photo viewer). The stage element wraps the
   <img> and receives the zoom/rotate transform; the image itself is
   unscaled so transform-origin stays predictable. touch-action: none
   stops the browser from intercepting pinch gestures as page-zoom. */
.lightbox-stage {
  touch-action: none;
  transition: transform 0.06s linear;
  transform-origin: center center;
  will-change: transform;
}
.lightbox-stage img {
  -webkit-user-drag: none;
  user-select: none;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  #staff-modal .staff-panel { animation: none; }
}


/* ═══════════════════════════════════════════════════════════════════
   The board's seven-day strip.
   Replaces the "Heute / Morgen" pair, which could only ever reach two
   days. Sits inside the existing #date-strip and borrows its card, so
   nothing else about the board's look changes.
   ═══════════════════════════════════════════════════════════════════ */
.ds7-days {
  display: flex; gap: 4px; flex: 1; min-width: 0;
  overflow-x: auto; scrollbar-width: none;
  scroll-snap-type: x proximity;
}
.ds7-days::-webkit-scrollbar { display: none; }

.ds7-day {
  flex: 1 0 auto; min-width: 66px; scroll-snap-align: start;
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 6px 10px 5px;
  border: 1px solid transparent; border-radius: 12px;
  background: transparent; color: #64748b;
  cursor: pointer; line-height: 1.25;
  transition: background 0.15s ease, color 0.15s ease, transform 0.12s ease;
  -webkit-tap-highlight-color: transparent;
}
.ds7-day:hover {
  background: rgba(225, 29, 72, 0.08); color: #0f172a;
  transform: translateY(-1px);
}
.ds7-day:focus-visible { outline: 2px solid #e11d48; outline-offset: 1px; }
.ds7-day.is-on {
  background: #e11d48; color: #fff; border-color: #e11d48;
  box-shadow: 0 3px 10px rgba(225, 29, 72, 0.28);
}
.ds7-day.is-on:hover { background: #e11d48; color: #fff; }
.ds7-day.is-past { opacity: 0.55; }
.ds7-day.is-past.is-on { opacity: 1; }
.ds7-day.is-we .ds7-dow { color: #b45309; }
.ds7-day.is-we.is-on .ds7-dow { color: #fff; }

.ds7-dow { font-size: 11.5px; font-weight: 900; white-space: nowrap; }
.ds7-num {
  font-size: 10.5px; font-weight: 700; opacity: 0.8;
  font-variant-numeric: tabular-nums;
}
/* The day's still-open rides. The empty variant keeps its box so every
   button is the same height whether or not it has a number. */
.ds7-n {
  min-width: 17px; height: 15px; margin-top: 1px; padding: 0 4px;
  border-radius: 999px; background: rgba(2, 6, 23, 0.08); color: #64748b;
  font-size: 9.5px; font-weight: 900; line-height: 15px;
  font-variant-numeric: tabular-nums;
}
.ds7-n.is-zero { background: transparent; }
.ds7-day.is-on .ds7-n { background: rgba(255, 255, 255, 0.28); color: #fff; }

.ds7-nav {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border: none; border-radius: 11px;
  background: #f1f5f9; color: #64748b;
  font-size: 13px; cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}
.ds7-nav:hover { background: #e11d48; color: #fff; }

body.dark .ds7-day { color: #93a4bd; }
body.dark .ds7-day:hover { background: rgba(251, 113, 133, 0.14); color: #e6edf6; }
body.dark .ds7-day.is-we .ds7-dow { color: #fcd34d; }
body.dark .ds7-n { background: rgba(255, 255, 255, 0.10); color: #93a4bd; }
body.dark .ds7-nav { background: rgba(255, 255, 255, 0.06); color: #93a4bd; }

@media (max-width: 767px) {
  .ds7-day { min-width: 58px; padding: 6px 7px; }
  .ds7-dow { font-size: 11px; }

  /* Two rows on a phone: the days get the full width, and the date
     field and the mode badge share the row underneath.
     `flex-wrap` alone put the picker and the badge on the SAME line as
     the strip until they ran out of room, which squeezed the seven days
     into about a third of the screen — two and a half buttons visible,
     with today off-screen. */
  #date-strip {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 6px;
    align-items: center;
  }
  #date-strip .ds7-days { grid-column: 2; min-width: 0; }
  #date-strip #ds-picker {
    grid-column: 1 / -1;
    width: 100%;
    /* 44px — the minimum a thumb can hit. It was 36. */
    min-height: 44px;
  }
  #date-strip #ds-mode {
    grid-column: 1 / -1;
    margin: 0;
    text-align: center;
  }
  #date-strip #ds-publish { grid-column: 1 / -1; width: 100%; }
  /* Nav buttons to the touch minimum as well. */
  .ds7-nav { width: 44px; height: 44px; }
  .ds7-day { min-height: 44px; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .ds7-day, .ds7-nav { transition: none; }
}

/* The "free drivers" toggle in the board's header row. It replaced a
   full-width strip of avatar chips above the board — a whole row spent
   on a single number. Styled to sit with the buttons beside it. */
/* dispatch.js does `classList.toggle("hidden", idleDrivers.length === 0)`
   to hide this when nobody is free — and it never worked, because
   style.css loads after the Tailwind build and a bare .idle-btn rule
   beats .hidden. "Frei verfügbar (0)" sat there permanently. */
.idle-btn.hidden { display: none !important; }
.idle-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px; border-radius: 8px;
  border: 1px dashed #cbd5e1; background: transparent; color: #64748b;
  font-size: 12px; font-weight: 700; cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}
.idle-btn:hover { border-color: #e11d48; color: #e11d48; }
.idle-btn.is-on {
  border-style: solid; border-color: transparent;
  background: rgba(225, 29, 72, 0.10); color: #be123c;
}
.idle-btn .idle-n {
  min-width: 18px; padding: 0 5px; border-radius: 999px;
  background: rgba(2, 6, 23, 0.08); color: inherit;
  font-size: 10.5px; font-weight: 900; line-height: 16px; text-align: center;
  font-variant-numeric: tabular-nums;
}
body.dark .idle-btn { border-color: rgba(255, 255, 255, 0.18); color: #93a4bd; }
body.dark .idle-btn:hover { border-color: #fb7185; color: #fb7185; }
body.dark .idle-btn.is-on { background: rgba(225, 29, 72, 0.22); color: #fda4af; }
body.dark .idle-btn .idle-n { background: rgba(255, 255, 255, 0.12); }
@media (max-width: 640px) {
  .idle-btn .idle-lbl { display: none; }
}
@media (prefers-reduced-motion: reduce) { .idle-btn { transition: none; } }

/* ═══════════════════════════════════════════════════════════════════
   Board card + lane refinements.
   Appended so it wins over the older tk- and dr- rules above without
   editing them in place — the layout is the operator's and these are
   targeted adjustments, not a rewrite.
   ═══════════════════════════════════════════════════════════════════ */

/* Taller lane and taller card. The strip was tight enough that the
   route lines and the meta row had no air between them. */
.dr-tasks { min-height: 190px; align-items: stretch; }
.tk-card {
  min-height: 176px;
  padding: 12px 14px;
  gap: 14px;
  align-content: start;
}
.tk-body { display: flex; flex-direction: column; gap: 8px; }

/* Pickup on top, destination underneath. They used to sit on one line
   with an arrow between them, so a long address pushed the other one
   out of sight. */
.tk-route {
  display: flex;
  flex-direction: column;
  gap: 5px;
  position: relative;
}
.tk-route-arrow { display: none; }
.tk-route-from,
.tk-route-to {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  font-size: 12px;
  line-height: 1.45;
  white-space: normal;
}
.tk-route-from > i,
.tk-route-to > i {
  flex: 0 0 auto;
  width: 12px;
  margin-top: 3px;
  text-align: center;
  font-size: 10px;
}
.tk-route-from > i { color: #3b82f6; }
.tk-route-to > i { color: #10b981; }
.tk-route-from > span,
.tk-route-to > span {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}
/* A hairline joining the two pins, so the pair reads as one journey. */
.tk-route::before {
  content: "";
  position: absolute;
  inset-inline-start: 5px;
  top: 15px;
  bottom: 15px;
  width: 1px;
  background: var(--border, rgba(2, 6, 23, 0.12));
}

/* ── the four-step track ───────────────────────────────────────────── */
/* Zugewiesen → Erhalten → Unterwegs → Erledigt. Each step is written by
   a different party — the panel sends, the driver acknowledges in
   Telegram or the PWA, the Transportschein upload moves it on, and
   Erledigt closes it — so the track is a map of that handover. A flat
   "Erhalten" pill said where it is but not how far along. */
.tk-track {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--surface-2, #f1f5f9);
}
.tk-track-dots { display: inline-flex; align-items: center; }
.tk-dot {
  width: 6px; height: 6px; border-radius: 999px;
  background: #cbd5e1;
}
.tk-dot.is-done { background: #10b981; }
.tk-dot.is-now { background: #3b82f6; box-shadow: 0 0 0 2.5px rgba(59, 130, 246, 0.22); }
.tk-dot-line { width: 9px; height: 1.5px; background: #e2e8f0; }
.tk-track-lbl {
  font-size: 10.5px; font-weight: 900; white-space: nowrap;
  color: #64748b;
}
.tk-track-1 { background: rgba(59, 130, 246, 0.12); }
.tk-track-1 .tk-track-lbl { color: #1d4ed8; }
.tk-track-2 { background: rgba(245, 158, 11, 0.16); }
.tk-track-2 .tk-track-lbl { color: #b45309; }
.tk-track-2 .tk-dot.is-now { background: #f59e0b; box-shadow: 0 0 0 2.5px rgba(245, 158, 11, 0.22); }
.tk-track-3 { background: rgba(16, 185, 129, 0.16); }
.tk-track-3 .tk-track-lbl { color: #047857; }
body.dark .tk-track { background: rgba(255, 255, 255, 0.06); }
body.dark .tk-track-lbl { color: #93a4bd; }
body.dark .tk-track-1 .tk-track-lbl { color: #93c5fd; }
body.dark .tk-track-2 .tk-track-lbl { color: #fcd34d; }
body.dark .tk-track-3 .tk-track-lbl { color: #6ee7b7; }
body.dark .tk-dot { background: rgba(255, 255, 255, 0.22); }
body.dark .tk-dot-line { background: rgba(255, 255, 255, 0.14); }

/* ── meta row: type, insurance, co-driver ──────────────────────────── */
.tk-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
  margin-top: auto; padding-top: 2px;
}
.tk-codriver {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: 7px;
  background: rgba(217, 70, 239, 0.12); color: #a21caf;
  font-size: 10.5px; font-weight: 800; white-space: nowrap;
}
.tk-codriver i { font-size: 9.5px; }
body.dark .tk-codriver { background: rgba(217, 70, 239, 0.20); color: #f0abfc; }

/* ── lane header: photo, name, vehicle ─────────────────────────────── */
/* Same three facts, given room to line up instead of stacking tight. */
.dr-info { align-items: center; gap: 12px; }
.dr-name { font-size: 15px; font-weight: 900; line-height: 1.25; }
.dr-sub {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 700; margin-top: 2px;
}
.dr-sub i { font-size: 11px; opacity: 0.75; }
.dr-avatar-img, .dr-avatar-fallback {
  width: 46px; height: 46px; border-radius: 14px;
}
.dr-kpis { margin-top: 7px; gap: 5px; }
.dr-kpi { padding: 3px 9px; font-size: 11px; border-radius: 999px; }

@media (max-width: 767px) {
  .dr-tasks { min-height: 0; }
  .tk-card { min-height: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .tk-card, .tk-track { transition: none; }
}

/* (Fahrzeug-Check CSS moved: the page is a Fuhrpark-section module now —
   src/features/wartung/wartung.page.ts + the .wt3-* block in fuhrpark.css.) */

/* ── the shared driver avatar ──────────────────────────────────────── */
/* One implementation, used wherever a driver's name appears. Five
   near-copies of "first letter on a gradient" existed across the page
   modules, and Finanzen showed only the letter even though the photo
   was in boardState all along. */
.mt-av {
  flex-shrink: 0; object-fit: cover; display: inline-flex;
  align-items: center; justify-content: center;
  border: 1px solid var(--border, rgba(2, 6, 23, 0.10));
  background: var(--surface-2, #f1f5f9);
}
.mt-av--ph { color: #fff; font-weight: 900; border-color: transparent; }
.mt-avname { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.mt-avname-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The dispatcher's note on a ride ("Zusätzliche Hinweise"). It used to
   be an amber icon beside the patient name with the text hidden in a
   title attribute — invisible on touch, and the thing it usually says
   is how to get the patient out of the building. The card is tall
   enough to show it now. */
.tk-note {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 2px; padding-top: 7px;
  border-top: 1px dashed var(--border, rgba(2, 6, 23, 0.12));
  font-size: 11.5px; font-weight: 700; line-height: 1.45;
  color: #b45309;
}
.tk-note > i { flex: 0 0 auto; margin-top: 2px; font-size: 10px; }
.tk-note > span {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere;
}
body.dark .tk-note { color: #fcd34d; }

/* ═══ Dispo-Assistent — "wer kann diese Fahrt nehmen?" ══════════════
   Lives INSIDE the .modal-shell as its second flex child. The shell is
   already `flex items-center justify-center`, so the two-pane row costs
   nothing — and closeModals(), which hides every .fixed.inset-0 by
   class, keeps working without being taught this exists.

   Below 1024px there is not room for two panes beside each other (the
   task card alone is max-w-lg), so the shell becomes a column and this
   becomes a bottom sheet. That breakpoint is the panel's existing
   sidebar-collapse point, not a new one. */
/* style.css loads AFTER admin.compiled.css, so a bare .dispo-advisor
   rule beats Tailwind's .hidden { display: none }. Without this the
   assistant is never hidden: it sits at the end of <body> on EVERY
   page, and on the Fahrzeuge tab it lands on top of the edit buttons —
   which reads as "the buttons don't work".
   The same note is written twenty lines above .db-pane. I wrote a new
   display:flex component and forgot it anyway, which is why
   scripts/test-hidden-override.js now checks the whole family. */
.dispo-advisor.hidden { display: none !important; }

.dispo-advisor {
  display: flex;
  flex-direction: column;
  width: 340px;
  flex-shrink: 0;
  max-height: 90vh;
  margin-inline-start: 14px;
  padding: 14px;
  border-radius: 20px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, rgba(2, 6, 23, 0.10));
  box-shadow: 0 10px 40px rgba(2, 6, 23, 0.18);
  overflow: hidden;
}
body.dark .dispo-advisor { background: #0f172a; border-color: #334155; }

.dispo-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}
.dispo-title {
  font-size: 14px;
  font-weight: 900;
  color: var(--text, #0f172a);
  margin: 0;
}
body.dark .dispo-title { color: #e6edf6; }
.dispo-count {
  margin-inline-start: auto;
  padding: 2px 9px;
  border-radius: 999px;
  background: #dcfce7;
  color: #166534;
  font-size: 11px;
  font-weight: 900;
}
.dispo-count.is-none { background: #fef3c7; color: #92400e; }
body.dark .dispo-count { background: rgba(22,101,52,0.28); color: #86efac; }
body.dark .dispo-count.is-none { background: rgba(146,64,14,0.28); color: #fcd34d; }

/* Collapse is a sheet affordance; on desktop the panel is always open
   and the chevron only wastes a target, so it is hidden there. */
.dispo-collapse { display: none; }

.dispo-ride {
  margin: 0 0 8px;
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 0.01em;
  color: #64748b;
}
body.dark .dispo-ride { color: #94a3b8; }

.dispo-body { overflow-y: auto; display: flex; flex-direction: column; gap: 8px; }

.dispo-note {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 700;
  color: #64748b;
}
.dispo-note.is-warn {
  padding: 5px 9px;
  border-radius: 9px;
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #b45309;
}
body.dark .dispo-note { color: #94a3b8; }
body.dark .dispo-note.is-warn {
  background: rgba(180,83,9,0.16); border-color: rgba(180,83,9,0.42); color: #fcd34d;
}

/* ── one candidate ─────────────────────────────────────────────────
   A button when it can be picked, a div when it cannot — so a
   suspended driver is not focusable and cannot be clicked by keyboard
   either. */
.dispo-cand {
  display: flex;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border-radius: 14px;
  border: 1px solid var(--border, rgba(2,6,23,0.10));
  /* The state rail. A border, not a ::before — the pseudo-element on a
     task card was already taken once and the collision produced a red
     line down every card. */
  border-inline-start-width: 4px;
  background: var(--surface-2, #f8fafc);
  text-align: start;
  cursor: default;
}
button.dispo-cand { cursor: pointer; }
button.dispo-cand:hover { background: #eef2ff; }
button.dispo-cand:active { transform: scale(0.99); }
body.dark .dispo-cand { background: #131c30; border-color: #334155; }
body.dark button.dispo-cand:hover { background: rgba(99,102,241,0.12); }

.dispo-cand.is-ok           { border-inline-start-color: #16a34a; }
.dispo-cand.is-tight        { border-inline-start-color: #ca8a04; }
.dispo-cand.is-unknown      { border-inline-start-color: #94a3b8; }
.dispo-cand.is-conflict     { border-inline-start-color: #dc2626; }
.dispo-cand.is-no-vehicle   { border-inline-start-color: #dc2626; }
.dispo-cand.is-suspended    { border-inline-start-color: #475569; opacity: 0.62; }

.dispo-cand-av { position: relative; flex-shrink: 0; }
.dispo-clock {
  position: absolute;
  inset-block-end: -1px;
  inset-inline-end: -1px;
  width: 9px; height: 9px;
  border-radius: 999px;
  border: 2px solid var(--surface-2, #f8fafc);
}
.dispo-clock.is-on { background: #16a34a; }
.dispo-clock.is-pause { background: #ca8a04; }
body.dark .dispo-clock { border-color: #131c30; }

.dispo-cand-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.dispo-cand-top { display: flex; align-items: center; gap: 8px; }
.dispo-cand-name {
  font-size: 13px; font-weight: 900; color: var(--text, #0f172a);
  overflow-wrap: anywhere;
}
body.dark .dispo-cand-name { color: #e6edf6; }

/* Icon AND word AND colour. Never colour alone — this is read in
   daylight, and the skill rates colour-only state HIGH severity. */
.dispo-verdict {
  margin-inline-start: auto;
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10.5px; font-weight: 900; white-space: nowrap;
}
.is-ok .dispo-verdict          { color: #15803d; }
.is-tight .dispo-verdict       { color: #a16207; }
.is-unknown .dispo-verdict     { color: #475569; }
.is-conflict .dispo-verdict,
.is-no-vehicle .dispo-verdict  { color: #b91c1c; }
.is-suspended .dispo-verdict   { color: #334155; }
body.dark .is-ok .dispo-verdict { color: #86efac; }
body.dark .is-tight .dispo-verdict { color: #fcd34d; }
body.dark .is-unknown .dispo-verdict { color: #cbd5e1; }
body.dark .is-conflict .dispo-verdict,
body.dark .is-no-vehicle .dispo-verdict { color: #fca5a5; }

.dispo-cand-veh,
.dispo-cand-why {
  font-size: 11px; font-weight: 700; color: #64748b; overflow-wrap: anywhere;
}
.dispo-cand-why { color: #475569; }
body.dark .dispo-cand-veh { color: #94a3b8; }
body.dark .dispo-cand-why { color: #cbd5e1; }

/* The driver's day, so the operator can see WHERE the new ride lands
   rather than trusting a count. */
.dispo-cand-day { display: flex; flex-direction: column; gap: 1px; margin-top: 3px; }
.dispo-trip {
  font-size: 10.5px; font-weight: 600; color: #64748b; overflow-wrap: anywhere;
}
.dispo-trip b { font-weight: 900; color: #334155; }
.dispo-trip-empty { font-style: italic; }
body.dark .dispo-trip { color: #94a3b8; }
body.dark .dispo-trip b { color: #cbd5e1; }

/* ── the shell becomes two panes ───────────────────────────────────── */
@media (min-width: 1024px) {
  .modal-shell.has-dispo { align-items: center; }
}

/* ── phone + tablet: a bottom sheet ────────────────────────────────
   Collapsed to its header by default. The count in that header ("3
   frei") is the one number worth seeing without a tap, so collapsing
   costs nothing and the form keeps the screen. */
@media (max-width: 1023px) {
  .modal-shell.has-dispo {
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-end;
    padding: 0;
    gap: 0;
  }
  .modal-shell.has-dispo > div:first-of-type {
    max-height: 62vh;
    overflow-y: auto;
    margin: 8px;
  }
  .dispo-advisor {
    width: auto;
    margin: 0;
    max-height: 46vh;
    border-radius: 20px 20px 0 0;
    border-inline: none;
    border-block-end: none;
    padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 10px);
  }
  .dispo-collapse {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Past the 44px touch floor — a gloved thumb on a tablet. */
    width: 44px; height: 44px;
    margin-inline-start: -10px;
    border: 0; background: transparent; color: #64748b; cursor: pointer;
  }
  .dispo-advisor.is-collapsed .dispo-ride,
  .dispo-advisor.is-collapsed .dispo-body { display: none; }
  .dispo-advisor.is-collapsed { max-height: none; }
  .dispo-collapse i { transition: transform 0.18s; }
  .dispo-advisor.is-collapsed .dispo-collapse i { transform: rotate(-90deg); }
}

@media (prefers-reduced-motion: reduce) {
  button.dispo-cand:active { transform: none; }
  .dispo-collapse i { transition: none; }
}

/* ═══ Dispo-Assistent — the "not listed" footnote ══════════════════
   The panel shows ACTIVE DRIVERS only. Saying so quietly is the
   difference between a deliberate filter and a missing name. */
.dispo-foot {
  margin: 6px 0 0;
  padding-top: 6px;
  border-top: 1px solid var(--border, rgba(2, 6, 23, 0.10));
  font-size: 10.5px;
  font-weight: 700;
  color: #94a3b8;
}
body.dark .dispo-foot { color: #64748b; border-top-color: #334155; }
