:root {
  --bg: #f4f6f8;
  --panel: #ffffff;
  --border: #dde3ea;
  --text: #1f2933;
  --muted: #667085;
  /* Identyfikacja Prime Power z mockupów: żółty akcent na czerni. */
  --accent: #f5a800;
  --accent-dark: #d99400;
  --ink: #1a1a1a;
  --ink-soft: #2e2e2e;
  --primary: #f5a800;
  --primary-dark: #d99400;
  --ok: #22c55e;
  --warn: #f59e0b;
  --info: #2563eb;
  --danger: #d92d20;
  --danger-dark: #b42318;
  --radius: 8px;
}

* { box-sizing: border-box; }

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

/* ---------- Login page ---------- */
.login-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.login-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 32px;
  width: 100%;
  max-width: 360px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06);
  text-align: center;
}

.login-card img.logo {
  max-width: 200px;
  margin-bottom: 24px;
}

/* ---------- Shell ---------- */
.shell {
  display: flex;
  min-height: 100vh;
}

/* ---------- Pasek nawigacji ----------
   Ciemny pasek przy jasnej treści: oko wraca do danych, nie do menu, a żółty akcent
   marki na grafitowym tle daje najwyższy kontrast, jaki ta paleta ma do zaoferowania.
   Gęstość jak w panelach operacyjnych — 40 px na pozycję, bez marnowania wysokości. */
.sidebar {
  width: 232px;
  flex-shrink: 0;
  background: #171a1f;
  color: #cfd4dc;
  display: flex;
  flex-direction: column;
  padding: 14px 12px 16px;
  gap: 2px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

/* Znak firmowy ma czarne skrzydła i niebieski napis — na ciemnym tle potrzebuje
   własnego, jasnego kafelka, inaczej połowa znaku znika. */
.brand {
  background: #fff;
  border-radius: 10px;
  padding: 10px 12px;
  margin-bottom: 14px;
}

.brand .logo { display: block; width: 100%; height: auto; }

.sidebar nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Etykieta grupy: dziesięć pozycji pod rząd czyta się jak worek, trzy krótkie grupy
   jak spis treści. */
.nav-group {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #7d8592;
  padding: 16px 10px 4px;
}

.sidebar a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding: 8px 10px;
  border-radius: 8px;
  color: #cfd4dc;
  text-decoration: none;
  font-size: 14px;
  transition: background 150ms ease, color 150ms ease;
}

.sidebar a:hover { background: rgba(255, 255, 255, 0.07); color: #fff; }

/* Stan aktywny niesiony trzema sygnałami naraz (pasek, tło, grubość) — sam kolor
   odpada, bo nie każdy go rozróżni. */
.sidebar a.active {
  background: rgba(245, 168, 0, 0.16);
  color: #fff;
  font-weight: 600;
}

.sidebar a.active::before {
  content: "";
  position: absolute;
  left: -12px;
  top: 8px;
  bottom: 8px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--accent);
}

.sidebar a.active .nav-ico { color: var(--accent); }

/* Obrys skupienia zostaje — bez niego panel jest nie do obsłużenia z klawiatury. */
.sidebar a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.nav-ico {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: #98a2b3;
}

.sidebar a:hover .nav-ico { color: #e4e7ec; }

/* Licznik przy pozycji: ile roboty czeka w danej zakładce. Cyfry o stałej szerokości,
   żeby liczba nie „skakała" przy odświeżeniu. */
.nav-count {
  margin-left: auto;
  font-style: normal;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  padding: 3px 7px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  color: #e4e7ec;
}

.nav-count.alarm { background: var(--danger); color: #fff; }

.sidebar .logs-link {
  margin-top: auto;
  border-top: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 0;
  padding-top: 14px;
  margin-bottom: 2px;
}

.sidebar .logs-link.active { border-radius: 0 0 8px 8px; }
.sidebar .logout { color: #ff9c92; }
.sidebar .logout:hover { background: rgba(217, 45, 32, 0.18); color: #ffd7d3; }

/* Wąskie ekrany: pasek kładzie się poziomo nad treścią zamiast zjadać jej szerokość. */
@media (max-width: 860px) {
  .shell { flex-direction: column; }
  .sidebar {
    width: 100%;
    height: auto;
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
  }
  .brand { margin: 0 12px 0 0; max-width: 150px; }
  .sidebar nav { flex-direction: row; flex-wrap: wrap; }
  .nav-group { display: none; }
  .sidebar .logs-link { margin: 0; border: none; padding-top: 8px; }
}

.main {
  flex: 1;
  padding: 28px 32px;
  max-width: 1400px;
}

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

/* ---------- Forms ---------- */
.form-inline {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-end;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 20px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
}

.field label { color: var(--muted); }

input, select, textarea {
  font: inherit;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
  color: var(--text);
}

input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--primary);
  outline-offset: -1px;
}

button {
  font: inherit;
  cursor: pointer;
  border: none;
  border-radius: 6px;
  padding: 9px 16px;
  background: var(--primary);
  color: var(--ink);
  font-weight: 600;
}

button:hover { background: var(--primary-dark); }
button.secondary { background: #e4e7ec; color: var(--text); }
button.secondary:hover { background: #d0d5dd; }
button.danger { background: var(--danger); color: #fff; }
button.danger:hover { background: var(--danger-dark); }
button:disabled { opacity: 0.6; cursor: default; }

/* ---------- Table ---------- */
table {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

th, td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
  vertical-align: middle;
}

th {
  background: var(--bg);
  color: var(--muted);
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

tr:last-child td { border-bottom: none; }

td.actions {
  display: flex;
  gap: 6px;
  white-space: nowrap;
}

td input, td select { width: 100%; min-width: 90px; }

.error {
  color: var(--danger);
  font-size: 13px;
  min-height: 18px;
}

.hint {
  color: var(--muted);
  font-size: 12px;
  margin-top: -8px;
  margin-bottom: 12px;
}

/* Podpowiedź WEWNĄTRZ pola: .field jest flexem z gap 4px, więc ujemny margines
   z reguły wyżej wciągał tekst na sam input i litery nachodziły na wpisaną treść.
   Wewnątrz pola odstępami rządzi gap, nie marginesy. */
.field > .hint { margin-top: 0; margin-bottom: 0; }

/* Ostrzeżenie w formularzu — osobny blok, nie doklejka do pola wyżej. */
.form-note {
  font-size: 12px;
  color: #93370d;
  background: #fffaeb;
  border-left: 3px solid #dc6803;
  padding: 8px 10px;
  border-radius: 0 4px 4px 0;
  margin: 0 0 12px;
  line-height: 1.5;
}

.empty {
  color: var(--muted);
  padding: 20px;
  text-align: center;
}

/* ---------- Badge'e statusów ---------- */
.badge {
  display: inline-block;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.badge-ok { background: #dcfce7; color: #15803d; }
.badge-warn { background: #fef3c7; color: #92400e; }
.badge-danger { background: #fee2e2; color: #b42318; }
.badge-info { background: #dbeafe; color: #1d4ed8; }
.badge-muted { background: #e4e7ec; color: #475467; }

/* ---------- Kafle statystyk ---------- */
.stat-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 20px;
}

.stat-card {
  flex: 1 1 140px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 14px 16px;
  text-decoration: none;
  color: inherit;
  display: block;
}

a.stat-card:hover { border-color: var(--accent); background: #fffdf7; }
.stat-card.stat-danger { border-left-color: var(--danger); }
.stat-card.stat-ok { border-left-color: var(--ok); }
.stat-n { font-size: 24px; font-weight: 700; line-height: 1.2; }
.stat-l { font-size: 12px; color: var(--muted); margin-top: 2px; }

/* ---------- Bannery alertów ---------- */
.alert {
  border-radius: var(--radius);
  padding: 10px 14px;
  margin-bottom: 8px;
  font-size: 14px;
  border-left: 3px solid var(--warn);
  background: #fffbeb;
}

.alert-high { border-left-color: var(--danger); background: #fef2f2; }
.alert-normal { border-left-color: var(--warn); background: #fffbeb; }

/* ---------- Chipy filtrów / pasek narzędzi ---------- */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 16px;
}

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

.chip {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 500;
}

.chip:hover { background: var(--bg); }
.chip.active { background: var(--accent); border-color: var(--accent); color: var(--ink); font-weight: 600; }

/* ---------- Modal ---------- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 40px 16px;
  overflow-y: auto;
  z-index: 100;
}

.modal {
  background: var(--panel);
  border-radius: var(--radius);
  width: 100%;
  max-width: 560px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}

.modal-head h2 { font-size: 16px; margin: 0; }
.modal-head .modal-x { padding: 4px 10px; }
.modal-body { padding: 20px; }
.modal-body .field { margin-bottom: 12px; }
/* Pola w oknie modalnym biorą całą szerokość — ale NIE checkboxy i radia. Reguła
   rozciągała kwadracik wyboru serwisanta na 320 px, przez co nazwisko dostawało
   resztkę i łamało się na dwie linie. */
.modal-body .field input:not([type="checkbox"]):not([type="radio"]),
.modal-body .field select,
.modal-body .field textarea { width: 100%; }

/* ---------- Karty i układy szczegółowe ---------- */
.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 20px;
  margin-bottom: 16px;
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.card-head h2 { font-size: 15px; margin: 0; }

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
}

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

.meta-row {
  display: flex;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
}

.meta-row:last-child { border-bottom: none; }
.meta-k { color: var(--muted); min-width: 170px; flex-shrink: 0; }
.meta-v { font-weight: 500; }

.back-link {
  display: inline-block;
  margin-bottom: 12px;
  color: var(--muted);
  text-decoration: none;
  font-size: 13px;
}

.back-link:hover { color: var(--text); }

.money {
  font-size: 22px;
  font-weight: 700;
}

/* ---------- Kalendarz ---------- */
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px;
}

.cal-head {
  text-align: center;
  font-size: 12px;
  color: var(--muted);
  font-weight: 600;
  text-transform: uppercase;
  padding: 6px 0;
}

.cal-day {
  min-height: 74px;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px;
  font-size: 13px;
  cursor: pointer;
  background: var(--panel);
}

.cal-day:hover { background: var(--bg); }
.cal-day.other-month { opacity: 0.4; }
.cal-day.today { border-color: var(--accent); border-width: 2px; }
.cal-day.selected { background: #fffdf7; border-color: var(--accent); }
.cal-dots { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 4px; }

.cal-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--muted);
}

.cal-dot.pilny { background: var(--danger); }
.cal-dot.planowany { background: var(--warn); }
.cal-dot.wykonany { background: var(--ok); }
/* Ręczne odhaczenie: obwódka zamiast wypełnienia — widać, że to nie to samo. */
.cal-dot.reczny { background: #fffaeb; border: 2px solid #dc6803; }
.cal-dot.nieprzydzielony { background: var(--danger); box-shadow: 0 0 0 2px #fee2e2; }

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin: 12px 0;
  font-size: 12px;
  color: var(--muted);
}

.legend-item { display: flex; align-items: center; gap: 5px; }

/* ---------- Mapa ---------- */
.map-split {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 16px;
  align-items: start;
}

@media (max-width: 900px) {
  .map-split { grid-template-columns: 1fr; }
}

#map {
  height: calc(100vh - 160px);
  min-height: 420px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* ---------- Pracownicy / awatary ---------- */
.avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  flex-shrink: 0;
}

.emp-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
  cursor: pointer;
}

.emp-row:last-child { border-bottom: none; }
.emp-row .grow { flex: 1; min-width: 0; }
.emp-sub { font-size: 12px; color: var(--muted); }

/* ---------- Lista wyboru wielokrotnego (serwisanci na zleceniu) ---------- */
/* Zamiast <select multiple>, które wymaga Cmd/Ctrl+klik i w praktyce jest
   nieklikalne — jedno zlecenie idzie na jedną osobę, parę albo ekipę. */
/* Lista serwisantów: jedna osoba w wierszu. Kafelki „pigułki" łamały nazwiska na dwie
   linie i przy pięciu osobach robiły mozaikę, w której nie dało się porównać obłożenia. */
.checklist {
  display: grid;
  /* 300 px na wiersz: w oknie modalnym wychodzi jedna kolumna (nazwisko i stan mają
     miejsce), na szerokim formularzu dwie. Węższe kolumny obcinały nazwiska. */
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 6px;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px;
  background: #fff;
}

.check-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 14px;
  cursor: pointer;
  user-select: none;
}

/* Nazwisko bierze całą wolną szerokość, plakietka stanu siada przy prawej krawędzi —
   dzięki temu wszystkie stany są w jednej kolumnie i da się je porównać wzrokiem. */
.check-item > span:not(.avail-tag) { flex: 1; }
.check-item .avail-tag { flex-shrink: 0; }

.check-item:hover { background: var(--bg); }
.check-item input { margin: 0; cursor: pointer; }
.check-item:has(input:checked) {
  background: #fff8e6;
  border-color: var(--accent);
  font-weight: 600;
}

.hint-inline {
  color: var(--muted);
  font-weight: 400;
  font-size: 12px;
}

/* Pin serwisanta na mapie — kolor wstawiany inline wg work_status. */
.pp-pin {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

/* ---------- Wiersze klikalne ---------- */
tr.clickable { cursor: pointer; }
tr.clickable:hover td { background: #fffdf7; }

/* Dokument raportu w panelu: kartka A4 z lib/report_html.php wyświetlana w ramce.
   Proporcje 210:297, więc widać całą stronę bez przewijania w środku. */
.doc-card { padding-bottom: 12px; }
.doc-frame {
  width: 100%;
  aspect-ratio: 210 / 297;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: #fff;
}

/* Kalendarz dostępności floty: siatka sztuka × dni. Wąskie kolumny, bo trzydzieści dni
   musi zmieścić się bez przewijania na typowym monitorze; przy węższym oknie przewija
   się poziomo tylko sama tabela, nie cała strona. */
.cal-scroll { overflow-x: auto; }
.cal-table { border-collapse: collapse; width: auto; min-width: 100%; }
.cal-table th, .cal-table td { border: 1px solid var(--border); padding: 0; }
.cal-table .cal-name {
  padding: 6px 10px;
  white-space: nowrap;
  position: sticky;
  left: 0;
  background: var(--panel);
  text-align: left;
  font-size: 13px;
}
.cal-table .cal-day { width: 22px; font-size: 10px; color: var(--muted); text-align: center; padding: 4px 0; }
.cal-table td.cal-free { background: var(--panel); height: 26px; }
.cal-table td.cal-busy { background: #f5a800; }
.cal-table td.cal-reserved { background: #bfdbfe; }
.cal-legend { display: flex; gap: 16px; margin-top: 10px; font-size: 12px; color: var(--muted); }
.cal-legend i { display: inline-block; width: 14px; height: 14px; vertical-align: -2px; margin-right: 4px; border: 1px solid var(--border); }
.cal-legend i.cal-busy { background: #f5a800; }
.cal-legend i.cal-reserved { background: #bfdbfe; }
.cal-legend i.cal-free { background: var(--panel); }
.actions-cell { white-space: nowrap; }
.actions-cell button { margin-right: 6px; }

/* Tydzień floty: ten sam .cal-table, ale tylko 7 kolumn zamiast 30 — starcza miejsca
   na krótki tekst w komórce (kto/co), nie tylko na sam kolor jak w kalendarzu najmu. */
.cal-table.cal-week .cal-day { width: 130px; font-size: 11px; }
.cal-table.cal-week td.cal-busy {
  height: auto;
  padding: 4px 8px;
  font-size: 12px;
  color: var(--ink);
}
.cal-table.cal-week td.cal-busy a { color: var(--ink); font-weight: 600; text-decoration: none; }
.cal-table.cal-week td.cal-busy a:hover { text-decoration: underline; }
.cal-table tr.retired td.cal-name { color: var(--muted); }
.cal-table tr.retired td.cal-free { background: #f4f4f4; }

/* Kto jedzie — druga linia pod klientem, w każdej komórce zajętej. */
.cal-table.cal-week td.cal-busy a:not(.cal-visit),
.cal-table.cal-week td.cal-busy .cal-visit-main,
.cal-table.cal-week td.cal-busy .cal-crew {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cal-table.cal-week td.cal-busy .cal-crew { font-size: 10px; font-weight: 400; color: var(--muted); }

/* Kilka wizyt tego samego auta i dnia — jedna pod drugą, nie zbiorczy licznik. */
.cal-table.cal-week td.cal-multi { padding: 3px 6px; }
.cal-table.cal-week td.cal-multi a.cal-visit { display: block; padding: 2px 0; }
.cal-table.cal-week td.cal-multi a.cal-visit + a.cal-visit { border-top: 1px solid rgba(0, 0, 0, 0.08); }


/* Grupy pól w długich formularzach — okno "Nowe zlecenie" ma kilkanaście pól
   i bez podziału na "kto i gdzie / co i kiedy / kto jedzie" czyta się jak lista. */
.form-section {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--border);
  padding-bottom: 6px;
  margin: 20px 0 14px;
}
.form-section:first-child { margin-top: 0; }

/* Pole z przyciskiem obok (np. select klienta + "nowa firma"). */
.field-row { display: flex; gap: 8px; align-items: center; }
.field-row select, .field-row input { flex: 1; min-width: 0; }

/* Dane klienta dzielą się na te dla biura i te, które schodzą serwisantowi na telefon
   (adres dojazdu + kontakt na miejscu). Podział musi być widać przy wpisywaniu, bo
   wpisanie nazwy firmy w "kontakt na miejscu" ujawnia klienta pracownikowi. */
.form-section.crew { color: var(--info); border-bottom-color: var(--info); }
.crew-fields {
  border-left: 3px solid var(--info);
  padding-left: 12px;
  margin-bottom: 4px;
}
.crew-fields .hint { margin-top: 0; }

/* Wynik sprawdzenia w wykazie podatników VAT. Kolor niesie treść, ale nie sam:
   status jest zawsze wypisany słowem, bo "zielona ramka" to za mało przy decyzji
   o przelewie na 15 000 zł. */
.wl-box {
  border: 1px solid var(--border);
  border-left: 3px solid var(--muted);
  border-radius: var(--radius);
  padding: 10px 12px;
  margin-bottom: 14px;
  font-size: 13px;
}
.wl-box.wl-ok { border-left-color: var(--ok); background: #f0fdf4; }
.wl-box.wl-warn { border-left-color: var(--warn); background: #fffbeb; }
.wl-box.wl-bad { border-left-color: var(--danger); background: #fef3f2; }
.wl-head { font-weight: 600; margin-bottom: 4px; }
.wl-box .wl-warn { color: var(--danger-dark); margin-top: 6px; }
.wl-accounts { display: flex; flex-direction: column; gap: 4px; margin: 8px 0; }
.wl-accounts label { display: flex; gap: 8px; align-items: center; font-family: ui-monospace, monospace; }
.wl-flag-ok { color: #15803d; font-weight: 600; }
.wl-flag-bad { color: var(--danger-dark); font-weight: 600; }
.wl-recheck { margin-top: 12px; }
.wl-recheck .hint { margin-top: 6px; margin-bottom: 0; }

/* Zdanie wprowadzające pod nagłówkiem strony — mówi, czym ten ekran różni się od
   sąsiedniego; bez niego "Katalog modeli" to sama nazwa. */
.lead {
  color: var(--muted);
  font-size: 14px;
  max-width: 70ch;
  margin: -4px 0 16px;
}

/* Szeroka tabela ma przewijać się sama, a nie rozpychać całą stronę. */
.table-scroll { overflow-x: auto; }

/* Odnośnik w formularzu, wyrównany do dolnej krawędzi pól obok. */
.form-note { align-self: flex-end; color: var(--muted); font-size: 12px; padding-bottom: 10px; }

/* Link wyglądający jak przycisk drugorzędny — wejście do podstrony z paska nad listą. */
.button-link {
  display: inline-block;
  padding: 8px 14px;
  border-radius: var(--radius);
  background: #e4e7ec;
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
}
.button-link:hover { background: #d0d5dd; }

/* Pasek okresu w Zleceniach: strzałki przesuwają cały zakres o jego długość, a pola
   dat dają natywny kalendarz — skok do dowolnego dnia bez żadnej biblioteki. */
.daterange { display: flex; align-items: center; gap: 6px; }
.daterange input[type="date"] {
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 14px;
  background: var(--panel);
  color: var(--text);
}
.daterange input:disabled { background: var(--bg); color: var(--muted); }
.daterange-sep { color: var(--muted); }
.daterange button:disabled { opacity: .45; cursor: default; }

.searchbar { margin: 12px 0; }
.searchbar input {
  width: 100%;
  max-width: 480px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 14px;
}

/* Tryb wyszukiwania trzeba nazwać wprost — wyniki są spoza wybranego zakresu dat. */
.search-note {
  display: flex;
  align-items: center;
  gap: 10px;
  background: #eff6ff;
  border-left: 3px solid var(--info);
  border-radius: var(--radius);
  padding: 8px 12px;
  margin-bottom: 12px;
  font-size: 13px;
}

/* Skok do miesiąca w kalendarzu serwisów — natywny picker, ten sam pasek co w Zleceniach. */
.daterange input[type="month"] {
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 14px;
  background: var(--panel);
  color: var(--text);
}

/* Pole nieaktywne z powodu innego wyboru w formularzu (np. klient przy agregacie floty).
   Zostaje widoczne, żeby było wiadomo, że istnieje i dlaczego nic w nim nie ma. */
.field-off label { color: var(--muted); }
.field-off select,
.field-off input {
  background: var(--bg);
  color: var(--muted);
  cursor: not-allowed;
}

/* Panel na telefonie — sidebar, tabele i siatki kalendarza/floty się na nim psują,
   więc blokujemy go całkowicie (mobile-guard.js dodaje tę klasę na body). Reguła
   `> *:not(#mobile-block)` chowa wszystko inne bezwarunkowo, nawet gdyby coś inne
   dopisało się do body później. */
#mobile-block { display: none; }
body.is-mobile-blocked #mobile-block {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 9999;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 24px;
  background: var(--bg);
  color: var(--text);
  font-size: 18px;
  line-height: 1.5;
}
body.is-mobile-blocked > *:not(#mobile-block) { display: none !important; }

/* Lista nadchodzących serwisów pod kalendarzem. Siatka pokazuje kropki, ta lista mówi
   co, u kogo, kto jedzie i czy jest już zlecone. */
.upcoming { margin-top: 20px; }
.upcoming .card-head { margin-bottom: 10px; }
.up-row {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  background: var(--panel);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 12px;
  margin-bottom: 8px;
}
.up-row.late { border-left-color: var(--danger); }
.up-when { min-width: 110px; display: flex; flex-direction: column; gap: 2px; font-size: 13px; }
.up-what { flex: 1; font-size: 14px; }
.up-meta { font-size: 12px; color: var(--muted); margin-top: 4px; }
.up-late { color: var(--danger-dark); font-weight: 600; }
.up-bell { color: var(--info); }
.up-actions { display: flex; flex-direction: column; gap: 6px; align-items: stretch; }
.up-actions button { white-space: nowrap; }

/* Obłożenie serwisantów przy wyborze ekipy. Kolor nie niesie treści sam — obok stoi
   słowo ("wolny", "obłożony", "kolizja 08:00"). */
.avail-tag { font-size: 11px; color: var(--muted); white-space: nowrap; }
.avail-free .avail-tag { color: #15803d; font-weight: 600; }
.avail-busy .avail-tag { color: #b45309; font-weight: 600; }
.avail-conflict .avail-tag { color: var(--danger-dark); font-weight: 700; }
/* Urlop to nie "dużo roboty" — inny kolor i wyszarzony wiersz, żeby nie dało się go
   wziąć za obłożenie. */
.avail-absent { background: #f2f4f7; }
.avail-absent .avail-tag { color: #6941c6; font-weight: 700; }
.muted-row td { color: var(--muted); }
.avail-note { font-size: 12px; color: var(--muted); margin-top: 6px; }
.avail-note.avail-none { color: var(--danger-dark); font-weight: 600; }

/* Obłożenie pracowników na pulpicie. Trzy sloty = limit dzienny; liczba stoi obok,
   więc kolor tylko wzmacnia to, co i tak jest napisane słowem. */
.wl-free { font-size: 13px; margin-bottom: 10px; }
.wl-none { font-size: 13px; margin-bottom: 10px; color: var(--danger-dark); font-weight: 600; }
.wl-slots { white-space: nowrap; }
.wl-slot {
  display: inline-block;
  width: 12px; height: 12px;
  margin-right: 3px;
  border-radius: 3px;
  border: 1px solid var(--border);
  background: var(--bg);
}
.wl-slot.on { background: #f59e0b; border-color: #f59e0b; }
.wl-slots.full .wl-slot.on { background: var(--danger); border-color: var(--danger); }
.wl-legend { font-size: 12px; color: var(--muted); margin-top: 10px; line-height: 1.5; }
.wl-over { color: var(--danger-dark); font-weight: 600; }

/* Wiersz serwisanta na mapie: nazwisko, zlecenie, adres ostatniej pozycji i kiedy
   ostatnio się odezwał. Status słowem po prawej — kolor pinezki tylko go powtarza. */
.emp-name { font-weight: 600; display: flex; align-items: center; gap: 6px; }
.emp-emergency {
  font-size: 10px;
  font-weight: 700;
  color: #fff;
  background: var(--danger);
  border-radius: 4px;
  padding: 1px 5px;
}
.emp-status { font-size: 12px; font-weight: 700; white-space: nowrap; }
.emp-hint { font-size: 11px; color: var(--muted); font-style: italic; margin-top: 2px; }
.emp-legend { font-size: 11px; color: var(--muted); line-height: 1.6; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.emp-legend .emp-emergency { font-size: 10px; }

/* --------------------------------------------------------------- Flota aut
   Widok dnia: kafelek na auto, żeby "kto czym jedzie" dało się przeczytać jednym
   spojrzeniem. Zielony pasek = auto stoi wolne, szary = w trasie. */
.head-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.head-actions input[type="date"] { padding: 5px 8px; font-size: 13px; }

.fleet-day {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.fleet-card {
  border: 1px solid var(--border);
  border-left: 4px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  background: #fff;
  /* Flex z gap zamiast marginesów na dzieciach: żaden margines — ani ujemny z .hint,
     ani sklejony przy zwijaniu — nie może wtedy nasunąć jednej linijki na drugą. */
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.fleet-card > * { margin: 0; }
.fleet-card.free { border-left-color: #22c55e; }
.fleet-card.busy { border-left-color: var(--muted); }
/* Wycofane auto, które nadal wisi na zleceniach tego dnia — to jest do posprzątania,
   więc ma wyglądać jak ostrzeżenie, a nie jak zwykła pozycja floty. */
.fleet-card.retired { border-left-color: var(--danger); background: #fffbfa; }
.fleet-retired { font-size: 12px; font-weight: 600; color: var(--danger-dark); }
.fleet-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.fleet-card .plate {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  letter-spacing: 0.5px;
  background: #f2f4f7;
  border-radius: 4px;
  padding: 1px 6px;
}
.fleet-crew { font-size: 13px; }
/* Notatka o aucie to podpowiedź dla dyspozytora ("czym to jest i do czego"), a nie
   dane zlecenia. Musi się odróżniać od reszty kafelka, inaczej czyta się ją jak fakt
   z grafiku — stąd znacznik, wcięcie i tło. */
.fleet-note {
  display: flex;
  gap: 6px;
  font-size: 12px;
  font-style: italic;
  color: var(--muted);
  line-height: 1.45;
  background: #f9fafb;
  border-left: 2px solid var(--border);
  border-radius: 0 4px 4px 0;
  padding: 5px 8px;
}
.fleet-note::before {
  content: "i";
  flex: 0 0 14px;
  height: 14px;
  margin-top: 1px;
  border: 1px solid var(--muted);
  border-radius: 50%;
  font-style: normal;
  font-size: 10px;
  font-weight: 700;
  line-height: 13px;
  text-align: center;
}
/* Notatka o aucie na kafelku. Reguła .hint ma ujemny margines górny (dosuwa
   podpowiedź pod pole formularza) — tutaj wciągała tekst na listę zleceń, więc auta
   z opisem miały nachodzące na siebie linie, a te bez opisu wyglądały poprawnie. */
.fleet-card .hint,
.card > .hint,
.card > table + .hint,
p.hint { margin-top: 8px; margin-bottom: 0; }
.fleet-orders { list-style: none; margin: 0; padding: 0; font-size: 12px; }
.fleet-orders li {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  padding: 5px 0;
  border-top: 1px solid var(--border);
}
.fleet-orders .btn-move { margin-left: auto; padding: 3px 9px; font-size: 12px; }
.fleet-orders .muted { margin-right: 4px; }

/* Wybór auta w formularzu zlecenia: zajęte zostaje widoczne, ale wyszarzone —
   dyspozytor ma wiedzieć, że bus istnieje i kto go ma, a nie szukać go po liście. */
.vehicle-note { font-size: 12px; color: var(--muted); margin-top: 4px; }
.vehicle-note.taken { color: var(--danger-dark); }

/* Stan serwisu w kalendarzu. „Wykonany" nie jest już przyciskiem — serwis domyka
   zatwierdzony raport, więc pokazujemy, na czym stoi sprawa, i prowadzimy do zlecenia. */
.up-state {
  font-size: 12px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 6px;
  text-decoration: none;
  white-space: nowrap;
}
.up-state.muted { background: #e4e7ec; color: #475467; }
.up-state.warn { background: #fef0c7; color: #b54708; }
.up-state.ok { background: #dcfce7; color: #15803d; }
.up-state.danger { background: #fee4e2; color: #b42318; }

/* Serwis odhaczony ręcznie — celowo NIE zielony. Zielone jest to, co ma raport;
   ręczne odhaczenie to czyjeś słowo i ma tak wyglądać. */
.up-state.manual { background: #fef0c7; color: #93370d; border: 1px dashed #dc6803; }
.manual-note {
  font-size: 12px;
  color: #93370d;
  background: #fffaeb;
  border-left: 3px solid #dc6803;
  padding: 4px 8px;
  margin-top: 4px;
  border-radius: 0 4px 4px 0;
}

/* Zdanie pod stanem serwisu: od kiedy czekamy i na co. */
.up-detail { font-size: 12px; color: var(--muted); margin-top: 4px; line-height: 1.5; }

/* --------------------------------------------------------------- Logi
   Wiersz zmiany rozwija się w porównanie przed → po. Kolory jak w edytorze diffów:
   to, co było, wyszarzone i przekreślone, to, co jest — wyraźne. */
.log-toolbar { flex-wrap: wrap; align-items: flex-end; gap: 10px; }
.tool-field { display: flex; flex-direction: column; gap: 3px; font-size: 12px; color: var(--muted); }
.log-table td { vertical-align: top; }
.log-table .nowrap { white-space: nowrap; }
.log-count {
  display: inline-block;
  margin-left: 6px;
  font-size: 11px;
  color: var(--muted);
  border: 1px dashed var(--border);
  border-radius: 4px;
  padding: 0 5px;
}
.log-detail td { background: #f9fafb; }
.log-change { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; padding: 3px 0; font-size: 13px; }
.log-field { min-width: 130px; color: var(--muted); }
.log-before { color: var(--muted); text-decoration: line-through; }
.log-arrow { color: var(--muted); }
.log-after { font-weight: 600; }

/* ---------- Pulpit: trzy strefy ----------
   Pytania po kolei: co się pali, co jest na dziś, jak stoimy ogólnie. Nagłówek strefy
   niesie tę kolejność, bo jedenaście równorzędnych liczb nie mówiło, od czego zacząć. */
.zone { margin-bottom: 22px; }

.zone-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.zone-head h2 {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}

.zone-count {
  font-size: 11px;
  font-weight: 700;
  background: var(--danger);
  color: #fff;
  border-radius: 999px;
  padding: 2px 8px;
}

/* Brak spraw do decyzji to dobra wiadomość i ma tak wyglądać — pusty biały prostokąt
   czyta się jak awaria ładowania. */
.zone-clear {
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  border-radius: var(--radius);
  color: #15803d;
  font-size: 14px;
  padding: 14px 16px;
}

/* Sortowanie alertów: nagłówek musi wyglądać na klikalny, inaczej nikt nie spróbuje. */
.alert-table th.sortable { cursor: pointer; user-select: none; }
.alert-table th.sortable:hover { color: var(--text); text-decoration: underline; }
.alert-table .nowrap { white-space: nowrap; }
.alert-table tr.sev-high td:first-child { border-left: 3px solid var(--danger); }
.alert-table tr.sev-normal td:first-child { border-left: 3px solid var(--warn); }

/* Przypięty filtr z pulpitu: lista pokazuje wycinek, więc musi o tym mówić wprost —
   inaczej wygląda jak lista, na której brakuje zleceń. */
.pinned {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  background: #fffaeb;
  border: 1px solid #fde68a;
  border-radius: var(--radius);
  padding: 10px 14px;
  margin-bottom: 12px;
  font-size: 14px;
}

/* Skrót do raportu przy statusie „Do akceptacji": decyzja o przyjęciu roboty zaczyna
   się od przeczytania raportu, więc ma być jedno kliknięcie stąd, a nie szukanie
   po zakładce Raporty. */
.status-cell { display: flex; align-items: center; gap: 6px; }
/* Lista rozwijana bierze całą szerokość komórki, ikona ma stały slot — dzięki temu
   prawa krawędź kolumny stoi w pionie niezależnie od tego, czy zlecenie ma raport. */
.status-cell .st-select { flex: 1; min-width: 0; }
.status-cell .report-link { flex: 0 0 26px; width: 26px; height: 26px; }
.status-cell .report-link.is-empty { pointer-events: none; }
.report-link {
  display: inline-flex;
  color: var(--info);
  padding: 4px;
  border-radius: 6px;
}
.report-link:hover { background: #eff4ff; }
.report-link .nav-ico { width: 18px; height: 18px; color: currentColor; }

/* Powód niewykonania — to jest informacja o zleceniu, nie o agregacie. */
.not-done { font-size: 12px; color: var(--danger-dark); font-weight: 600; }

/* Lista zleceń: stałe szerokości kolumn, żeby dni ustawiły się w jednej linii w pionie.
   Bez table-layout: fixed każda dzienna tabela liczy szerokości z własnej treści. */
.orders-table { table-layout: fixed; }
.orders-table .c-time { width: 72px; }
.orders-table .c-prio { width: 92px; }
.orders-table .c-type { width: 16%; }
.orders-table .c-client { width: 18%; }
.orders-table .c-addr { width: 16%; }
.orders-table .c-device { width: 12%; }
.orders-table .c-crew { width: 15%; }
/* Status musi pomieścić najdłuższą pozycję listy ("Do akceptacji") plus ikonę raportu —
   ścięte "W trakc…" zmusza do zgadywania, co tam właściwie stoi. */
.orders-table .c-status { width: 178px; }
/* Przy stałym układzie długi adres bez spacji rozpychałby komórkę poza tabelę —
   ale łamanie w środku wyrazu wolno stosować tylko tam, gdzie stoi tekst. Godzina
   złamana na "08:3 / 0" to nie jest godzina. */
.orders-table td { overflow-wrap: break-word; }
.orders-table td:first-child,
.orders-table .status-cell { white-space: nowrap; }

/* Kolizje po wpisaniu urlopu: lista osieroconych zleceń z gotową podpowiedzią zastępcy.
   Ostrzegawcza ramka, bo to jest robota do wykonania teraz, a nie komunikat do zamknięcia. */
.absence-clash {
  background: #fffaeb;
  border: 1px solid #fde68a;
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 14px;
}
.clash-head { font-size: 14px; margin-bottom: 10px; }
.clash-table { background: transparent; border: none; }
.clash-table th { background: transparent; border-bottom: 1px solid #fde68a; }
.clash-table td { border-bottom: 1px solid #fde68a; vertical-align: top; }
.clash-table tr:last-child td { border-bottom: none; }
.clash-alone { color: var(--danger-dark); font-weight: 600; }
.clash-done { color: #15803d; font-weight: 600; }

/* Zdjęcie papierowego protokołu pod statusem raportu. Kadr bywa krzywy i słabo
   oświetlony, więc pokazujemy je duże, a pełny rozmiar otwiera się po kliknięciu. */
.paper-photo { margin-top: 16px; border-top: 1px solid var(--border); padding-top: 14px; }
.paper-photo-head {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}
.paper-photo img {
  display: block;
  width: 100%;
  max-height: 460px;
  object-fit: contain;
  background: #f2f4f7;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 7px);
  cursor: zoom-in;
}

/* Galeria agregatu. Domyślne 560px modala starcza na formularz, nie na siatkę zdjęć —
   poszerzamy tylko to jedno okno, zamiast dokładać parametr do openModal. */
.modal:has(.gallery-grid) { max-width: 920px; }
.modal:has(.gallery-grid) .modal-body { max-height: 76vh; overflow-y: auto; }

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
}
.gallery-tile { margin: 0; }
.gallery-img {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 160px;
  background: #f2f4f7;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 7px);
  overflow: hidden;
}
.gallery-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  cursor: zoom-in;
}
.gallery-tile figcaption {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 6px;
  font-size: 12px;
  color: var(--muted);
}
.gallery-tile figcaption .badge { align-self: flex-start; }
