/* ═══════════════════════════════════════════════════════════════════════════
   Cramer-Mühle · Zeiterfassung 3.0
   System designu — mobile-first, tryb jasny/ciemny, estetyka premium.

   Złoto jest AKCENTEM, nie tłem: pojawia się na aktywnym stanie, na jednym
   przycisku głównym w widoku i na cienkich obramowaniach. Powierzchnie niosą
   hierarchię, nie kolor.

   Tryb ciemny celuje w OLED — tło strony jest czystą czernią, więc piksele
   są wygaszone. Hierarchię budują kolejne poziomy grafitu ponad nią.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── tokeny ────────────────────────────────────────────────────────────── */

:root {
  /* skala odstępów — 4 px */
  --s-1: .25rem;  --s-2: .5rem;   --s-3: .75rem;  --s-4: 1rem;
  --s-5: 1.25rem; --s-6: 1.5rem;  --s-8: 2rem;    --s-10: 2.5rem;
  --s-12: 3rem;   --s-16: 4rem;   --s-20: 5rem;

  /* promienie */
  --r-sm: 10px;  --r-md: 14px;  --r-lg: 20px;
  --r-xl: 26px;  --r-full: 999px;

  /* typografia */
  --font: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI",
          Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-num: ui-monospace, "SF Mono", "Cascadia Mono", "Roboto Mono",
              Menlo, Consolas, monospace;

  --t-xs: .6875rem; --t-sm: .8125rem; --t-base: .9375rem;
  --t-md: 1.0625rem; --t-lg: 1.25rem; --t-xl: 1.625rem;
  --t-2xl: 2.125rem; --t-3xl: 3rem;

  --lh-tight: 1.15; --lh-normal: 1.5; --lh-loose: 1.7;
  --track-tight: -.022em; --track-wide: .08em;

  /* ruch */
  --e-out: cubic-bezier(.22, 1, .36, 1);
  --e-inout: cubic-bezier(.65, 0, .35, 1);
  --e-spring: cubic-bezier(.34, 1.56, .64, 1);
  --d-fast: 140ms; --d-base: 260ms; --d-slow: 420ms;

  /* wysokość dolnej nawigacji — potrzebna do paddingu treści */
  --nav-h: 4.25rem;
  --tap: 44px;          /* minimalne pole dotykowe */

  color-scheme: light dark;
}

/* ── tryb jasny (domyślny) ─────────────────────────────────────────────── */

:root,
:root[data-theme="light"] {
  --bg:           #F7F4EF;
  --bg-grad:      radial-gradient(1200px 600px at 15% -10%, #FFFDF8 0%, transparent 60%),
                  radial-gradient(900px 500px at 100% 0%, #F3EDE1 0%, transparent 55%);
  --surface-1:    #FFFFFFEE;
  --surface-2:    #FFFFFF;
  --surface-3:    #F2ECE1;
  --surface-glass: rgba(255, 255, 255, .72);
  --surface-sunk: #EFE9DE;

  --text:         #171512;
  --text-2:       #5C564C;
  --text-3:       #8A8377;
  --text-inv:     #FFFFFF;

  --border:       rgba(23, 21, 18, .10);
  --border-2:     rgba(23, 21, 18, .16);
  --border-gold:  rgba(166, 124, 0, .32);

  --gold:         #96700A;   /* 4.9:1 na --bg — tekst akcentowy */
  --gold-strong:  #7A5C05;
  --gold-soft:    rgba(166, 124, 0, .10);
  --gold-grad:    linear-gradient(135deg, #B98C12 0%, #8A6708 100%);
  --on-gold:      #FFFFFF;
  /* złoto marki z logo (#CB9F19 … #DCBD18) przyciemnione dla czytelności
     na kremowym tle — odcień zachowany */
  --brand-grad:   linear-gradient(115deg, #A8820E 0%, #C09A11 38%, #8E6D08 100%);

  --ok:           #1F7A4D;  --ok-soft:   rgba(31, 122, 77, .10);
  --warn:         #8A5B00;  --warn-soft: rgba(138, 91, 0, .10);
  --err:          #B02A20;  --err-soft:  rgba(176, 42, 32, .10);
  --info:         #1E5F8F;  --info-soft: rgba(30, 95, 143, .10);
  /* Kratki kalendarza nieobecności — świadomie mocniejsze niż tokeny --*-soft.
     Tamte mają 10% krycia i na białej karcie urlop był praktycznie niewidoczny;
     przy trzydziestu wierszach nie dawało się odróżnić chorobowego od
     okolicznościowego bez najeżdżania myszą. Litera w kratce rozstrzyga to
     ostatecznie, ale kolor ma nieść informację już z drugiego końca pokoju. */
  --kal-urlaub:     rgba(30, 95, 143, .34);
  --kal-krank:      rgba(176, 42, 32, .34);
  --kal-sonder:     rgba(138, 91, 0, .36);
  --kal-unbezahlt:  rgba(90, 90, 96, .30);
  --kal-litera:     #1B1B1F;

  --shadow-1: 0 1px 2px rgba(23,21,18,.05), 0 2px 8px rgba(23,21,18,.04);
  --shadow-2: 0 2px 6px rgba(23,21,18,.06), 0 10px 30px rgba(23,21,18,.07);
  --shadow-3: 0 8px 20px rgba(23,21,18,.08), 0 24px 60px rgba(23,21,18,.10);
  --shadow-gold: 0 6px 24px rgba(166,124,0,.20);

  --skeleton: linear-gradient(90deg, #E9E2D6 25%, #F4EFE6 50%, #E9E2D6 75%);
}

/* ── tryb ciemny ───────────────────────────────────────────────────────── */

:root[data-theme="dark"] {
  --bg:           #000000;               /* OLED: piksele wygaszone */
  --bg-grad:      radial-gradient(1100px 560px at 12% -12%, #14161B 0%, transparent 62%),
                  radial-gradient(800px 460px at 100% 4%, #17130B 0%, transparent 58%);
  --surface-1:    #101216;
  --surface-2:    #16191F;
  --surface-3:    #1D212A;
  --surface-glass: rgba(20, 23, 29, .66);
  --surface-sunk: #0A0B0E;

  --text:         #F2F3F5;
  --text-2:       #A7ADB8;
  --text-3:       #6F7681;
  --text-inv:     #0B0C0F;

  --border:       rgba(255, 255, 255, .09);
  --border-2:     rgba(255, 255, 255, .15);
  --border-gold:  rgba(212, 175, 55, .30);

  --gold:         #E0BC5B;   /* 9.5:1 na czerni */
  --gold-strong:  #F0D488;
  --gold-soft:    rgba(212, 175, 55, .11);
  --gold-grad:    linear-gradient(135deg, #E6C56A 0%, #B08D2A 100%);
  --on-gold:      #17130A;
  /* oryginalne złoto z logo — na czerni działa bez korekty */
  --brand-grad:   linear-gradient(115deg, #CB9F19 0%, #DCBD18 45%, #CCA019 100%);

  --ok:           #4ADE80;  --ok-soft:   rgba(74, 222, 128, .12);
  --warn:         #FBBF5A;  --warn-soft: rgba(251, 191, 90, .12);
  --err:          #FF7A70;  --err-soft:  rgba(255, 122, 112, .12);
  --info:         #6FB4EC;  --info-soft: rgba(111, 180, 236, .12);
  /* Odpowiedniki dla trybu ciemnego — na czarnym tle potrzeba innych barw
     i nieco niższego krycia, żeby litera została czytelna. */
  --kal-urlaub:     rgba(111, 180, 236, .30);
  --kal-krank:      rgba(255, 122, 112, .30);
  --kal-sonder:     rgba(251, 191, 90, .30);
  --kal-unbezahlt:  rgba(190, 190, 200, .22);
  --kal-litera:     #F2F2F4;

  --shadow-1: 0 1px 2px rgba(0,0,0,.6), 0 2px 8px rgba(0,0,0,.4);
  --shadow-2: 0 2px 8px rgba(0,0,0,.55), 0 12px 34px rgba(0,0,0,.5);
  --shadow-3: 0 10px 26px rgba(0,0,0,.6), 0 30px 70px rgba(0,0,0,.6);
  --shadow-gold: 0 6px 28px rgba(212,175,55,.16);

  --skeleton: linear-gradient(90deg, #16191F 25%, #1F242D 50%, #16191F 75%);
}

/* systemowy tryb ciemny, gdy użytkownik nie wybrał ręcznie */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #000000;
    --bg-grad: radial-gradient(1100px 560px at 12% -12%, #14161B 0%, transparent 62%),
               radial-gradient(800px 460px at 100% 4%, #17130B 0%, transparent 58%);
    --surface-1: #101216; --surface-2: #16191F; --surface-3: #1D212A;
    --surface-glass: rgba(20, 23, 29, .66); --surface-sunk: #0A0B0E;
    --text: #F2F3F5; --text-2: #A7ADB8; --text-3: #6F7681; --text-inv: #0B0C0F;
    --border: rgba(255,255,255,.09); --border-2: rgba(255,255,255,.15);
    --border-gold: rgba(212,175,55,.30);
    --gold: #E0BC5B; --gold-strong: #F0D488; --gold-soft: rgba(212,175,55,.11);
    --gold-grad: linear-gradient(135deg, #E6C56A 0%, #B08D2A 100%); --on-gold: #17130A;
    --brand-grad: linear-gradient(115deg, #CB9F19 0%, #DCBD18 45%, #CCA019 100%);
    --ok: #4ADE80; --ok-soft: rgba(74,222,128,.12);
    --warn: #FBBF5A; --warn-soft: rgba(251,191,90,.12);
    --err: #FF7A70; --err-soft: rgba(255,122,112,.12);
    --info: #6FB4EC; --info-soft: rgba(111,180,236,.12);
    /* Odpowiedniki dla trybu ciemnego — na czarnym tle potrzeba innych barw
       i nieco niższego krycia, żeby litera została czytelna. */
    --kal-urlaub:     rgba(111, 180, 236, .30);
    --kal-krank:      rgba(255, 122, 112, .30);
    --kal-sonder:     rgba(251, 191, 90, .30);
    --kal-unbezahlt:  rgba(190, 190, 200, .22);
    --kal-litera:     #F2F2F4;
    --shadow-1: 0 1px 2px rgba(0,0,0,.6), 0 2px 8px rgba(0,0,0,.4);
    --shadow-2: 0 2px 8px rgba(0,0,0,.55), 0 12px 34px rgba(0,0,0,.5);
    --shadow-3: 0 10px 26px rgba(0,0,0,.6), 0 30px 70px rgba(0,0,0,.6);
    --shadow-gold: 0 6px 28px rgba(212,175,55,.16);
    --skeleton: linear-gradient(90deg,#16191F 25%,#1F242D 50%,#16191F 75%);
  }
}

/* ── reset ─────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

/* Atrybut `hidden` MUSI wygrywać z układem.
   Przeglądarka daje mu tylko `display: none` z domyślnego arkusza, więc
   każda nasza reguła w rodzaju `.btn-icon { display: inline-grid }` go bije
   — element z hidden=true i tak się rysował. Wyszło na zrzucie ekranu:
   w polu wyboru pliku krzyżyk „usuń" stał widoczny, choć żadnego pliku nie
   było. Dotyczyło to też pasków ostrzeżeń i komunikatów walidacji.
   Stąd jedna reguła zamiast łatania każdego komponentu osobno. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-height: 100dvh;
  font-family: var(--font);
  font-size: var(--t-base);
  line-height: var(--lh-normal);
  color: var(--text);
  background: var(--bg);
  background-image: var(--bg-grad);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overscroll-behavior-y: none;
}

h1, h2, h3, h4 { margin: 0; line-height: var(--lh-tight); letter-spacing: var(--track-tight); font-weight: 650; }
p { margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; border: none; background: none; }
a { color: var(--gold); text-decoration-thickness: 1px; text-underline-offset: 2px; }
table { border-collapse: collapse; width: 100%; }
:where(ul, ol) { margin: 0; padding: 0; list-style: none; }

/* liczby zawsze tabelarycznie — kolumny czasu muszą się układać */
.num, td.num, .clock, .stat-value, .time { font-variant-numeric: tabular-nums; }

/* ── dostępność ────────────────────────────────────────────────────────── */

:focus-visible {
  outline: 2.5px solid var(--gold);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
:focus:not(:focus-visible) { outline: none; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Natywny input type=file. Ukryty, ale NIE przez display:none ani
   visibility:hidden — wtedy część przeglądarek odmawia otwarcia okna wyboru
   pliku po programowym .click(). Musi zostać w układzie, tylko niewidoczny. */
.sr-only-input {
  position: absolute; width: 1px; height: 1px; opacity: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  pointer-events: none;
}

/* Własna kontrolka pliku — zastępuje napis rysowany przez przeglądarkę
   w języku systemu telefonu. */
.file-picker {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--s-2) var(--s-2) var(--s-3);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2); min-height: 48px;
}
.file-picker .file-name {
  flex: 1; min-width: 0; font-size: var(--t-sm); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.file-picker .file-name.is-empty { color: var(--text-3); }
.file-picker:focus-within { border-color: var(--gold); box-shadow: 0 0 0 3px var(--gold-soft); }

.skip-link {
  position: absolute; top: -100px; left: var(--s-4); z-index: 200;
  background: var(--surface-2); color: var(--text);
  padding: var(--s-3) var(--s-5); border-radius: var(--r-md);
  box-shadow: var(--shadow-3); transition: top var(--d-fast) var(--e-out);
}
.skip-link:focus { top: var(--s-4); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
}

/* ── animacje ──────────────────────────────────────────────────────────── */

@keyframes fade-in   { from { opacity: 0 } to { opacity: 1 } }
@keyframes slide-up  { from { opacity: 0; transform: translate3d(0, 14px, 0) }
                       to   { opacity: 1; transform: none } }
@keyframes slide-down{ from { opacity: 0; transform: translate3d(0, -10px, 0) }
                       to   { opacity: 1; transform: none } }
@keyframes pop       { from { opacity: 0; transform: scale(.94) }
                       to   { opacity: 1; transform: scale(1) } }
@keyframes shimmer   { from { background-position: 200% 0 } to { background-position: -200% 0 } }
@keyframes spin      { to { transform: rotate(360deg) } }
@keyframes pulse-ring{ 0% { box-shadow: 0 0 0 0 var(--gold-soft) }
                       70% { box-shadow: 0 0 0 14px transparent }
                       100% { box-shadow: 0 0 0 0 transparent } }
@keyframes toast-in  { from { opacity: 0; transform: translate3d(0, 20px, 0) scale(.96) }
                       to   { opacity: 1; transform: none } }

/* pojawianie się przy przewijaniu — klasę .is-visible nadaje IntersectionObserver */
.reveal {
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  transition: opacity var(--d-slow) var(--e-out), transform var(--d-slow) var(--e-out);
  will-change: opacity, transform;
}
.reveal.is-visible { opacity: 1; transform: none; will-change: auto; }
.reveal:nth-child(2) { transition-delay: 50ms }
.reveal:nth-child(3) { transition-delay: 100ms }
.reveal:nth-child(4) { transition-delay: 150ms }
.reveal:nth-child(5) { transition-delay: 200ms }

/* ── układ ─────────────────────────────────────────────────────────────── */

.app { min-height: 100dvh; display: flex; flex-direction: column; }

.shell { display: flex; flex: 1; min-height: 0; }

.main {
  flex: 1;
  min-width: 0;
  padding: var(--s-4) var(--s-4) calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--s-6));
  max-width: 1180px;
  margin-inline: auto;
  width: 100%;
}

.stack   { display: flex; flex-direction: column; gap: var(--s-4); }
.stack-2 { display: flex; flex-direction: column; gap: var(--s-2); }
.stack-6 { display: flex; flex-direction: column; gap: var(--s-6); }
.row     { display: flex; align-items: center; gap: var(--s-3); }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.wrap    { flex-wrap: wrap; }
.grow    { flex: 1; min-width: 0; }

.grid { display: grid; gap: var(--s-3); }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-auto { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

/* ── nagłówek ──────────────────────────────────────────────────────────── */

.topbar {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: var(--s-3);
  padding: calc(env(safe-area-inset-top) + var(--s-3)) var(--s-4) var(--s-3);
  background: var(--surface-glass);
  backdrop-filter: saturate(180%) blur(18px);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  border-bottom: 1px solid var(--border);
}

.topbar-title { font-size: var(--t-md); font-weight: 650; letter-spacing: var(--track-tight); }
.topbar-sub { font-size: var(--t-xs); color: var(--text-3); letter-spacing: var(--track-wide);
              text-transform: uppercase; }

.brand { display: flex; align-items: center; gap: var(--s-3); }

/* ── logo ───────────────────────────────────────────────────────────────
   Herb i sygnet ładowane jako zewnętrzne SVG przez mask-image, nie <img>.
   Dzięki temu plik jest cache'owany raz (i wchodzi do precache w sw.js),
   a kolor bierze się z tokenu motywu — złoto marki świeci na czerni, ale
   na kremowym tle byłoby zbyt jasne, więc tryb jasny dostaje przyciemnioną
   wersję z zachowaniem odcienia.                                        */

.logo {
  display: block; flex-shrink: 0;
  background: var(--brand-grad);
  -webkit-mask: var(--logo-src) center / contain no-repeat;
          mask: var(--logo-src) center / contain no-repeat;
}
.logo-mark { --logo-src: url('/img/logo-mark-mono.svg'); aspect-ratio: 119.5 / 80; }
.logo-full { --logo-src: url('/img/logo-full-mono.svg'); aspect-ratio: 203.5 / 103.5; }

.brand-mark { height: 30px; }
.auth-logo-full { width: min(260px, 68%); margin: 0 auto var(--s-6); }
.sidebar .logo-full { width: 176px; margin-bottom: var(--s-2); }

/* Zapasowo, gdyby maska nie była wspierana — wtedy zwykły obrazek. */
@supports not ((-webkit-mask-image: url('#')) or (mask-image: url('#'))) {
  .logo { background: none; }
  .logo::after { content: ''; display: block; width: 100%; height: 100%;
                 background: var(--logo-src) center / contain no-repeat; }
  .logo-mark { --logo-src: url('/img/logo-mark.svg'); }
  .logo-full { --logo-src: url('/img/logo-full.svg'); }
}

/* ── karty ─────────────────────────────────────────────────────────────── */

.card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-5);
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--d-base) var(--e-out),
              transform var(--d-base) var(--e-out),
              border-color var(--d-base) var(--e-out);
}
.card-glass {
  background: var(--surface-glass);
  backdrop-filter: saturate(160%) blur(20px);
  -webkit-backdrop-filter: saturate(160%) blur(20px);
}
.card-accent { border-color: var(--border-gold); box-shadow: var(--shadow-1), var(--shadow-gold); }
.card-flush { padding: 0; overflow: hidden; }

.card-tap { cursor: pointer; }
.card-tap:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); border-color: var(--border-2); }
.card-tap:active { transform: translateY(0) scale(.995); }

.card-head { display: flex; align-items: center; justify-content: space-between;
             gap: var(--s-3); margin-bottom: var(--s-4); }
.card-title { font-size: var(--t-md); font-weight: 650; }
.card-sub { font-size: var(--t-sm); color: var(--text-2); margin-top: 2px; }

.section-label {
  font-size: var(--t-xs); font-weight: 600; letter-spacing: var(--track-wide);
  text-transform: uppercase; color: var(--text-3);
  margin: var(--s-6) 0 var(--s-3);
}
.section-label:first-child { margin-top: 0; }

/* ── zegar / główny panel obecności ────────────────────────────────────── */

.clock-card { text-align: center; padding: var(--s-8) var(--s-5); position: relative; overflow: hidden; }
.clock-card::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(420px 200px at 50% -20%, var(--gold-soft), transparent 70%);
  pointer-events: none;
}
.clock {
  font-size: clamp(2.75rem, 15vw, var(--t-3xl));
  font-weight: 300; letter-spacing: -.03em; line-height: 1;
  font-feature-settings: "tnum";
}
.clock-date { color: var(--text-2); font-size: var(--t-sm); margin-top: var(--s-2); }

.status-pill {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--s-4); border-radius: var(--r-full);
  font-size: var(--t-sm); font-weight: 600;
  background: var(--surface-3); color: var(--text-2);
  border: 1px solid var(--border);
}
.status-pill[data-state="working"] { background: var(--ok-soft); color: var(--ok); border-color: transparent; }
.status-pill[data-state="break"]   { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.status-pill[data-state="off"]     { background: var(--surface-3); color: var(--text-3); }

.dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.dot-live { animation: pulse-ring 2.2s var(--e-out) infinite; }

/* ── kafelki statystyk ─────────────────────────────────────────────────── */

.stat {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--s-4);
  display: flex; flex-direction: column; gap: var(--s-1);
}
.stat-label { font-size: var(--t-xs); color: var(--text-3); letter-spacing: .04em;
              text-transform: uppercase; font-weight: 600; }
.stat-value { font-size: var(--t-lg); font-weight: 650; letter-spacing: -.02em; }
.stat-value.accent { color: var(--gold); }
.stat-hint { font-size: var(--t-xs); color: var(--text-3); }

/* ── przyciski ─────────────────────────────────────────────────────────── */

.btn {
  --btn-bg: var(--surface-2);
  --btn-fg: var(--text);
  --btn-bd: var(--border-2);
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  min-height: var(--tap); padding: var(--s-3) var(--s-5);
  border-radius: var(--r-md); border: 1px solid var(--btn-bd);
  background: var(--btn-bg); color: var(--btn-fg);
  font-size: var(--t-base); font-weight: 600; letter-spacing: -.005em;
  text-align: center; white-space: nowrap;
  transition: transform var(--d-fast) var(--e-out),
              box-shadow var(--d-base) var(--e-out),
              background var(--d-fast) var(--e-out),
              opacity var(--d-fast) linear;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.btn:hover:not(:disabled) { transform: translateY(-1px); box-shadow: var(--shadow-2); }
.btn:active:not(:disabled) { transform: translateY(0) scale(.975); transition-duration: 60ms; }
.btn:disabled { opacity: .42; cursor: not-allowed; }

.btn-primary {
  --btn-bg: var(--gold-grad); --btn-fg: var(--on-gold); --btn-bd: transparent;
  box-shadow: var(--shadow-gold);
}
.btn-primary:hover:not(:disabled) { box-shadow: var(--shadow-2), var(--shadow-gold); }

.btn-ok     { --btn-bg: var(--ok-soft);   --btn-fg: var(--ok);   --btn-bd: transparent; }
.btn-danger { --btn-bg: var(--err-soft);  --btn-fg: var(--err);  --btn-bd: transparent; }
.btn-warn   { --btn-bg: var(--warn-soft); --btn-fg: var(--warn); --btn-bd: transparent; }
.btn-ghost  { --btn-bg: transparent;      --btn-fg: var(--text-2); --btn-bd: transparent; }
.btn-ghost:hover:not(:disabled) { --btn-bg: var(--surface-3); box-shadow: none; }

.btn-lg { min-height: 58px; font-size: var(--t-md); border-radius: var(--r-lg); padding-inline: var(--s-6); }
.btn-sm { min-height: 36px; padding: var(--s-2) var(--s-3); font-size: var(--t-sm); border-radius: var(--r-sm); }
.btn-block { width: 100%; }

/* przycisk-ikona — zawsze z aria-label, nazwa dostępna nie może zniknąć */
.btn-icon {
  min-height: var(--tap); min-width: var(--tap); padding: 0;
  border-radius: var(--r-md); border: 1px solid transparent;
  display: inline-grid; place-items: center; color: var(--text-2);
  background: transparent;
  transition: background var(--d-fast) var(--e-out), color var(--d-fast) var(--e-out),
              transform var(--d-fast) var(--e-out);
}
.btn-icon:hover { background: var(--surface-3); color: var(--text); }
.btn-icon:active { transform: scale(.9); }
.btn-icon.danger:hover { background: var(--err-soft); color: var(--err); }
.btn-icon.ok:hover { background: var(--ok-soft); color: var(--ok); }

/* fala przy kliknięciu */
.btn .ripple {
  position: absolute; border-radius: 50%; transform: scale(0);
  background: currentColor; opacity: .22; pointer-events: none;
  animation: ripple-out 560ms var(--e-out) forwards;
}
@keyframes ripple-out { to { transform: scale(2.6); opacity: 0 } }

.icon { width: 20px; height: 20px; flex-shrink: 0; stroke-width: 1.75;
        transition: transform var(--d-base) var(--e-spring); }
.icon-sm { width: 16px; height: 16px; }
.btn:hover .icon, .btn-icon:hover .icon { transform: scale(1.08); }

/* ── nawigacja dolna (telefon) ─────────────────────────────────────────── */

.navbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  display: flex; align-items: stretch;
  padding: var(--s-2) var(--s-2) calc(env(safe-area-inset-bottom) + var(--s-2));
  background: var(--surface-glass);
  backdrop-filter: saturate(180%) blur(22px);
  -webkit-backdrop-filter: saturate(180%) blur(22px);
  border-top: 1px solid var(--border);
}
.navbar-item {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; padding: var(--s-2) var(--s-1); min-height: 56px;
  border-radius: var(--r-md); color: var(--text-3);
  font-size: var(--t-xs); font-weight: 600;
  position: relative;
  transition: color var(--d-fast) var(--e-out), background var(--d-fast) var(--e-out);
  -webkit-tap-highlight-color: transparent;
}
.navbar-item span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.navbar-item:active { background: var(--surface-3); }
.navbar-item[aria-current="page"] { color: var(--gold); }
.navbar-item[aria-current="page"] .icon { transform: translateY(-1px) scale(1.06); }
.navbar-item[aria-current="page"]::before {
  content: ''; position: absolute; top: 2px; left: 50%; translate: -50% 0;
  width: 22px; height: 3px; border-radius: var(--r-full); background: var(--gold);
  animation: pop var(--d-base) var(--e-spring);
}

.nav-badge {
  position: absolute; top: 4px; left: calc(50% + 8px);
  min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: var(--r-full); background: var(--err); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 17px; text-align: center;
}

/* ── sidebar (tablet i desktop) ────────────────────────────────────────── */

.sidebar { display: none; }

@media (min-width: 900px) {
  .navbar { display: none; }
  .main { padding-bottom: var(--s-10); padding-inline: var(--s-8); }

  .sidebar {
    display: flex; flex-direction: column; gap: var(--s-1);
    width: 258px; flex-shrink: 0;
    padding: var(--s-5) var(--s-3);
    border-right: 1px solid var(--border);
    background: var(--surface-glass);
    backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
    position: sticky; top: 0; height: 100dvh; overflow-y: auto;
  }
  .sidebar-item {
    display: flex; align-items: center; gap: var(--s-3);
    padding: var(--s-3) var(--s-4); border-radius: var(--r-md);
    color: var(--text-2); font-size: var(--t-base); font-weight: 550;
    text-align: left; width: 100%; min-height: var(--tap);
    transition: background var(--d-fast) var(--e-out), color var(--d-fast) var(--e-out);
  }
  .sidebar-item:hover { background: var(--surface-3); color: var(--text); }
  .sidebar-item[aria-current="page"] {
    background: var(--gold-soft); color: var(--gold); font-weight: 650;
    box-shadow: inset 2px 0 0 var(--gold);
  }
  .sidebar-badge {
    margin-left: auto; min-width: 20px; height: 20px; padding: 0 6px;
    border-radius: var(--r-full); background: var(--err); color: #fff;
    font-size: 11px; font-weight: 700; line-height: 20px; text-align: center;
  }
  .sidebar-foot { margin-top: auto; padding-top: var(--s-4); border-top: 1px solid var(--border); }
}

@media (min-width: 1200px) { .main { padding-inline: var(--s-10); } }

/* ── formularze ────────────────────────────────────────────────────────── */

.field { display: flex; flex-direction: column; gap: var(--s-2); }
.label { font-size: var(--t-sm); font-weight: 600; color: var(--text-2); }
.hint { font-size: var(--t-xs); color: var(--text-3); }

.input, .select, .textarea {
  width: 100%; min-height: var(--tap);
  padding: var(--s-3) var(--s-4);
  background: var(--surface-2);
  border: 1.5px solid var(--border-2);
  border-radius: var(--r-md);
  color: var(--text); font-size: var(--t-base);
  transition: border-color var(--d-fast) var(--e-out),
              box-shadow var(--d-fast) var(--e-out),
              background var(--d-fast) var(--e-out);
  appearance: none;
}
.input::placeholder, .textarea::placeholder { color: var(--text-3); }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--gold);
  box-shadow: 0 0 0 3.5px var(--gold-soft);
}
.input[aria-invalid="true"], .select[aria-invalid="true"] {
  border-color: var(--err); box-shadow: 0 0 0 3.5px var(--err-soft);
}
.textarea { min-height: 96px; resize: vertical; line-height: var(--lh-normal); }

.select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238A8377' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right var(--s-4) center;
  background-size: 18px; padding-right: var(--s-10);
}
:root[data-theme="dark"] .select,
:root:not([data-theme="light"]) .select { }

.input-group { position: relative; display: flex; align-items: center; }
.input-group .input { padding-left: var(--s-10); }
.input-group .input-icon {
  position: absolute; left: var(--s-4); color: var(--text-3);
  pointer-events: none; display: grid; place-items: center;
  transition: color var(--d-base) var(--e-out);
}
.input-group:focus-within .input-icon { color: var(--gold); }
.input-group .input-action {
  position: absolute; right: var(--s-2);
  min-height: 36px; min-width: 36px; border-radius: var(--r-sm);
  display: grid; place-items: center; color: var(--text-3);
}
.input-group .input-action:hover { color: var(--text); background: var(--surface-3); }
.input-group:has(.input-action) .input { padding-right: var(--s-12); }

.error-text {
  display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--t-sm); color: var(--err);
  animation: slide-down var(--d-base) var(--e-out);
}

/* przełącznik */
.switch { display: flex; align-items: center; gap: var(--s-3); min-height: var(--tap); cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch-track {
  width: 48px; height: 28px; border-radius: var(--r-full); flex-shrink: 0;
  background: var(--surface-3); border: 1px solid var(--border-2);
  position: relative; transition: background var(--d-base) var(--e-out),
                                  border-color var(--d-base) var(--e-out);
}
.switch-thumb {
  position: absolute; top: 2px; left: 2px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--text-3);
  transition: transform var(--d-base) var(--e-spring), background var(--d-base) var(--e-out);
}
.switch input:checked + .switch-track { background: var(--gold-soft); border-color: var(--gold); }
.switch input:checked + .switch-track .switch-thumb { transform: translateX(20px); background: var(--gold); }
.switch input:focus-visible + .switch-track { outline: 2.5px solid var(--gold); outline-offset: 2px; }

/* pole wyboru — używane m.in. dla noclegu w kabinie */
.check {
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-4); min-height: var(--tap);
  background: var(--surface-2); border: 1.5px solid var(--border-2);
  border-radius: var(--r-md); cursor: pointer;
  transition: border-color var(--d-fast) var(--e-out), background var(--d-fast) var(--e-out);
}
.check:hover { border-color: var(--border-gold); }
.check:has(input:checked) { border-color: var(--gold); background: var(--gold-soft); }
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check-box {
  width: 22px; height: 22px; border-radius: 7px; flex-shrink: 0; margin-top: 1px;
  border: 2px solid var(--border-2); display: grid; place-items: center;
  color: transparent;
  transition: background var(--d-fast) var(--e-out), border-color var(--d-fast) var(--e-out),
              color var(--d-fast) var(--e-out);
}
.check:has(input:checked) .check-box { background: var(--gold); border-color: var(--gold); color: var(--on-gold); }
.check:has(input:focus-visible) { outline: 2.5px solid var(--gold); outline-offset: 2px; }
.check-title { font-weight: 600; font-size: var(--t-base); }
.check-desc { font-size: var(--t-sm); color: var(--text-2); margin-top: 2px; }

/* segmentowany przełącznik (np. wybór motywu, języka) */
.segment {
  display: inline-flex; padding: 3px; gap: 2px;
  background: var(--surface-3); border-radius: var(--r-md);
  border: 1px solid var(--border);
}
.segment button {
  padding: var(--s-2) var(--s-4); min-height: 38px; border-radius: 11px;
  font-size: var(--t-sm); font-weight: 600; color: var(--text-2);
  transition: background var(--d-base) var(--e-out), color var(--d-base) var(--e-out);
}
.segment button[aria-pressed="true"] {
  background: var(--surface-1); color: var(--text); box-shadow: var(--shadow-1);
}

/* ── tabele / listy danych ─────────────────────────────────────────────── */

.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: var(--r-lg); }

.table { font-size: var(--t-sm); min-width: 100%; }
.table th {
  text-align: left; font-size: var(--t-xs); font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase; color: var(--text-3);
  padding: var(--s-3) var(--s-3); border-bottom: 1px solid var(--border);
  white-space: nowrap; position: sticky; top: 0;
  background: var(--surface-1); backdrop-filter: blur(8px);
}
.table td { padding: var(--s-3); border-bottom: 1px solid var(--border); vertical-align: middle; }
.table tbody tr { transition: background var(--d-fast) linear; }
.table tbody tr:hover { background: var(--surface-3); }
.table tbody tr:last-child td { border-bottom: none; }
.table .right { text-align: right; }
.table .center { text-align: center; }
.table tr.is-holiday { background: var(--warn-soft); }
.table tr.is-holiday:hover { background: var(--warn-soft); filter: brightness(1.04); }

/* ── arkusz miesiąca (3.11) ────────────────────────────────────────────────

   Wiersz na każdy dzień, także pusty. CAŁY wiersz jest przyciskiem — nie
   ikonka po prawej: przy trzydziestu jeden wierszach na telefonie cel
   wielkości ikony trafia się co trzeci raz, a ta lista istnieje właśnie po to,
   żeby w nią klikać.

   Kolor NIE jest jedyną informacją o stanie dnia: w prawej kolumnie stoi
   odznaka ze słowem („Fehlt", „Urlaub", „Offene Schicht"). Ta sama zasada co
   przy liście obecności w 3.9.                                              */

.blatt-tabela tbody tr { cursor: pointer; }
.blatt-tabela tbody tr:focus-visible {
  outline: 2px solid var(--gold); outline-offset: -2px;
}

/* Dzień roboczy bez odbicia i bez nieobecności — to jest ta dziura do
   wypełnienia. Lewy pasek, nie samo tło: na wydruku i przy słabym kontraście
   ekranu w kabinie tło potrafi zniknąć. */
.blatt-fehlt { background: var(--err-soft); }
.blatt-fehlt td:first-child { box-shadow: inset 3px 0 0 var(--err); }

/* Urlop, chorobowe i reszta — dzień wyjaśniony, nie brakujący. */
.blatt-abwesend { background: var(--info-soft); }

/* SWOISTOŚĆ, nie ozdoba: `.table tbody tr:hover` wyżej w tym pliku ma (0,2,2)
   i wygrywa ze zwykłym `.blatt-fehlt:hover` (0,2,0). Skutek zmierzony w
   przeglądarce: wiersz pod kursorem — czyli ten, na który kadry właśnie patrzą
   i który zaraz klikną — tracił kolor mówiący, że to brak. Pełny selektor
   z `.table` i `tbody` podnosi swoistość ponad tamtą regułę. */
.table.blatt-tabela tbody tr.blatt-fehlt:hover {
  background: var(--err-soft); filter: brightness(1.05);
}
.table.blatt-tabela tbody tr.blatt-abwesend:hover {
  background: var(--info-soft); filter: brightness(1.05);
}

/* Sobota, niedziela, święto i dzień, który jeszcze nie nadszedł.
   Wyszarzone, ale nadal klikalne — kierowca bywa w sobotę w trasie. */
.blatt-frei td, .blatt-zukunft td { color: var(--text-3); }
.blatt-frei .blatt-dzien, .blatt-zukunft .blatt-dzien { color: var(--text-3); }

.blatt-data { white-space: nowrap; }
.blatt-dzien { font-weight: 650; color: var(--text-2); margin-right: 2px; }
.blatt-uwaga { min-width: 120px; }

/* Resturlaub: liczba stoi w KAŻDYM wierszu, ale wyróżniona tylko tam, gdzie
   spadła. Wzrok łapie wtedy same dni urlopu, a stan na dowolny dzień miesiąca
   nadal da się odczytać bez szukania. */
.blatt-urlop-spadek { font-weight: 650; color: var(--info); }

/* PASEK ZAKRESU NA PULPICIE musi sie ZAWIJAC.

   Do 3.14.1 byly trzy przyciski i miescily sie obok tytulu. Czwarty
   („Biezacy miesiac") rozpycha wiersz do 465 px, a telefon ma 390 —
   dokument zaczynal wystawac poza ekran i cala strona jechala w bok.
   Zlapane testem `test:pulpit-ui`, ktory mierzy `scrollWidth`. */
.pulpit-zakres { flex-wrap: wrap; gap: var(--s-2); }
.pulpit-zakres > .row { flex-wrap: wrap; }

/* ── ZMIANA NOCNA ──────────────────────────────────────────────────────────

   „+1" przy godzinie wyjścia. Bez tego znaku wiersz „21:56 | 11:04" czyta się
   jak wyjście PRZED wejściem tego samego dnia — Roman odczytał tak prawdziwy
   wiersz z produkcji i zrozumiał go odwrotnie. Znak jest MAŁY, ale stoi tuż
   przy liczbie, bo dopiero razem z nią coś znaczy. */
.naechster-tag {
  margin-left: 3px; padding: 0 3px;
  font-size: .68em; font-weight: 700; line-height: 1.5;
  color: var(--gold-strong); background: var(--gold-soft);
  border-radius: 3px; vertical-align: top;
}

/* Dzień, w którym kierowca pracował, ale wejście odbił poprzedniego wieczoru.
   Strzałka mówi „to przyszło z wczoraj" — godziny wejścia tego dnia nie było
   i nie wolno jej udawać. */
/* Godziny odcinków — jedna linia na odcinek. Dzień kierowcy nocnego ma
   zwykle dwa: to, co przyszło z wczoraj (00:00 – 11:00), i to, co zaczął
   dziś wieczorem (21:58 – 24:00). Wiersz rośnie wtedy o linijkę i tak ma
   być: dwie liczby w jednej linijce zlewałyby się w jedną. */
.odcinki { white-space: nowrap; line-height: 1.45; }
.odcinek + .odcinek { margin-top: 1px; }

/* Delikatne tło całego wiersza — dzień bez własnego wejścia inaczej wygląda
   po prostu na pusty. SWOISTOŚĆ jak przy `.blatt-fehlt` wyżej: pełny selektor
   z `.table` i `tbody`, bo `.table tbody tr:hover` (0,2,2) wygrałoby ze zwykłą
   klasą i kolor znikałby dokładnie pod kursorem. */
.blatt-nacht { background: var(--gold-soft); }
.blatt-nacht td:first-child { box-shadow: inset 3px 0 0 var(--gold); }
.table.blatt-tabela tbody tr.blatt-nacht:hover {
  background: var(--gold-soft); filter: brightness(1.05);
}

/* ── okno jednego dnia ─────────────────────────────────────────────────── */

.dzien-stan {
  display: flex; flex-direction: column; gap: var(--s-1);
  padding: var(--s-3); margin-bottom: var(--s-3);
  border-radius: var(--r-md); background: var(--surface-3);
}
.dzien-info {
  display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--t-sm); color: var(--text-2);
}

.dzien-zakladki {
  display: flex; gap: var(--s-1); margin-bottom: var(--s-4);
  padding: 3px; border-radius: var(--r-full); background: var(--surface-3);
}
.dzien-zakladka {
  flex: 1; padding: var(--s-2) var(--s-3); border: none; cursor: pointer;
  border-radius: var(--r-full); background: transparent; color: var(--text-2);
  font-size: var(--t-sm); font-weight: 650; font-family: inherit;
  transition: background var(--d-fast) linear, color var(--d-fast) linear;
}
.dzien-zakladka:hover { color: var(--text); }
/* Aktywna zakładka musi być widoczna NA PIERWSZY RZUT OKA. Przy samej różnicy
   tła (surface na surface-3) obie wyglądały na zrzucie niemal identycznie,
   a od tego, która jest wybrana, zależy, co się zapisze: godziny czy urlop. */
.dzien-zakladka.is-aktywna {
  background: var(--surface); color: var(--gold);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .12);
}

.dzien-zmiany { margin-bottom: var(--s-4); }

/* Stopka okna dnia: „Zamknij" po lewej, zapis po prawej i szeroki.
   Slot wypełnia się przy każdym przełączeniu zakładki — inaczej stopka
   musiałaby znać obie zakładki naraz. */
.dzien-zapisz { flex: 1; display: flex; }
.dzien-zapisz .btn { width: 100%; }

/* Godzina poprawiona przez kadry.
   Bez tego znaku w tabeli stała sama poprawiona wartość i nie dało się jej
   odróżnić od godziny wbitej przez kierowcę — a przy kontroli czasu pracy
   pyta się dokładnie o tę różnicę. Pierwotna godzina i notatka siedzą
   w atrybucie title. */
.table td.korrigiert { position: relative; white-space: nowrap; }
.korr-punkt {
  display: inline-block; width: 5px; height: 5px; margin-left: 5px;
  /* `var(--gold)`, nie `var(--brand)`: zmiennej `--brand` nie ma w kodzie
     i nigdy nie było, więc `background` był nieprawidłowy i kropka NIE
     RYSOWAŁA SIĘ WCALE. Skutek: w tabeli kadr stała sama poprawiona godzina,
     bez znaku odróżniającego ją od godziny wbitej przez kierowcę — czyli
     dokładnie to, czemu ta kropka miała zapobiegać. */
  border-radius: 50%; background: var(--gold); vertical-align: 2px;
}

/* Dzień wpisany przez kadry za kierowcę (bo nie miał telefonu).
   Inny znak niż złota kropka korekty, bo to jest inna rzecz: tam kadry
   POPRAWIŁY godziny kierowcy, tu dnia w ogóle nie było. Kwadrat, nie kółko —
   różnicę widać kątem oka, a nie po porównaniu odcieni. */
.table td.erfasst { position: relative; white-space: nowrap; }
.erfasst-punkt {
  display: inline-block; width: 5px; height: 5px; margin-left: 5px;
  border-radius: 1px; background: var(--info); vertical-align: 2px;
}

/* ── blokada wymuszonej aktualizacji ──────────────────────────────────────

   Zakrywa WSZYSTKO, łącznie z ekranem logowania i dolnym paskiem nawigacji.
   Nie ma przycisku zamknięcia i nie ma go mieć — decyzja kierownika floty
   brzmiała: kierowca dostaje informację i musi zaktualizować.

   Tło jest pełne, nie półprzezroczyste: przez przezroczystą warstwę widać
   przyciski odbicia, a widoczny przycisk zaprasza do prób dotknięcia. */
.upgrade-gate {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; align-items: center; justify-content: center;
  padding: var(--s-5);
  background: var(--bg);
  overscroll-behavior: contain;
}
.upgrade-box {
  width: 100%; max-width: 380px;
  display: flex; flex-direction: column; gap: var(--s-4);
  text-align: center;
}
.upgrade-logo { width: 72px; height: 72px; margin: 0 auto; }
.upgrade-title { font-size: var(--t-xl); font-weight: 700; line-height: 1.2; }
.upgrade-text { font-size: var(--t-sm); color: var(--text-2); line-height: 1.5; }
.upgrade-wersje {
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-lg); text-align: left;
}

/* ── kalendarz nieobecności ────────────────────────────────────────────────

   Siatka: kierowcy w wierszach, dni miesiąca w kolumnach. Kolumny są wąskie
   celowo — trzydzieści jeden dni ma zmieścić się na jednym ekranie laptopa,
   bo cała wartość tego widoku polega na tym, że miesiąc widać naraz. Na
   telefonie tabela przewija się w poziomie (.table-wrap), a kolumna
   z nazwiskiem zostaje przyklejona do lewej krawędzi — inaczej po przewinięciu
   do 20. dnia nie wiadomo, czyj to wiersz. */
.kal-grid { border-collapse: separate; border-spacing: 0; }
.kal-grid th, .kal-grid td { padding: 0; border-bottom: 1px solid var(--border); }
.kal-grid .kal-name {
  position: sticky; left: 0; z-index: 1;
  background: var(--surface-2);
  padding: var(--s-2) var(--s-3);
  min-width: 148px; max-width: 148px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-size: var(--t-xs); text-align: left; font-weight: 500;
  text-transform: none; letter-spacing: 0;
}
.kal-grid thead .kal-name { z-index: 2; }
.kal-grid .kal-day {
  width: 22px; min-width: 22px;
  padding: var(--s-2) 0; text-align: center;
  font-size: 10px; font-variant-numeric: tabular-nums; font-weight: 600;
  letter-spacing: 0;
}
.kal-grid .kal-cell { width: 22px; min-width: 22px; height: 26px; }
.kal-grid td.kal-frei { background: var(--surface-3); }
/* Dzisiejsza kolumna — kadry najczęściej szukają właśnie jej. */
.kal-grid th.kal-heute { color: var(--gold); box-shadow: inset 0 -2px 0 var(--gold); }
.kal-grid tbody tr:hover .kal-name { background: var(--surface-3); }

.kal-holiday { background: var(--kal-urlaub); }
.kal-sick    { background: var(--kal-krank); }
.kal-special { background: var(--kal-sonder); }
.kal-unpaid  { background: var(--kal-unbezahlt); }
.kal-other   { background: var(--surface-3); }

/* Litera w kratce. Sam kolor nie wystarcza: nie odróżni go osoba
   nierozróżniająca barw, gubi się na wydruku i znika przy patrzeniu z boku
   na ekran laptopa. Litera rozstrzyga jednoznacznie. */
.kal-litera {
  display: block; text-align: center;
  font-size: 10px; font-weight: 700; line-height: 26px;
  color: var(--kal-litera); letter-spacing: -.02em;
}

/* Pusty dzień jest klikalny — kadry wpisują nieobecność wprost z siatki,
   bez przepisywania nazwiska i daty do osobnego formularza. */
.kal-pusta { cursor: pointer; }
.kal-pusta:hover { background: var(--gold-soft); }
.kal-pusta:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }
/* Wniosek jeszcze nierozpatrzony — ten sam kolor, ale w paski, żeby nie dało
   się go pomylić z urlopem już przyznanym. */
.kal-offen {
  background-image: repeating-linear-gradient(
    45deg, transparent 0 3px, rgba(127, 127, 127, .38) 3px 5px);
}
.kal-probe {
  display: inline-block; width: 14px; height: 14px; border-radius: 3px;
  border: 1px solid var(--border-2); flex-shrink: 0;
}

/* lista kart — układ mobilny zamiast tabeli */
.record {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-4); border-bottom: 1px solid var(--border);
  transition: background var(--d-fast) linear;
}
.record:last-child { border-bottom: none; }
.record:hover { background: var(--surface-3); }
.record-main { flex: 1; min-width: 0; }
.record-title { font-weight: 600; font-size: var(--t-base); }
.record-meta { font-size: var(--t-sm); color: var(--text-2); margin-top: 2px; }
.record-value { text-align: right; font-weight: 650; flex-shrink: 0; }

/* ── odznaki ───────────────────────────────────────────────────────────── */

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px var(--s-3); border-radius: var(--r-full);
  font-size: var(--t-xs); font-weight: 650; white-space: nowrap;
  background: var(--surface-3); color: var(--text-2);
}
.badge-ok   { background: var(--ok-soft);   color: var(--ok); }
.badge-warn { background: var(--warn-soft); color: var(--warn); }
.badge-err  { background: var(--err-soft);  color: var(--err); }
.badge-info { background: var(--info-soft); color: var(--info); }
.badge-gold { background: var(--gold-soft); color: var(--gold); }

/* ── kto jest w pracy (3.9) ────────────────────────────────────────────────

   Sam kolor nie może być jedyną informacją — kropka ma `title`, a obok
   stoi odznaka ze słowem. Kierowca floty z daltonizmem nie jest przypadkiem
   teoretycznym, a lista i tak musi się dać czytać na słońcu.               */

.anwesend-punkt {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  margin-right: 8px; flex-shrink: 0; vertical-align: baseline;
  background: var(--text-3, #888);
}
.anwesend-punkt.is-arbeit { background: var(--ok); }
.anwesend-punkt.is-pause  { background: var(--warn); }
.anwesend-punkt.is-frei   { background: var(--err); }

.anwesend-summe {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-4);
  font-size: var(--t-sm); color: var(--text-2);
  padding: 0 var(--s-4) var(--s-2);
}
.anwesend-summe .anwesend-punkt { margin-right: 4px; }

/* Słowo o stanie w wierszu danych. Pogrubione, bo jest pierwsze i ma się
   odczytać przed nazwą użytkownika, która stoi zaraz obok. */
.anwesend-slowo { font-weight: 650; }
.anwesend-slowo.is-arbeit { color: var(--ok); }
.anwesend-slowo.is-pause  { color: var(--warn); }
.anwesend-slowo.is-frei   { color: var(--text-3); }

/* ── modale ────────────────────────────────────────────────────────────── */

.modal-backdrop {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: end center;
  background: rgba(0, 0, 0, .5);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  animation: fade-in var(--d-base) var(--e-out);
  padding: 0;
}
.modal-backdrop[hidden] { display: none; }

.modal {
  width: 100%; max-width: 560px; max-height: 92dvh;
  display: flex; flex-direction: column;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: var(--shadow-3);
  animation: slide-up var(--d-slow) var(--e-out);
  padding-bottom: env(safe-area-inset-bottom);
}
.modal::before {
  content: ''; display: block; width: 38px; height: 4px; flex-shrink: 0;
  margin: var(--s-3) auto var(--s-1); border-radius: var(--r-full);
  background: var(--border-2);
}
.modal-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3); padding: var(--s-4) var(--s-5) var(--s-3);
}
.modal-title { font-size: var(--t-lg); font-weight: 650; }
.modal-body { padding: 0 var(--s-5) var(--s-5); overflow-y: auto; flex: 1;
              display: flex; flex-direction: column; gap: var(--s-4); }
.modal-foot {
  display: flex; gap: var(--s-3); padding: var(--s-4) var(--s-5);
  border-top: 1px solid var(--border);
}
.modal-foot .btn { flex: 1; }

@media (min-width: 640px) {
  .modal-backdrop { place-items: center; padding: var(--s-6); }
  .modal { border-radius: var(--r-xl); border-bottom: 1px solid var(--border);
           animation: pop var(--d-base) var(--e-out); max-height: 86dvh; }
  .modal::before { display: none; }
  .modal-head { padding-top: var(--s-5); }
}

/* ── powiadomienia ─────────────────────────────────────────────────────── */

.toast-wrap {
  position: fixed; z-index: 150;
  left: var(--s-4); right: var(--s-4);
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--s-3));
  display: flex; flex-direction: column; gap: var(--s-2);
  pointer-events: none;
}
@media (min-width: 900px) {
  .toast-wrap { left: auto; right: var(--s-6); bottom: var(--s-6); width: 380px; }
}

.toast {
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-4); border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--border-2);
  box-shadow: var(--shadow-3);
  animation: toast-in var(--d-base) var(--e-out);
  pointer-events: auto;
}
.toast.leaving { animation: fade-in var(--d-base) var(--e-out) reverse forwards; }
.toast-icon { flex-shrink: 0; margin-top: 1px; }
.toast-body { flex: 1; min-width: 0; font-size: var(--t-sm); }
.toast-title { font-weight: 650; }
.toast-ok   { border-left: 3px solid var(--ok); }
.toast-ok   .toast-icon { color: var(--ok); }
.toast-err  { border-left: 3px solid var(--err); }
.toast-err  .toast-icon { color: var(--err); }
.toast-warn { border-left: 3px solid var(--warn); }
.toast-warn .toast-icon { color: var(--warn); }
.toast-info { border-left: 3px solid var(--info); }
.toast-info .toast-icon { color: var(--info); }

/* pasek offline */
.offline-bar {
  position: fixed; left: 0; right: 0; z-index: 140;
  top: 0;
  display: flex; align-items: center; justify-content: center; gap: var(--s-2);
  padding: calc(env(safe-area-inset-top) + 6px) var(--s-4) 6px;
  background: var(--warn); color: #1A1206;
  font-size: var(--t-sm); font-weight: 650;
  animation: slide-down var(--d-base) var(--e-out);
}
.offline-bar[hidden] { display: none; }

/* pasek aktualizacji

   Osobny od paska offline i na przeciwnym końcu ekranu, bo oba potrafią wypaść
   naraz: kierowca wraca w zasięg, kolejka odbić się wysyła i przy tej samej
   okazji dojeżdża nowa wersja aplikacji.

   Na telefonie siedzi NAD dolną nawigacją — zakrycie przycisków „Heute"
   i „Verlauf" paskiem, którego nikt nie prosił, byłoby gorsze od samej starej
   wersji. Na szerokim ekranie nawigacji na dole nie ma, więc idzie do
   samej krawędzi. */
.update-bar {
  position: fixed; left: 0; right: 0; z-index: 59;
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom));
  display: flex; align-items: center; justify-content: center; gap: var(--s-2);
  padding: 10px var(--s-4);
  border: 0; width: 100%;
  background: var(--accent); color: #041018;
  font-family: inherit; font-size: var(--t-sm); font-weight: 650;
  cursor: pointer;
  animation: slide-up var(--d-base) var(--e-out);
}
.update-bar[hidden] { display: none; }
.update-bar:active { filter: brightness(0.94); }

@keyframes slide-up { from { opacity: 0; transform: translate3d(0, 10px, 0) }
                      to   { opacity: 1; transform: none } }

@media (min-width: 900px) {
  .update-bar { bottom: 0; padding-bottom: calc(env(safe-area-inset-bottom) + 10px); }
}

/* ── stany ładowania ───────────────────────────────────────────────────── */

.skeleton {
  background: var(--skeleton); background-size: 200% 100%;
  animation: shimmer 1.4s linear infinite;
  border-radius: var(--r-sm); color: transparent !important;
}
.skeleton-line { height: 12px; margin: 6px 0; }
.skeleton-line.w-40 { width: 40% } .skeleton-line.w-60 { width: 60% }
.skeleton-line.w-80 { width: 80% } .skeleton-line.w-100 { width: 100% }

.spinner {
  width: 18px; height: 18px; flex-shrink: 0;
  border: 2.5px solid currentColor; border-right-color: transparent;
  border-radius: 50%; animation: spin .7s linear infinite; opacity: .85;
}
.spinner-lg { width: 30px; height: 30px; border-width: 3px; }

.empty {
  display: flex; flex-direction: column; align-items: center; gap: var(--s-3);
  padding: var(--s-12) var(--s-5); text-align: center; color: var(--text-3);
}
.empty .icon { width: 40px; height: 40px; opacity: .5; }
.empty-title { font-weight: 600; color: var(--text-2); font-size: var(--t-base); }

/* ── ekran logowania ───────────────────────────────────────────────────── */

.auth {
  min-height: 100dvh; display: grid; place-items: center;
  padding: var(--s-6) var(--s-5);
  padding-top: calc(env(safe-area-inset-top) + var(--s-6));
  position: relative; overflow: hidden;
}
.auth::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(620px 320px at 50% 8%, var(--gold-soft), transparent 68%);
  animation: fade-in 1.1s var(--e-out);
}
.auth-inner { width: 100%; max-width: 400px; position: relative; z-index: 1;
              animation: slide-up var(--d-slow) var(--e-out); }
.auth-logo {
  width: 64px; height: 64px; margin: 0 auto var(--s-5);
  border-radius: var(--r-lg); display: grid; place-items: center;
  background: var(--gold-grad); color: var(--on-gold);
  font-size: var(--t-lg); font-weight: 700;
  box-shadow: var(--shadow-gold), var(--shadow-2);
}
.auth-title { text-align: center; font-size: var(--t-xl); }
.auth-sub {
  text-align: center; color: var(--text-3); margin-top: var(--s-2);
  font-size: var(--t-xs); letter-spacing: var(--track-wide); text-transform: uppercase;
}

/* Pięć równych kafelków w jednym rzędzie.
   Przy pełnych nazwach języków (Deutsch, Polski, Русский, Română, Bosanski)
   rząd się zawijał i ostatni przycisk zostawał sam pod spodem — wyglądało to
   jak błąd układu. Kody są równej długości, więc grid o pięciu kolumnach
   trzyma je w linii nawet na 320 px. Bez flex-wrap: nie ma czego zawijać. */
.lang-row {
  display: grid; grid-template-columns: repeat(5, 1fr);
  gap: var(--s-2); max-width: 320px; margin-inline: auto;
}
.lang-btn {
  min-height: 44px; padding: var(--s-2);
  border-radius: var(--r-sm); border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text-2);
  font-size: var(--t-sm); font-weight: 700; letter-spacing: 0.04em;
  transition: all var(--d-fast) var(--e-out);
}
.lang-btn:hover { border-color: var(--border-gold); color: var(--text); }
.lang-btn[aria-pressed="true"] { background: var(--gold-soft); color: var(--gold); border-color: var(--gold); }

.divider { display: flex; align-items: center; gap: var(--s-4); color: var(--text-3); font-size: var(--t-xs); }
.divider::before, .divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }

/* ── podpis ────────────────────────────────────────────────────────────── */

.sign-pad {
  width: 100%; height: auto; aspect-ratio: 5 / 2; display: block;
  background: var(--surface-2); border: 1.5px dashed var(--border-2);
  border-radius: var(--r-md); touch-action: none; cursor: crosshair;
}
.sign-pad:focus-visible { border-color: var(--gold); border-style: solid; }

/* ── pojazdy ───────────────────────────────────────────────────────────── */

.vehicle-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: var(--s-2); }
.vehicle {
  min-height: 56px; padding: var(--s-3);
  border-radius: var(--r-md); border: 1.5px solid var(--border-2);
  background: var(--surface-2); color: var(--text);
  font-size: var(--t-sm); font-weight: 650; font-variant-numeric: tabular-nums;
  transition: all var(--d-fast) var(--e-out);
}
/* „Leihfahrzeug" jest dwa razy dłuższe od numeru rejestracyjnego i przy
   minmax(104px) wychodziło poza kafelek. Zmniejszamy sam napis zamiast
   rozpychać siatkę — numery mają zostać w równym rzędzie. */
.vehicle { line-height: 1.15; overflow-wrap: anywhere; }
.vehicle.vehicle-long { font-size: var(--t-xs); letter-spacing: -0.01em; }
.vehicle:hover { border-color: var(--border-gold); transform: translateY(-1px); }
.vehicle[aria-pressed="true"] {
  background: var(--gold-soft); border-color: var(--gold); color: var(--gold);
  box-shadow: var(--shadow-gold);
}

/* ── pomocnicze ────────────────────────────────────────────────────────── */

.muted { color: var(--text-2); }
.dim { color: var(--text-3); }
.accent { color: var(--gold); }
.ok-text { color: var(--ok); }
.err-text { color: var(--err); }
.warn-text { color: var(--warn); }
.small { font-size: var(--t-sm); }
.xs { font-size: var(--t-xs); }
.bold { font-weight: 650; }
.center-text { text-align: center; }
.nowrap { white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mt-auto { margin-top: auto; }
.hidden { display: none !important; }

.page { animation: slide-up var(--d-base) var(--e-out); }
.page[hidden] { display: none; }

/* pasek przewijania — dyskretny, żeby nie psuł estetyki */
@media (min-width: 900px) {
  * { scrollbar-width: thin; scrollbar-color: var(--border-2) transparent; }
  *::-webkit-scrollbar { width: 10px; height: 10px; }
  *::-webkit-scrollbar-track { background: transparent; }
  *::-webkit-scrollbar-thumb {
    background: var(--border-2); border-radius: var(--r-full);
    border: 3px solid transparent; background-clip: content-box;
  }
  *::-webkit-scrollbar-thumb:hover { background: var(--text-3); background-clip: content-box; }
}

/* druk — HR drukuje zestawienia */
@media print {
  .navbar, .sidebar, .topbar, .toast-wrap, .btn, .offline-bar { display: none !important; }
  body { background: #fff; color: #000; }
  .card { box-shadow: none; border: 1px solid #ccc; break-inside: avoid; }
  .main { padding: 0; max-width: none; }
}

/* Pasek wyjaśniający, dlaczego eksport jest wyłączony.
   Wyszarzony przycisk bez powodu wygląda jak awaria — a tu chodzi o regułę:
   raport powstaje dopiero po zamknięciu miesiąca. */
.hint-box {
  display: flex; align-items: center; gap: var(--s-2);
  margin-top: var(--s-3); padding: var(--s-3);
  border-radius: var(--r-md); border: 1px solid var(--border);
  background: var(--surface-3); color: var(--text-2);
  font-size: var(--t-sm); line-height: 1.4;
}
.hint-box .icon { flex: none; color: var(--gold); }

/* Pasek zachęcający do instalacji.
   Kierowca dostaje link i ma z niego zrobić aplikację z ikoną. Przeglądarka
   umie to sama, ale chowa propozycję w menu pod trzema kropkami — stąd własny
   pasek nad dolną nawigacją. Znika po instalacji albo po odrzuceniu. */
.install-bar {
  position: fixed; left: var(--s-3); right: var(--s-3);
  bottom: calc(var(--nav-h) + var(--s-3) + env(safe-area-inset-bottom, 0px));
  z-index: 90;
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-3) var(--s-3) var(--s-4);
  border-radius: var(--r-lg); border: 1px solid var(--border-gold);
  background: var(--surface-glass); backdrop-filter: blur(14px) saturate(1.3);
  box-shadow: var(--shadow-3);
  opacity: 0; transform: translateY(12px);
  transition: opacity var(--d-base) var(--e-out), transform var(--d-base) var(--e-out);
}
.install-bar.is-visible { opacity: 1; transform: none; }
.install-bar .install-icon {
  flex: none; width: 34px; height: 34px; border-radius: 9px;
  background: var(--brand-grad);
}
.install-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.install-text strong { font-size: var(--t-sm); }
.install-text .small { color: var(--text-2); line-height: 1.3; }

@media (min-width: 900px) {
  .install-bar { left: auto; right: var(--s-6); bottom: var(--s-6); max-width: 420px; }
}
@media (prefers-reduced-motion: reduce) {
  .install-bar { transition: none; opacity: 1; transform: none; }
}

/* ── zdjęcie profilowe (3.6) ──────────────────────────────────────────────
   Kółko przy nazwisku na ekranie Konta. Gdy zdjęcia nie ma, w środku stoją
   inicjały — pusty szary krążek wygląda jak niedoładowany obrazek i kierowcy
   zgłaszaliby go jako usterkę.

   `object-fit: cover` jest tu obowiązkowe: zdjęcia z telefonu bywają pionowe
   i poziome, a bez tego jedne byłyby ściśnięte, a drugie rozciągnięte. */
.awatar {
  width: 48px;
  height: 48px;
  flex: 0 0 48px;
  border-radius: 50%;
  background: var(--gold-soft);
  color: var(--gold);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 15px;
  overflow: hidden;
  user-select: none;
}
.awatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ── rozmowy (3.7) ─────────────────────────────────────────────────────────

   Do 3.6 skrzynka była listą pism i tak wyglądała. Rozmowa musi wyglądać jak
   rozmowa — kierowcy znają ten układ z komunikatorów w telefonie i to jedyny
   wzorzec, którego nie trzeba im tłumaczyć.

   Złoto zostaje akcentem, zgodnie z zasadą u góry pliku: własny dymek dostaje
   złote TŁO O NISKIM KRYCIU i złotą krawędź, nie złotą płaszczyznę. Napis
   w środku zostaje kolorem tekstu, żeby kontrast trzymał się w obu trybach. */

.rozmowa-wiersz {
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.rozmowa-wiersz:last-child { border-bottom: none; }
.rozmowa-tresc { flex: 1; min-width: 0; }

/* Licznik nieprzeczytanych. Ten sam czerwony co odznaka przy zakładce —
   kierowca ma skojarzyć kropkę w pasku z konkretnym wierszem na liście. */
.licznik-nowych {
  flex-shrink: 0;
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: var(--r-full);
  background: var(--err); color: #fff;
  font-size: var(--t-xs); font-weight: 700; line-height: 20px; text-align: center;
}

.czat { display: flex; flex-direction: column; gap: var(--s-3); }

.czat-naglowek {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) 0 var(--s-3);
  border-bottom: 1px solid var(--border);
}
/* Awatar w nagłówku jest mniejszy niż na liście — na telefonie 390 px pełne
   48 px razem z przyciskiem powrotu zabierały nazwisku połowę szerokości. */
.czat-naglowek .awatar { width: 38px; height: 38px; flex: 0 0 38px; font-size: 13px; }
.czat-nazwa { font-weight: 650; font-size: var(--t-md); }

.czat-strumien { display: flex; flex-direction: column; gap: var(--s-2); }
.czat-pusto { text-align: center; padding: var(--s-8) var(--s-4); }

.czat-dzien {
  display: flex; align-items: center; justify-content: center;
  margin: var(--s-3) 0 var(--s-1);
}
.czat-dzien span {
  padding: 2px var(--s-3);
  border-radius: var(--r-full);
  background: var(--surface-sunk);
  color: var(--text-3);
  font-size: var(--t-xs); font-weight: 600;
}

.czat-dymek {
  max-width: 85%;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-lg);
  background: var(--surface-3);
  border: 1px solid transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Adres, numer rejestracyjny albo długie słowo bez spacji rozpychały dymek
     poza ekran — na telefonie kończyło się to poziomym przewijaniem strony. */
  overflow-wrap: anywhere;
}
.czat-dymek.jego { align-self: flex-start; border-bottom-left-radius: var(--r-sm); }
.czat-dymek.moj {
  align-self: flex-end;
  border-bottom-right-radius: var(--r-sm);
  background: var(--gold-soft);
  border-color: var(--border-gold);
}
/* Pismo z biura — to, co ma temat. Złota krawędź z boku odróżnia je od zdania
   napisanego w rozmowie, także gdy przyjdzie w środku wątku. */
.czat-dymek.pismo {
  border-left: 3px solid var(--gold);
  border-radius: var(--r-md);
  background: var(--surface-2);
  box-shadow: var(--shadow-1);
}
.czat-temat { font-weight: 650; margin-bottom: var(--s-1); }
.czat-tresc { white-space: pre-wrap; line-height: var(--lh-normal); }

.czat-stopka-dymka {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--s-1);
  margin-top: var(--s-1);
  color: var(--text-3);
}
.czat-godzina { font-size: var(--t-xs); font-variant-numeric: tabular-nums; }
.czat-ptaszki { color: var(--text-3); }
/* Dwa ptaszki na złoto dopiero po odczytaniu. Kolor NIE jest tu jedynym
   nośnikiem informacji — kształt ikony zmienia się z jednego ptaszka na dwa,
   więc czytelne jest to także dla kierowcy rozróżniającego kolory słabiej. */
.czat-ptaszki-widziane { color: var(--gold); }

.czat-znika {
  margin-top: var(--s-1);
  font-size: var(--t-xs);
  color: var(--text-3);
}

.czat-dymek.czat-nieudany {
  background: var(--err-soft);
  border-color: var(--err);
  cursor: default;
}

/* Pole pisania trzyma się dołu ekranu, ale NIE jest `fixed`: przy `fixed`
   klawiatura ekranowa na Androidzie zasłaniała pole, w które kierowca właśnie
   pisał. `sticky` zostaje w przepływie strony i przewija się razem z nią,
   a przeglądarka sama dosuwa je nad klawiaturę. */
.czat-stopka {
  position: sticky;
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: flex-end; gap: var(--s-2);
  padding: var(--s-3) 0;
  background: var(--bg);
  border-top: 1px solid var(--border);
}
.czat-stopka-blokada { justify-content: center; text-align: center; }
.czat-pole {
  flex: 1; min-width: 0;
  resize: none;
  max-height: 140px;
  line-height: var(--lh-normal);
}
.czat-stopka .btn-icon.primary {
  flex-shrink: 0;
  width: var(--tap); height: var(--tap);
  background: var(--gold-grad); color: var(--on-gold);
  border-radius: var(--r-full);
}

@media (min-width: 900px) {
  /* Na desktopie dolnej nawigacji nie ma — pole pisania siada przy krawędzi. */
  .czat-stopka { bottom: 0; }
  .czat-dymek { max-width: 70%; }
}

/* ── załączniki (3.7) ──────────────────────────────────────────────────── */

/* Pasek z wybranym plikiem stoi NAD polem pisania i jest przyklejony razem
   z nim — inaczej kierowca, który dodał zdjęcie i zaczął pisać dłuższy tekst,
   traciłby z oczu to, co właśnie zamierza wysłać. */
.czat-stopka-blok {
  position: sticky;
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom, 0px));
  background: var(--bg);
}
.czat-stopka-blok .czat-stopka { position: static; }

.czat-zalacznik-pasek { padding-top: var(--s-2); }
.czat-zalacznik-wybrany {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--border-gold);
  border-radius: var(--r-md);
  background: var(--gold-soft);
}
.czat-zalacznik-mini {
  width: 40px; height: 40px; flex: 0 0 40px;
  object-fit: cover; border-radius: var(--r-sm);
}
.czat-zalacznik-ikona {
  width: 40px; height: 40px; flex: 0 0 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm); background: var(--surface-3); color: var(--text-2);
}

/* Zdjęcie w dymku. `max-height` jest tu ważniejsze niż wygląda: bez niego
   pionowe zdjęcie z telefonu zajmuje cztery ekrany i reszta rozmowy znika
   z oczu. Kierowca dotyka miniatury, żeby pobrać pełny plik.

   `contain`, NIE `cover` — sprawdzone na zrzucie z uruchomionego ekranu.
   Przy `cover` pionowe zdjęcie listu przewozowego było przycinane w połowie
   i kierowca widział górę dokumentu bez podpisu na dole, nie mając powodu
   przypuszczać, że czegoś nie widzi. Puste pasy po bokach przy szerokim
   zdjęciu są mniejszym złem niż ucięty dokument. */
.czat-obraz-przycisk {
  display: block; padding: 0; margin-bottom: var(--s-2);
  background: none; border: none; cursor: pointer;
  border-radius: var(--r-md); overflow: hidden;
  -webkit-tap-highlight-color: transparent;
}
.czat-obraz {
  display: block; width: 100%; max-height: 280px;
  object-fit: contain; background: var(--surface-sunk);
}

.czat-plik {
  display: flex; align-items: center; gap: var(--s-3);
  width: 100%; margin-bottom: var(--s-2);
  padding: var(--s-3);
  border: 1px solid var(--border-2); border-radius: var(--r-md);
  background: var(--surface-2); color: inherit; text-align: left; cursor: pointer;
}
.czat-plik:hover { border-color: var(--border-gold); }

/* ── skanowanie (3.7) ─────────────────────────────────────────────────── */

.skan-lista { display: flex; flex-direction: column; gap: var(--s-2); }
.skan-strona {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2);
}
/* Ramka o stałych wymiarach — strona obrócona o 90° nie może przestawiać
   wysokości całego wiersza przy każdym dotknięciu strzałki. */
.skan-ramka {
  width: 64px; height: 84px; flex: 0 0 64px;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; border-radius: var(--r-sm); background: var(--surface-sunk);
}
.skan-mini { max-width: 100%; max-height: 100%; display: block; }
.skan-opis { flex: 1; min-width: 0; display: flex; align-items: center;
             justify-content: space-between; gap: var(--s-2); }

/* ── pulpit obciążenia (3.8) ───────────────────────────────────────────────

   Wykresy są tu z divów, nie z biblioteki: kilkadziesiąt kilobajtów do
   pobrania przez każdy telefon przy każdym wydaniu, za pięć poziomych słupków
   w panelu, który otwierają dwie osoby w firmie. */

.pulpit-alarm {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-4);
  border-radius: var(--r-md);
  margin-bottom: var(--s-4);
  font-weight: 600;
}
.pulpit-alarm-zly { background: var(--err-soft); color: var(--err); border: 1px solid var(--err); }
.pulpit-alarm-ok  { background: var(--ok-soft);  color: var(--ok);  border: 1px solid var(--ok); }

.pulpit-wiersz {
  width: 100%; text-align: left; background: none; border: none;
  border-bottom: 1px solid var(--border); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.pulpit-wiersz:last-child { border-bottom: none; }

/* Wiersz poniżej minimum. Czerwony pasek z boku, NIE samo czerwone tło —
   kolor nigdy nie jest u nas jedynym nośnikiem informacji, a sama wartość
   godzinowa obok i tak rozstrzyga. */
.pulpit-zly { border-left: 3px solid var(--err); background: var(--err-soft); }

.pulpit-brak { opacity: .55; }

/* Kierowcy bez drugiej zmiany — zwinięci pod jedną linijką. Rozwinięci
   zajmowali cały ekran i trzeba było przez nich przewijać do zestawień. */
.pulpit-bez-pomiaru,
.pulpit-pelny-zakres { padding: var(--s-3) var(--s-4); border-top: 1px solid var(--border); }
.pulpit-bez-pomiaru > summary,
.pulpit-pelny-zakres > summary {
  cursor: pointer; font-size: var(--t-sm); color: var(--text-2);
  list-style: none;
}
.pulpit-bez-pomiaru > summary::-webkit-details-marker,
.pulpit-pelny-zakres > summary::-webkit-details-marker { display: none; }
.pulpit-bez-pomiaru > summary::before,
.pulpit-pelny-zakres > summary::before {
  content: '▸'; display: inline-block; width: 1em; color: var(--text-3);
}
.pulpit-bez-pomiaru[open] > summary::before,
.pulpit-pelny-zakres[open] > summary::before { content: '▾'; }

/* Wiersz z zerem. Od 3.9 słupki pokazują WSZYSTKICH aktywnych, także tych,
   którzy w tym okresie nie jeździli — zero też jest odpowiedzią. Żeby nie
   udawało wyniku: bez słupka i wyszarzone. */
.pulpit-slupek-zero { opacity: .55; }
.pulpit-slupek-zero .pulpit-slupek-wartosc { color: var(--text-3); }

/* Wykres roczny — dwanaście pionowych słupków. Pionowe, bo to oś CZASU:
   poziome słupki czyta się jako ranking, a tu chodzi o przebieg. */
.trend {
  display: flex; align-items: flex-end; gap: var(--s-1);
  height: 190px;
}
.trend-kolumna {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center;
  height: 100%;
}
.trend-wartosc {
  font-size: var(--t-xs); font-family: var(--font-num);
  color: var(--text-3); line-height: 1.2; min-height: 1.2em;
}
/* Tor rośnie w górę, więc słupek trzyma się DOŁU kolumny. */
.trend-tor {
  flex: 1; width: 100%;
  display: flex; align-items: flex-end;
  background: var(--surface-sunk);
  border-radius: var(--r-sm);
  overflow: hidden;
}
.trend-slupek { width: 100%; background: var(--gold-grad); border-radius: var(--r-sm); }
.trend-etykieta {
  margin-top: var(--s-1);
  font-size: var(--t-xs); color: var(--text-2); font-weight: 600;
}
.trend-rok { font-size: 9px; color: var(--text-3); min-height: 11px; }

@media (max-width: 520px) {
  /* Na telefonie dwanaście słupków to około 26 px na kolumnę — liczba godzin
     nad słupkiem przestaje się mieścić i zawija, rozjeżdżając wysokości. */
  .trend { height: 150px; }
  .trend-wartosc { display: none; }
}

/* ── przycisk „więcej" w dolnym pasku (3.8) ───────────────────────────────
   Do 3.8 ekrany bez `primary` nie miały na telefonie ŻADNEGO wejścia —
   sidebar pojawia się dopiero od 900 px. Kierowca nie mógł podpisać miesiąca,
   a kadry nie widziały wiadomości. */

.wiecej-pozycja {
  display: flex; align-items: center; gap: var(--s-3);
  width: 100%; text-align: left;
  padding: var(--s-4);
  background: none; border: none;
  border-bottom: 1px solid var(--border);
  color: inherit; font-size: var(--t-base); font-weight: 600;
  cursor: pointer;
}
.wiecej-pozycja:last-child { border-bottom: none; }
.wiecej-pozycja:active { background: var(--surface-3); }
/* Odznaka w liście stoi w przepływie, a nie nad ikoną jak w pasku. */
.wiecej-odznaka { position: static; flex-shrink: 0; }

.pulpit-wartosc {
  flex-shrink: 0;
  font-family: var(--font-num);
  font-weight: 650;
  font-size: var(--t-md);
  font-variant-numeric: tabular-nums;
}
.pulpit-wartosc-zla { color: var(--err); }

.pulpit-slupek-wiersz { display: flex; align-items: center; gap: var(--s-3); }
.pulpit-slupek-nazwa { flex: 0 0 34%; font-size: var(--t-sm); }
.pulpit-slupek-tor {
  flex: 1; min-width: 0; height: 12px;
  background: var(--surface-sunk);
  border-radius: var(--r-full);
  overflow: hidden;
}
.pulpit-slupek {
  height: 100%;
  background: var(--gold-grad);
  border-radius: var(--r-full);
}
.pulpit-slupek-wartosc {
  flex: 0 0 auto; min-width: 62px; text-align: right;
  font-family: var(--font-num); font-size: var(--t-sm);
  font-variant-numeric: tabular-nums; color: var(--text-2);
}

@media (max-width: 520px) {
  /* Na telefonie nazwisko i słupek nie mieszczą się obok siebie czytelnie. */
  .pulpit-slupek-wiersz { flex-wrap: wrap; }
  .pulpit-slupek-nazwa { flex: 1 1 100%; }
  .pulpit-slupek-tor { flex: 1 1 auto; }
}
