/* ==========================================================================
   aplikacja.css — komponenty własne, których Bootstrap nie ma (etap U1).

   Granica wobec `motyw.css`: tam mieszkają nadpisania zmiennych Bootstrapa,
   tutaj klasy, które w Bootstrapie nie istnieją. Wartości — wyłącznie tokeny
   z `_tokeny.css`, ani jednej liczby ani koloru wpisanego na sztywno.

   Nazwy klas są polskie, tak jak nazwy szablonów i makr. Wyjątkiem są klasy
   Bootstrapa, których nie tłumaczymy (`nav-link`, `modal-header`, `btn`).

   Komponenty ekranów pracy — komórka lejka, karta wpisu, pasek stanu firmy —
   dochodzą w etapach U3–U5. Tutaj jest tylko to, czego potrzebuje rama
   i jedenaście istniejących szablonów.
   ========================================================================== */

/* ==========================================================================
   1. Odnośnik „przejdź do treści"

   Widoczny dopiero po dojściu klawiaturą. Bez niego każde wejście z klawiatury
   zaczyna się od przejścia przez cały pasek nawigacji.
   ========================================================================== */

.skok-do-tresci {
  position: absolute;
  left: var(--odstep-2);
  top: var(--odstep-2);
  z-index: 1100;
  padding: var(--odstep-2) var(--odstep-3);
  background-color: var(--tlo);
  color: var(--tekst);
  border: 2px solid var(--tekst);
  border-radius: var(--promien);
  transform: translateY(-200%);
}

.skok-do-tresci:focus-visible {
  transform: translateY(0);
}

/* ==========================================================================
   2. Stała rama strony — sekcja 4.1 spisu parytetu

   Pasek przyklejony do góry, pod nim obszar komunikatów, treść, stopka
   `Helper - aplikacja do mierzenia konwersji.`
   ========================================================================== */

.pasek-marki {
  background-color: var(--marka);
  box-shadow: var(--cien-paska);
}

.pasek-marki .navbar-brand {
  color: var(--tekst-na-marce);
  font-weight: 700;
  letter-spacing: 0.06em;
}

/* Bez przezroczystości, i to jest ODSTĘPSTWO OD PROTOTYPU, świadome.
   Prototyp przygasza nieaktywne pozycje `opacity: 0.92`. Biel wygaszona do 92%
   na tle marki daje **4.41:1**, czyli poniżej progu 4.5:1 dla zwykłego tekstu
   (SC 1.4.3) — a to najczęściej czytany napis w całej aplikacji. Pełna biel daje
   5.00:1. Pozycję bieżącą i tak poznaje się po pogrubieniu i podkreśleniu, nie po
   jasności, więc przygaszanie nic nie niosło poza utratą kontrastu. */
.pasek-marki .nav-link,
.pasek-marki .przycisk-menu {
  color: var(--tekst-na-marce);
}

.pasek-marki .nav-link:hover,
.pasek-marki .nav-link:focus-visible,
.pasek-marki .przycisk-menu:hover,
.pasek-marki .przycisk-menu:focus-visible {
  color: var(--tekst-na-marce);
  text-decoration: underline;
}

/* Pozycja bieżąca: pogrubienie i podkreślenie, nigdy sam kolor (SC 1.4.1).
   W znaczniku towarzyszy im `aria-current="page"`. */
.pasek-marki .nav-link.aktywna {
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 0.3em;
}

/* Pierścień skupienia na tle marki: ciemny pierścień na czerwonym paska nie
   byłby widoczny. Biały daje 5.00:1 wobec marki (SC 1.4.11 wymaga 3:1). */
.pasek-marki :focus-visible {
  outline-color: var(--pierscien-na-marce);
}

/* `Wyloguj` jest przyciskiem wysyłającym POST, a wygląda jak pozycja menu:
   Django od wersji 5.1 nie wypuszcza wylogowania metodą GET, a wygląd paska
   jest parytetem. Zmienia się mechanika, nie wygląd. */
.przycisk-menu {
  background: none;
  border: 0;
  padding: var(--odstep-2);
  font: inherit;
  cursor: pointer;
}

.pasek-marki .navbar-toggler {
  border-color: var(--obwodka-dekoracyjna);
}

/* Ikona „hamburgera" Bootstrapa jest ciemna i na czerwonym pasku znika.
   Odwrócenie filtrem, a nie podmiana obrazka: obrazek to adres `data:` z kolorem
   wpisanym w środku, a koloru w adresie `data:` nie da się wziąć z tokenu. */
.pasek-marki .navbar-toggler-icon {
  filter: invert(1) grayscale(1) brightness(2);
}

.stopka {
  background-color: var(--tlo-ciche);
  border-top: 1px solid var(--obwodka-dekoracyjna);
  color: var(--tekst-cichy);
  font-size: var(--krok-tekstu-maly);
  padding-block: var(--odstep-3);
  text-align: center;
}

/* ==========================================================================
   3. Karty i szerokości treści
   ========================================================================== */

.karta {
  background-color: var(--tlo);
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: var(--promien);
  box-shadow: var(--cien-karty);
  padding: var(--odstep-4);
}

.karta-waska {
  max-width: var(--szerokosc-formularza);
  margin-inline: auto;
}

.tresc-waska {
  max-width: var(--szerokosc-tresci);
  margin-inline: auto;
}

.legenda {
  font-size: var(--krok-tekstu-duzy);
  font-weight: 600;
  margin-bottom: var(--odstep-3);
  padding-bottom: var(--odstep-2);
  border-bottom: 1px solid var(--obwodka-dekoracyjna);
}

/* ==========================================================================
   3a. Dwie kolumny ekranu konta — dołożone w U2

   Przeniesione z `docs/prototypy-ui/motyw.css` (blok `.kolumny-konta`), bez
   zmian poza tym komentarzem. Sekcja 1.11 spisu parytetu: `Zaktualizuj swoje
   informacje` po lewej, `Zaktualizuj hasło` po prawej.

   Numer „3a", a nie „4": kolejne sekcje mają numery, które są w tym pliku
   punktem odniesienia dla komentarzy w szablonach — przenumerowanie ich
   rozjechałoby te odwołania bez żadnej zmiany w wyglądzie.

   Jedna kolumna do 62em (992 px, próg `lg` Bootstrapa), dwie powyżej. Grid,
   a nie `row`/`col` Bootstrapa: obie karty mają wtedy równą wysokość bez
   dokładania klasy `h-100`, a kolejność czytania przez czytnik ekranu jest ta
   sama co kolejność w znaczniku.
   ========================================================================== */

.kolumny-konta {
  display: grid;
  gap: var(--odstep-4);
  grid-template-columns: 1fr;
}

@media (min-width: 62em) {
  .kolumny-konta {
    grid-template-columns: 1fr 1fr;
  }
}

/* ==========================================================================
   3b. Dwie kolumny strony startowej i znak firmowy — dołożone w U3

   Przeniesione z `docs/prototypy-ui/motyw.css` (blok `.kolumny-powitania`),
   bez zmian poza tym komentarzem. Sekcja 4.5 punkt 1 spisu parytetu: po lewej
   `Witaj w aplikacji Helper!` i logo, po prawej formularz dziennego sukcesu.

   Próg jest **inny niż przy `.kolumny-konta`** (48em zamiast 62em) i nie jest
   to niekonsekwencja: tam obie kolumny to formularze z polami pełnej
   szerokości, a tu lewa kolumna jest obrazkiem 361 px szerokości, więc dwie
   kolumny mieszczą się wcześniej.

   ZNAK FIRMOWY: plik `img/logo.png` przeniesiony z 1.0 bajt w bajt, wymiary
   własne 361 × 140. `max-width: 100%` z `height: auto` pilnują, żeby na wąskim
   ekranie skalował się zamiast rozpychać stronę — Bootstrap Reboot nie robi
   tego samo z siebie, robi to dopiero klasa `.img-fluid`, której 1.0 nie ma.
   ========================================================================== */

.kolumny-powitania {
  display: grid;
  gap: var(--odstep-4);
  grid-template-columns: 1fr;
}

@media (min-width: 48em) {
  .kolumny-powitania {
    grid-template-columns: 1fr 1fr;
  }
}

.znak-firmowy {
  height: auto;
  max-width: 100%;
}

/* ==========================================================================
   3c. Panel menedżera na stronie startowej — dołożone w U3

   Przeniesione z `docs/prototypy-ui/motyw.css` (bloki `.kolumny-panelu`
   i `.pasek-kontekstu`), bez zmian poza tym komentarzem. Sekcja 4.5 punkt 3
   spisu parytetu: po lewej lista `Wybierz użytkownika`, po prawej zakres dat
   i `Usuń wpisy`.

   PASEK KONTEKSTU (dodatek 5 z sekcji 7 planu) mówi, czyje dane widać. Wybór
   z listy żyje w sesji i filtruje trzy ekrany (sekcja 5.4), a w 1.0 nie widać
   tego nigdzie poza dopiskiem w nagłówku lejka — czyli menedżer patrzy na cudze
   dane, nie mając tego powiedzianego wprost. Pasek dostanie to samo miejsce
   w lejku (U4) i w CRM (U5), dlatego styl stoi tutaj, a nie przy ekranie.

   Gruba krawędź po lewej, a nie samo tło: pasek ma się odróżniać od komunikatu
   flash także wtedy, gdy oba stoją nad sobą. Kolor nie niesie tu znaczenia sam
   (SC 1.4.1) — niesie je ikona i treść zdania.

   OKNO W TREŚCI (`.okno-w-tresci`) to krok potwierdzenia przy `Usuń wpisy`.
   Nie jest nakładką: liczby w nim muszą pochodzić z serwera, więc jest
   osobnym żądaniem i osobnym stanem ekranu, a nie oknem otwieranym klikiem
   (uzasadnienie w `helper.successes.views._preview_purge`). Wygląda jak okno
   potwierdzenia z sekcji 8, bo jest tą samą rozmową z użytkownikiem.
   ========================================================================== */

.kolumny-panelu {
  display: grid;
  gap: var(--odstep-4);
  grid-template-columns: 1fr;
}

@media (min-width: 48em) {
  .kolumny-panelu {
    grid-template-columns: 1fr 1fr;
  }
}

.pasek-kontekstu {
  align-items: flex-start;
  background-color: var(--informacja-tlo);
  border: 1px solid var(--informacja);
  border-left-width: 4px;
  border-radius: var(--promien);
  color: var(--informacja);
  display: flex;
  gap: var(--odstep-2);
  margin-bottom: var(--odstep-4);
  padding: var(--odstep-3);
}

.pasek-kontekstu > .ikona {
  flex: 0 0 auto;
}

.pasek-kontekstu strong {
  color: var(--informacja);
}

.pasek-kontekstu p:last-child {
  margin-bottom: 0;
}

.okno-w-tresci {
  background-color: var(--tlo-ciche);
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: var(--promien);
  padding: var(--odstep-4);
  /* Pasek nawigacji jest przyklejony do góry, więc skok odsyłaczem `#potwierdzenie`
     (krok potwierdzenia w lejku) chowałby nagłówek pytania POD paskiem. Zapas jest
     wyższy od paska, żeby nad pytaniem został jeszcze margines — inaczej wygląda ono
     na przycięte. Sprawdzone w przeglądarce, U4. */
  scroll-margin-top: 5rem;
}

.okno-w-tresci h3 {
  align-items: center;
  display: flex;
  gap: var(--odstep-2);
}

.okno-w-tresci dl {
  display: grid;
  gap: var(--odstep-1) var(--odstep-3);
  grid-template-columns: 1fr;
  margin-bottom: var(--odstep-3);
}

@media (min-width: 30em) {
  .okno-w-tresci dl {
    grid-template-columns: auto 1fr;
  }
}

.okno-w-tresci dt {
  color: var(--tekst-cichy);
  font-weight: 400;
}

.okno-w-tresci dd {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  margin: 0;
}

/* ==========================================================================
   4. Formularze — części, których Bootstrap nie ma

   `.podpowiedz-pola` zamiast `.form-text`: podpowiedź do hasła jest listą
   warunków wyliczoną z `AUTH_PASSWORD_VALIDATORS`, a `.form-text` nie
   przewiduje listy w środku.
   ========================================================================== */

.podpowiedz-pola {
  color: var(--tekst-cichy);
  font-size: var(--krok-tekstu-maly);
  margin-top: var(--odstep-1);
}

.podpowiedz-pola ul {
  margin: var(--odstep-1) 0 0;
  padding-left: 1.25rem;
}

/* Podsumowanie błędów nad formularzem — luka 4 spisu parytetu. Przy 24 polach
   ankiety PROSPECT (U5) sam czerwony obrys pola nie wystarcza, bo pole
   z błędem może być poza ekranem. */
.podsumowanie-bledow {
  background-color: var(--blad-tlo);
  border: 1px solid var(--blad);
  border-left-width: 4px;
  border-radius: var(--promien);
  color: var(--tekst);
  padding: var(--odstep-3);
  margin-bottom: var(--odstep-4);
}

.podsumowanie-bledow h2 {
  color: var(--blad);
  font-size: var(--krok-tekstu);
  font-weight: 700;
  margin-bottom: var(--odstep-2);
}

.podsumowanie-bledow ul {
  margin-bottom: 0;
  padding-left: 1.25rem;
}

.podsumowanie-bledow a {
  color: var(--blad);
}

/* ==========================================================================
   4a. Ekrany kont dołożone w U2 — sekret, kod QR, kody zapasowe, kroki,
       pole kodu jednorazowego

   Pięć bloków przeniesionych z `docs/prototypy-ui/motyw.css` (sekcja 7 tamtego
   pliku), bez zmian poza tym komentarzem i poza jedną rzeczą wypisaną przy
   `.ramka-qr`. Numer „4a", a nie „5": kolejne sekcje mają numery, które są
   punktem odniesienia dla komentarzy w szablonach, więc przenumerowanie ich
   rozjechałoby te odwołania bez żadnej zmiany w wyglądzie. Ta sama zasada co
   przy sekcji „3a".

   Wszystkie pięć istnieje dlatego, że polityka CSP `default-src 'self'` bez
   `unsafe-inline` (D7) nie wykona atrybutu `style` — każda z tych rzeczy
   w prototypie ma klasę, a nie atrybut, i tak samo ma być w szablonie.
   ========================================================================== */

/* Sekret base32 w czytelnych grupach — ekran parowania drugiego składnika.
   Krój o stałej szerokości znaku i rozstrzelenie: sekret się PRZEPISUJE
   z ekranu do telefonu, więc „0" i „O" muszą się różnić na pierwszy rzut oka.
   `word-break: break-all`, bo przy 360 px sekret nie ma gdzie się złamać. */
.sekret {
  background-color: var(--tlo-wylaczone);
  border: 1px solid var(--obwodka-pola);
  border-radius: var(--promien);
  color: var(--tekst);
  display: inline-block;
  font-family: ui-monospace, "SFMono-Regular", "Consolas", monospace;
  font-size: 1.125rem;
  letter-spacing: 0.08em;
  padding: var(--odstep-2) var(--odstep-3);
  word-break: break-all;
}

/* Biała ramka pod kodem QR. Biel jest tu wpisana na sztywno i to jest JEDYNA
   wartość w tym pliku poza tokenami — celowo: kod QR czyta się kontrastem
   czarnych modułów wobec białego tła, więc „białe" nie jest tu decyzją
   wizualną, tylko warunkiem odczytania go kamerą. Token `--tlo` mógłby kiedyś
   przestać być bielą i kod przestałby się skanować. */
.ramka-qr {
  background-color: #ffffff;
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: var(--promien);
  display: inline-block;
  padding: var(--odstep-3);
}

/* `image-rendering: pixelated`: symbol QR jest siatką kwadratów, a wygładzanie
   przy skalowaniu rozmywa ich krawędzie i pogarsza odczyt. */
.ramka-qr img {
  display: block;
  height: auto;
  image-rendering: pixelated;
  width: 12.5rem;
}

/* Kody zapasowe. Numerowane, żeby dało się je przepisać bez gubienia wiersza —
   ale numer rysuje CSS (`counter`), a nie treść: nie jest częścią kodu i nikt
   nie ma go przepisać razem z kodem. */
.kody-zapasowe {
  display: grid;
  gap: var(--odstep-2);
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: kod;
}

.kody-zapasowe li {
  background-color: var(--tlo-ciche);
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: var(--promien-maly);
  counter-increment: kod;
  display: flex;
  gap: var(--odstep-2);
  padding: var(--odstep-2) var(--odstep-3);
}

.kody-zapasowe li::before {
  color: var(--tekst-cichy);
  content: counter(kod) ".";
  font-size: var(--krok-tekstu-maly);
  min-width: 1.5rem;
  text-align: right;
}

.kody-zapasowe code {
  color: var(--tekst);
  font-family: ui-monospace, "SFMono-Regular", "Consolas", monospace;
  font-size: 1.0625rem;
  letter-spacing: 0.06em;
}

/* Pole na kod jednorazowy — szerokość pod sześć cyfr, nie pod cały wiersz.
   Pole rozciągnięte na całą kartę zapowiada, że wpisze się w nie zdanie. */
.pole-kodu {
  font-family: ui-monospace, "SFMono-Regular", "Consolas", monospace;
  font-size: 1.25rem;
  letter-spacing: 0.25em;
  max-width: 12rem;
}

/* Wariant dla pola przyjmującego OBA rodzaje kodu (ekran potwierdzenia przy
   logowaniu): osiem znaków kodu zapasowego nie mieści się w 12 rem, a przy
   rozstrzeleniu 0,25 em litery odklejają się od siebie za mocno. */
.pole-kodu-szerokie {
  letter-spacing: 0.12em;
  max-width: 18rem;
}

/* Lista kroków „co zrobić" na ekranie parowania. Numery w kółkach rysuje CSS,
   bo `<ol>` z domyślnym znacznikiem daje przy trzech krokach wyliczenie, które
   niczym nie różni się od zwykłej listy — a to jest instrukcja do wykonania
   po kolei. */
.kroki {
  counter-reset: krok;
  list-style: none;
  margin: 0;
  padding: 0;
}

.kroki li {
  counter-increment: krok;
  padding-left: 2.25rem;
  position: relative;
}

.kroki li + li {
  margin-top: var(--odstep-3);
}

.kroki li::before {
  align-items: center;
  background-color: var(--marka);
  border-radius: 50%;
  color: #ffffff;
  content: counter(krok);
  display: flex;
  font-size: var(--krok-tekstu-maly);
  font-weight: 700;
  height: 1.625rem;
  justify-content: center;
  left: 0;
  position: absolute;
  top: 0.05rem;
  width: 1.625rem;
}

/* ==========================================================================
   5. Ikony ze sprite'u `icons/ikony.svg`

   `<svg class="ikona"><use href="…#nazwa"></use></svg>` zamiast czcionki
   ikon: czcionka wymaga drugiego arkusza i pliku na kilkaset kilobajtów,
   a sprite z dziewięcioma symbolami waży cztery kilobajty. Kolor bierze się
   z `currentColor`, czyli z koloru tekstu obok.
   ========================================================================== */

.ikona {
  fill: currentColor;
  flex: 0 0 auto;
  height: var(--ikona);
  width: var(--ikona);
  vertical-align: -0.125em;
}

.ikona-srednia {
  height: var(--ikona-srednia);
  width: var(--ikona-srednia);
}

.ikona-duza {
  height: var(--ikona-duza);
  width: var(--ikona-duza);
}

/* ==========================================================================
   6. Komunikaty (obszar flash) — kategorie z sekcji 2 spisu parytetu

   Znaczenie niosą trzy rzeczy naraz: tekst, ikona i kolor. Nigdy sam kolor —
   SC 1.4.1 („Użycie koloru").
   ========================================================================== */

.obszar-komunikatow:not(:empty) {
  margin-bottom: var(--odstep-3);
}

.komunikat {
  border: 1px solid;
  border-left-width: 4px;
  border-radius: var(--promien);
  display: flex;
  gap: var(--odstep-2);
  margin-bottom: var(--odstep-3);
  padding: var(--odstep-3);
}

/* Ikona wyrównana do pierwszego wiersza tekstu, nie do góry pudełka. */
.komunikat > .ikona {
  height: var(--ikona-srednia);
  margin-top: var(--wyrownanie-ikony);
  width: var(--ikona-srednia);
}

.komunikat p:last-child {
  margin-bottom: 0;
}

.komunikat-ostrzezenie {
  background-color: var(--ostrzezenie-tlo);
  border-color: var(--ostrzezenie-obwodka);
  color: var(--ostrzezenie);
}

.komunikat-sukces {
  background-color: var(--sukces-tlo);
  border-color: var(--sukces);
  color: var(--sukces);
}

.komunikat-blad {
  background-color: var(--blad-tlo);
  border-color: var(--blad);
  color: var(--blad);
}

.komunikat-informacja {
  background-color: var(--informacja-tlo);
  border-color: var(--informacja);
  color: var(--informacja);
}

/* ==========================================================================
   7. Stan pusty — dodatek 6 z sekcji 7 planu

   Jedno zdanie o tym, że nic tu nie ma, i jedno o tym, co zrobić dalej.
   Wersja 1.0 pisze w tym miejscu samo `Brak wpisów`.
   ========================================================================== */

.stan-pusty {
  background-color: var(--tlo-ciche);
  border: 1px dashed var(--obwodka-pola);
  border-radius: var(--promien);
  display: flex;
  gap: var(--odstep-3);
  padding: var(--odstep-4);
}

.stan-pusty > .ikona {
  color: var(--tekst-cichy);
  height: var(--ikona-duza);
  width: var(--ikona-duza);
}

.stan-pusty p:last-child {
  margin-bottom: 0;
}

/* ==========================================================================
   7a. Karta wpisu dziennika sukcesów — dołożone w U3

   Przeniesione z `docs/prototypy-ui/motyw.css` (blok `.karta-wpisu`), bez
   zmian poza tym komentarzem. W 1.0 każdy wpis to `container border p-2 my-2`:
   znacznik czasu w jednym wierszu, pod nim treść.

   Format znacznika `RRRR.MM.DD GG:MM` — KROPKI, inaczej niż data w komórce
   lejka (`RRRR-MM-DD GG:MM`, łączniki). To nie jest pomyłka: oba są przepisane
   z ekranu 1.0 i oba zostają (`helper.shared.formatting`).

   `white-space: pre-line` w treści wpisu **zastępuje** `replace('\r\n', '<br>')
   | safe` z 1.0. Ten sam efekt na ekranie — łamanie wierszy tam, gdzie
   użytkownik nacisnął Enter — bez wpuszczania na stronę HTML-a z pola
   tekstowego. Wartość `pre-line`, a nie `pre-wrap`: dwie z rzędu puste linie
   z wklejonego tekstu nie rozciągają wtedy karty.

   `tabular-nums` w znaczniku czasu: cyfry mają równą szerokość, więc daty
   w kolejnych kartach stoją w jednej kolumnie, mimo że każda jest osobnym
   wierszem.
   ========================================================================== */

.karta-wpisu {
  background-color: var(--tlo);
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: var(--promien);
  padding: var(--odstep-3);
}

.karta-wpisu + .karta-wpisu {
  margin-top: var(--odstep-2);
}

.wpis-czas {
  color: var(--tekst-cichy);
  display: block;
  font-size: var(--krok-tekstu-maly);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.wpis-tresc {
  margin: var(--odstep-1) 0 0;
  white-space: pre-line;
}

/* ==========================================================================
   7b. Tablica lejka sprzedaży — dołożone w U4

   Przeniesione z `docs/prototypy-ui/motyw.css`, z jedną zmianą: prototypowe
   selektory `.bi` (font Bootstrap Icons) są tu `.ikona`, bo produkcja bierze
   ikony ze sprite'u SVG — font z CDN nie przeszedłby przez CSP (D7).

   TO NIE JEST ZNACZNIK `<table>` i nie jest to uproszczenie. Kolumny w 1.0 są
   sortowane KAŻDA OSOBNO po dacie wejścia w swój etap (sekcja 4.6 parytetu),
   więc wiersz tabeli nie znaczy nic: firma z trzeciego wiersza kolumny Leads
   nie ma nic wspólnego z firmą z trzeciego wiersza kolumny Suspect. To tabela
   układu, nie tabela danych — a czytnik ekranu ogłasza w `<table>` wiersze,
   których nie ma. Cztery kolumny w siatce dają ten sam wygląd i pozwalają
   jednym znacznikiem obsłużyć widok szeroki (cztery kolumny) i wąski (cztery
   zwijane sekcje) BEZ powtarzania danych w treści strony.

   KOLOR DATY NIE JEST JEDYNYM NOŚNIKIEM ZNACZENIA (SC 1.4.1): przy dacie stoi
   kółko pełne (nowsza niż 3 tygodnie) albo obwódka kółka (starsza), a czytnik
   ekranu dostaje pełne zdanie w tekście ukrytym. Kontrast obu kolorów na białym
   policzony w nagłówku `_tokeny.css`: informacja 7.09:1, sukces 6.77:1.

   KOSZ STOI NA KOŃCU RZĘDU, ZA LINIĄ — naprawa luki 1. W 1.0 rząd wygląda tak:
   strzałka w lewo, KOSZ, strzałka w prawo, wszystkie trzy identyczne i bez
   podpisu. Pomyłka bierze się stąd, że kosz jest tam, gdzie ręka spodziewa się
   strzałki.
   ========================================================================== */

.lejek {
  display: grid;
  gap: var(--odstep-3);
  grid-template-columns: 1fr;
}

.lejek-kolumna {
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: var(--promien);
  min-width: 0;
}

.lejek-naglowek {
  background-color: var(--tlo-ciche);
  border-bottom: 1px solid var(--obwodka-dekoracyjna);
  border-radius: calc(var(--promien) - 1px) calc(var(--promien) - 1px) 0 0;
  font-size: var(--krok-tekstu-maly);
  font-weight: 700;
  letter-spacing: 0.04em;
  margin: 0;
  text-transform: uppercase;
}

.lejek-naglowek-tekst {
  display: block;
  padding: var(--odstep-2) var(--odstep-3);
}

/* Zwijak jest widoczny WYŁĄCZNIE w widoku wąskim (klasa `d-md-none` w treści
   strony), a nagłówek nieklikalny wyłącznie w szerokim. Dwa elementy zamiast
   jednego, bo przycisk, który na szerokim ekranie nic nie robi, zostawałby
   w kolejności `tab` jako pułapka. Powtórzony jest tylko krótki napis
   nagłówka, nie dane. */
.lejek-zwijak {
  align-items: center;
  background: none;
  border: 0;
  color: var(--tekst);
  display: flex;
  font: inherit;
  gap: var(--odstep-2);
  justify-content: space-between;
  letter-spacing: inherit;
  padding: var(--odstep-3);
  text-align: left;
  text-transform: inherit;
  width: 100%;
}

.lejek-zwijak .strzalka-zwijaka {
  transition: transform 0.15s ease-in-out;
}

.lejek-zwijak[aria-expanded="true"] .strzalka-zwijaka {
  transform: rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
  .lejek-zwijak .strzalka-zwijaka {
    transition: none;
  }
}

.lejek-komorki {
  padding: var(--odstep-2);
}

.lejek-pusta {
  color: var(--tekst-cichy);
  font-size: var(--krok-tekstu-maly);
  margin: 0;
  padding: var(--odstep-2);
}

/* Od szerokości `md` (768 px) siatka staje się tablicą: cztery kolumny równej
   szerokości, wspólna obwódka, kolumny rozdzielone linią. Zwinięte sekcje są
   tu rozwijane na siłę — inaczej sekcja zwinięta palcem na telefonie zostałaby
   zwinięta po obróceniu ekranu. */
@media (min-width: 48em) {
  .lejek {
    border: 1px solid var(--obwodka-dekoracyjna);
    border-radius: var(--promien);
    gap: 0;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    overflow: hidden;
  }

  .lejek-kolumna {
    border: 0;
    border-radius: 0;
  }

  .lejek-kolumna + .lejek-kolumna {
    border-left: 1px solid var(--obwodka-dekoracyjna);
  }

  .lejek-naglowek {
    border-radius: 0;
  }

  .lejek-komorki {
    display: block !important;
    height: auto !important;
    overflow: visible !important;
  }
}

/* --- komórka lejka -------------------------------------------------------- */

.komorka-lejka {
  border-radius: var(--promien-maly);
  padding: var(--odstep-2);
}

.komorka-lejka + .komorka-lejka {
  border-top: 1px solid var(--obwodka-dekoracyjna);
}

/* Komórka etapu bieżącego jest wyróżniona tłem. W 1.0 poznaje się ją tylko po
   tym, że są w niej ikony — a menedżer ikon nie widzi wcale, więc nie ma jak
   odczytać, gdzie firma naprawdę stoi. */
.komorka-lejka-biezaca {
  background-color: var(--marka-tlo);
}

.komorka-nazwa {
  display: block;
  font-weight: 600;
}

/* Luka 13 spisu parytetu: nazwy firm nie muszą być unikalne, a na tablicy widać
   wtedy dwie identyczne pozycje. Dopisek różnicujący to data wejścia w etap
   tej kolumny. */
.dopisek-roznicujacy {
  color: var(--tekst-cichy);
  display: block;
  font-size: 0.75rem;
  font-weight: 400;
}

.komorka-data {
  align-items: center;
  display: flex;
  font-size: var(--krok-tekstu-maly);
  font-variant-numeric: tabular-nums;
  gap: var(--odstep-1);
  margin: var(--odstep-1) 0 0;
}

.komorka-data > .ikona {
  height: 0.6875rem;
  width: 0.6875rem;
}

.data-nowa {
  color: var(--informacja);
}

.data-stara {
  color: var(--sukces);
}

/* --- ikony akcji w komórce ------------------------------------------------
   Rzędem akcji jest FORMULARZ, nie otoczka: jeden formularz na komórkę
   obsługuje ruch w przód, a odsyłacze obok proszą o krok potwierdzenia.
   Dlatego układ poziomy dostaje i otoczkę, i formularz — inaczej rozdzielnik
   przed koszem nie ma czego rozepchnąć. */

.akcje-komorki,
.akcje-komorki form {
  align-items: center;
  display: flex;
  gap: var(--odstep-1);
}

.akcje-komorki {
  margin-top: var(--odstep-2);
}

.akcja {
  --bs-btn-padding-x: 0.5rem;
  --bs-btn-padding-y: 0.25rem;
  line-height: 1;
}

.akcja .ikona {
  height: 1rem;
  width: 1rem;
}

.akcje-rozdzielnik {
  align-self: stretch;
  border-left: 1px solid var(--obwodka-dekoracyjna);
  flex: 1 1 auto;
  margin-left: auto;
  min-width: var(--odstep-3);
}

.akcja-kosz {
  --bs-btn-color: var(--blad);
  --bs-btn-border-color: var(--blad);
  --bs-btn-bg: var(--tlo);
  --bs-btn-hover-color: #ffffff;
  --bs-btn-hover-bg: var(--blad);
  --bs-btn-hover-border-color: var(--blad);
  --bs-btn-active-color: #ffffff;
  --bs-btn-active-bg: var(--blad);
  --bs-btn-active-border-color: var(--blad);
}

/* --- legenda tablicy — dodatek 4 z sekcji 7 planu -------------------------
   Wersja 1.0 koloruje daty i nie tłumaczy tego nigdzie; nie mówi też nigdzie,
   że lejek jest kumulatywny, czyli że `Leads (13)` znaczy „13 firm przeszło
   przez Leads", a nie „13 firm czeka na kontakt". To jest najczęstsze
   nieporozumienie przy czytaniu tego ekranu. */

.legenda-tablicy {
  background-color: var(--tlo-ciche);
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: var(--promien);
  padding: var(--odstep-3);
}

.legenda-tablicy dl {
  display: grid;
  gap: var(--odstep-2) var(--odstep-3);
  grid-template-columns: 1fr;
  margin: 0;
}

@media (min-width: 48em) {
  .legenda-tablicy dl {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.legenda-tablicy dt {
  align-items: center;
  display: flex;
  gap: var(--odstep-2);
}

.legenda-tablicy dd {
  color: var(--tekst-cichy);
  font-size: var(--krok-tekstu-maly);
  margin: 0 0 var(--odstep-2);
}

.probka-daty {
  align-items: center;
  display: inline-flex;
  font-size: var(--krok-tekstu-maly);
  font-variant-numeric: tabular-nums;
  gap: var(--odstep-1);
}

.probka-daty > .ikona {
  height: 0.6875rem;
  width: 0.6875rem;
}

/* Nagłówek wersalikami z podkreśleniem — `Lejek sprzedaży` w 1.0 ma
   `text-uppercase`. WERSALIKI ROBI STYL, nie treść: w znaczniku napis jest
   zapisany normalnie, więc czytnik ekranu czyta „Lejek sprzedaży", a nie
   „L, E, J, E, K". Wskaźnik skuteczności jest zielony i pogrubiony, tak jak
   tam. */
.naglowek-wersalikami {
  letter-spacing: 0.04em;
  text-decoration: underline;
  text-transform: uppercase;
  text-underline-offset: 0.25em;
}

/* Dopisek adresu w nagłówku lejka u menedżera: `LEJEK SPRZEDAŻY - (JAN.KOWALSKI@SEEN.PL)`.

   Adres e-mail jest jednym ciągiem bez spacji, więc przeglądarka nie ma go gdzie złamać —
   przy 360 px rozpychał nagłówek do 406 px i **cała strona przewijała się w poziomie**.
   `anywhere` pozwala złamać go w dowolnym miejscu, ale dopiero wtedy, gdy nie mieści się
   w wierszu: na szerokim ekranie nic się nie zmienia.

   Dlaczego nie `break-all`: tamto łamie każdy wyraz, także `SPRZEDAŻY`. Tutaj chodzi
   wyłącznie o ciąg, którego nie da się złamać inaczej. */
.dopisek-naglowka {
  overflow-wrap: anywhere;
}

.wskaznik-skutecznosci {
  color: var(--sukces);
  font-weight: 700;
}

/* ==========================================================================
   7c. Rząd formularzy CRM — dołożone w U5

   Sekcja 4.7 spisu parytetu: wersja 1.0 stawia `Nowy klient` i `Wybierz
   klienta` OBOK SIEBIE w jednym rzędzie (a na karcie klienta dochodzi trzeci,
   `Zmień nazwę klienta`). Rząd zostaje rzędem, ale ZAWIJA SIĘ, zamiast ściskać
   pola do nieczytelnej szerokości — 17 rem to najmniejsza szerokość, przy
   której mieści się napis `— wybierz firmę —`.

   `align-items: flex-end` wyrównuje przyciski, a nie etykiety: pola mają
   podpowiedzi różnej długości, a lista dodatkowo bierze podpowiedź NAD
   kontrolką (SC 3.2.2), więc wyrównanie do góry rozjeżdżałoby przyciski
   o kilkanaście pikseli.
   ========================================================================== */

.rzad-formularzy {
  align-items: flex-end;
  display: flex;
  flex-wrap: wrap;
  gap: var(--odstep-4);
}

.rzad-formularzy > form {
  flex: 1 1 17rem;
  margin: 0;
  min-width: 0;
}

/* ==========================================================================
   7d. Karta klienta CRM — dołożone w U5 (zlecenie drugie)

   Największy ekran całego przepisania: rząd trzech formularzy, nazwa klienta
   z koszem menedżera, pasek stanu firmy, trzy zwijane sekcje i dwie ankiety
   o łącznie 34 polach. Klasy przeniesione z prototypu
   `docs/prototypy-ui/crm-karta-klienta.html` (`motyw.css`, sekcja karty).

   Rząd formularzy (`.rzad-formularzy`) jest wspólny z ekranem `/crm/` i stoi
   w sekcji 7c — tutaj dochodzi wyłącznie to, czego tamten ekran nie ma.
   ========================================================================== */

/* --- nagłówek karty: nazwa klienta i kosz menedżera ------------------------
   Kosz stoi po PRZECIWNEJ STRONIE rzędu niż nazwa (odstępstwo 7), a nie tuż
   przy niej jak w 1.0: pomyłka przy usuwaniu bierze się z bliskości przycisku
   do czegoś innego. `align-items: baseline` wyrównuje podpis kosza do linii
   pisma nazwy, a nie do jej pudełka — nazwa bywa dwuwierszowa. */

.naglowek-klienta {
  align-items: baseline;
  border-bottom: 1px solid var(--obwodka-dekoracyjna);
  display: flex;
  flex-wrap: wrap;
  gap: var(--odstep-3);
  justify-content: space-between;
  margin-bottom: var(--odstep-3);
  padding-bottom: var(--odstep-2);
}

.naglowek-klienta h1,
.naglowek-klienta h2 {
  margin-bottom: 0;
}

/* Kosz z widocznym podpisem (odstępstwo 8) — w 1.0 jest samą ikoną z atrybutem
   `alt="delete"`. Ikona i podpis stoją w jednej linii; `.akcja` z sekcji 7b
   daje kolory i rozmiar, tutaj dochodzi wyłącznie ułożenie dwóch elementów. */
.naglowek-klienta .akcja-kosz {
  align-items: center;
  display: inline-flex;
  gap: var(--odstep-1);
  white-space: nowrap;
}

/* --- pasek stanu firmy — odstępstwo 1 --------------------------------------
   JEDYNE miejsce ekranu, które mówi wprost, na jakim etapie stoi firma.
   W 1.0 trzeba to wywnioskować z tego, która z trzech sekcji jest rozwinięta,
   a dla firmy w etapie LEAD wszystkie trzy są zwinięte i ekran nie mówi nic.

   Cztery kolumny dopiero od `md`: na telefonie cztery pudełka z datą po
   `RRRR-MM-DD GG:MM` mają po 90 px, czyli data łamie się w środku. */

.pasek-etapow {
  display: grid;
  gap: var(--odstep-2);
  grid-template-columns: 1fr;
  list-style: none;
  margin: 0 0 var(--odstep-4);
  padding: 0;
}

@media (min-width: 48em) {
  .pasek-etapow {
    grid-template-columns: repeat(4, 1fr);
  }
}

.etap {
  background-color: var(--tlo-ciche);
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: var(--promien);
  border-top-width: 4px;
  padding: var(--odstep-2) var(--odstep-3);
}

.etap-przebyty {
  border-top-color: var(--sukces);
}

/* Etap bieżący ma inne tło, inną obwódkę I podpis `etap bieżący` — kolor nie
   jest tu jedynym nośnikiem znaczenia (SC 1.4.1). */
.etap-biezacy {
  background-color: var(--marka-tlo);
  border-color: var(--marka);
  border-top-color: var(--marka);
}

.etap-nieosiagniety {
  border-top-color: var(--obwodka-dekoracyjna);
  color: var(--tekst-cichy);
}

.etap-nazwa {
  display: block;
  font-weight: 600;
}

.etap-data {
  color: var(--tekst-cichy);
  display: block;
  font-size: var(--krok-tekstu-maly);
}

.etap-biezacy .etap-data {
  color: var(--marka-ciemniejsza);
}

.etap-znacznik {
  color: var(--marka-ciemna);
  display: block;
  font-size: var(--krok-tekstu-maly);
  font-weight: 700;
  text-transform: uppercase;
}

/* --- tytuł zwijanej sekcji i licznik wypełnienia ---------------------------
   Nazwy sekcji są w 1.0 wersalikami (`SUSPECT`, `PROSPECT`, `CUSTOMER`) i tak
   są zapisane w treści — to nie styl, tylko dosłowna treść z ekranu.

   Licznik (odstępstwo 3) mówi, ile pól ma odpowiedź. NICZEGO NIE BLOKUJE:
   firma przechodzi cały lejek z pustymi ankietami i nic nie protestuje. */

.tytul-sekcji {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: var(--odstep-2);
  width: 100%;
}

.nazwa-sekcji {
  font-weight: 700;
  letter-spacing: 0.03em;
}

.licznik-wypelnienia {
  background-color: var(--tlo-wylaczone);
  border-radius: 999px;
  color: var(--tekst-cichy);
  display: inline-block;
  font-size: var(--krok-tekstu-maly);
  font-weight: 600;
  padding: 0.1rem 0.65rem;
  white-space: nowrap;
}

.licznik-wypelnienia-pelny {
  background-color: var(--sukces-tlo);
  color: var(--sukces);
}

/* --- bloki tematyczne ankiety PROSPECT — odstępstwo 2 ----------------------
   KOLEJNOŚĆ PÓL SIĘ NIE ZMIENIA. Bloki są cięciem ciągu 24 pól na cztery
   nieprzeplatające się odcinki, więc pole numer n zostaje pomiędzy n-1 i n+1.
   Zakres pól jest wypisany w legendzie, żeby dało się to sprawdzić wzrokiem. */

.blok-ankiety {
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: var(--promien);
  margin-bottom: var(--odstep-4);
  padding: var(--odstep-3);
  /* Skok ze spisu bloków ma zostawić nagłówek bloku poniżej przyklejonego
     paska — ta sama wartość i ten sam powód co przy `.okno-w-tresci`. */
  scroll-margin-top: 5rem;
}

/* `float: none` i `width: auto` cofają domyślne zachowanie `legend`
   w Bootstrapie, który rozciąga ją na całą szerokość pola zbiorczego —
   przez co ramka bloku przechodziłaby przez środek napisu. */
.blok-ankiety > legend {
  color: var(--marka-ciemna);
  float: none;
  font-size: var(--krok-tekstu);
  font-weight: 700;
  margin-bottom: 0;
  padding: 0 var(--odstep-2);
  width: auto;
}

.blok-zakres {
  color: var(--tekst-cichy);
  font-size: var(--krok-tekstu-maly);
  font-weight: 400;
}

/* --- spis bloków: skok do bloku bez przewijania 24 pól — odstępstwo 13 ----- */

.spis-blokow {
  display: flex;
  flex-wrap: wrap;
  gap: var(--odstep-2);
  list-style: none;
  margin: 0 0 var(--odstep-3);
  padding: 0;
}

.spis-blokow a {
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: 999px;
  display: inline-block;
  font-size: var(--krok-tekstu-maly);
  padding: 0.15rem 0.7rem;
  text-decoration: none;
}

.spis-blokow a:hover,
.spis-blokow a:focus-visible {
  background-color: var(--marka-tlo);
  border-color: var(--marka);
}

/* --- siatka pól ankiety ---------------------------------------------------- */

.siatka-pol {
  display: grid;
  gap: var(--odstep-3);
  grid-template-columns: 1fr;
}

@media (min-width: 48em) {
  .siatka-pol-2 {
    grid-template-columns: 1fr 1fr;
  }
}

.pole-szerokie {
  grid-column: 1 / -1;
}

/* Pole daty i pole liczby nie potrzebują całej szerokości wiersza — pole
   rozciągnięte na 60 rem sugeruje, że wpisuje się w nie zdanie, nie datę. */
.pole-krotkie .form-control {
  max-width: 14rem;
}

/* --- pole wyboru: cel dotknięcia nie mniejszy niż 24 px (SC 2.5.8) ---------
   Ankieta PROSPECT ma trzynaście pól wyboru z długimi etykietami. W 1.0 są to
   nagie `input` z etykietą obok, wielkości domyślnej przeglądarki (13 px) —
   na telefonie nie do trafienia. Tutaj cały prostokąt jest polem etykiety,
   więc kliknięcie w tekst przełącza pole.

   KOLEJNOŚĆ WIZUALNA ZAMIENIA `order`, NIE ZNACZNIK. Makro `pole_formularza`
   renderuje etykietę PRZED kontrolką — tak samo na wszystkich ekranach
   aplikacji — a tutaj kontrolka ma stać po lewej. `order: -1` na polu wyboru
   przestawia ją wzrokowo, zostawiając kolejność w dokumencie bez zmian:
   czytnik ekranu i klawiatura idą po znaczniku, więc jedno ułożenie nie
   psuje drugiego. Wariant z `flex-direction: row-reverse` odwróciłby też
   komunikat błędu i podpowiedź, czyli wszystkie cztery dzieci. */

.pole-wyboru {
  align-items: flex-start;
  background-color: var(--tlo);
  border: 1px solid var(--obwodka-dekoracyjna);
  border-radius: var(--promien-maly);
  display: flex;
  flex-wrap: wrap;
  gap: var(--odstep-2);
  padding: var(--odstep-2) var(--odstep-3);
}

.pole-wyboru input[type="checkbox"] {
  flex: 0 0 auto;
  height: 1.35rem;
  margin: 0.15rem 0 0;
  order: -1;
  width: 1.35rem;
}

.pole-wyboru label {
  flex: 1 1 12rem;
  font-weight: 400;
  margin: 0;
  min-height: 1.65rem;
}

/* Komunikat błędu i podpowiedź — gdyby kiedyś się pojawiły — schodzą pod
   parę „kontrolka i etykieta", a nie wciskają się między nie. */
.pole-wyboru .invalid-feedback,
.pole-wyboru .podpowiedz-pola {
  flex: 1 0 100%;
  order: 1;
}

.pole-wyboru:focus-within {
  border-color: var(--marka);
}

.pole-wyboru-zaznaczone {
  background-color: var(--sukces-tlo);
  border-color: var(--sukces);
}

/* --- pole daty odsłaniane polem wyboru — pięć par (pola 10, 15, 19, 21, 23) -
   ODWZOROWANIE, NIE NAPRAWA. W 1.0 skrypt ustawia `style.display`, pole
   zostaje w dokumencie i JEST WYSYŁANE, a zależność „data tylko wtedy, gdy
   pole wyboru zaznaczone" nie jest wymuszana ani przez formularz, ani przez
   bazę (uzasadnienie w `helper/clients/prospect_survey.py`). Ukrycie stylem
   zachowuje się identycznie: pole zostaje w formularzu i leci na serwer.

   DLACZEGO ARKUSZ, A NIE SKRYPT. Prototyp przestawia atrybut `hidden`
   skryptem. Tutaj robi to `:has()`, więc odsłanianie działa przy wyłączonym
   JavaScripcie — a przy CSP bez `unsafe-inline` mniej skryptu to mniej rzeczy,
   które mogą nie zadziałać.

   `@supports` jest ZABEZPIECZENIEM, nie ozdobą: przeglądarka bez `:has()`
   odrzuciłaby regułę odsłaniającą, a zostawiła regułę chowającą — czyli pięć
   pól byłoby ukrytych na zawsze. Poza blokiem pola są widoczne zawsze, co jest
   gorsze wizualnie i nie gubi ani jednej danej.

   Druga reguła odsłania pole z BŁĘDEM niezależnie od pola wyboru. Bez niej
   odnośnik z podsumowania błędów (luka 4) prowadziłby do kontrolki, której
   nie widać — a użytkownik dostawałby stronę, która „nie zapisała", i nie
   miałby jak zobaczyć powodu. */

.pole-zaleznie {
  border-left: 3px solid var(--ostrzezenie-obwodka);
  margin-top: var(--odstep-2);
  padding-left: var(--odstep-3);
}

@supports selector(:has(*)) {
  .pole-zaleznie {
    display: none;
  }

  .pole-wyboru:has(input[type="checkbox"]:checked) + .pole-zaleznie,
  .pole-zaleznie:has(.is-invalid) {
    display: block;
  }
}

.notka-zaleznosci {
  color: var(--ostrzezenie);
  font-size: var(--krok-tekstu-maly);
  margin-bottom: 0;
}

/* --- rząd zapisu: zdanie o zakresie zapisu i przycisk `Zapisz` -------------
   Poniżej `md` rząd przykleja się do dolnej krawędzi okna (odstępstwo 13).
   Powód: po dwudziestu czterech polach przycisk `Zapisz` jest na telefonie
   dwa ekrany niżej niż pole, które się właśnie wypełniło. Przycisk jest TEN
   SAM i nazywa się tak samo — przyklejenie jest zmianą położenia, nie
   dołożeniem drugiego zapisu.

   U menedżera ten rząd nie powstaje wcale: nie ma przycisku `Zapisz`
   (sekcja 4.8 punkt 4). */

.pasek-zapisu {
  align-items: center;
  border-top: 1px solid var(--obwodka-dekoracyjna);
  display: flex;
  flex-wrap: wrap;
  gap: var(--odstep-3);
  justify-content: space-between;
  margin-top: var(--odstep-3);
  padding-top: var(--odstep-3);
}

@media (max-width: 47.99em) {
  .pasek-zapisu {
    background-color: var(--tlo);
    bottom: 0;
    box-shadow: 0 -2px 6px rgba(27, 31, 36, 0.12);
    margin-left: calc(-1 * var(--odstep-3));
    margin-right: calc(-1 * var(--odstep-3));
    padding: var(--odstep-3);
    position: sticky;
    z-index: 5;
  }
}

/* --- cztery akapity sekcji CUSTOMER — sekcja 1.10 spisu parytetu -----------
   To nie jest ankieta: żadnego pola, żadnego przycisku, nic do zapisania. */

.akapity-customer p {
  max-width: 46rem;
}

.akapity-customer p:last-child {
  margin-bottom: 0;
}

/* ==========================================================================
   8. Okno potwierdzenia — punkt 6 listy `docs/zmiany-ui-wobec-1.0.md`

   Jedyny dodany element interfejsu w całym przepisaniu. Treść zawsze nazywa
   obiekt i mówi, co zostanie utracone (luka 1: wersja 1.0 usuwa bez pytania).
   ========================================================================== */

.okno-potwierdzenia .modal-header {
  background-color: var(--blad-tlo);
  border-bottom-color: var(--blad);
}

.okno-potwierdzenia .modal-title {
  color: var(--blad);
  font-weight: 700;
}

.okno-potwierdzenia dl {
  display: grid;
  gap: var(--odstep-1) var(--odstep-3);
  grid-template-columns: 1fr;
  margin-bottom: var(--odstep-3);
}

@media (min-width: 36em) {
  .okno-potwierdzenia dl {
    grid-template-columns: auto 1fr;
  }
}

.okno-potwierdzenia dt {
  color: var(--tekst-cichy);
  font-size: var(--krok-tekstu-maly);
  font-weight: 600;
}

.okno-potwierdzenia dd {
  font-variant-numeric: tabular-nums;
  margin: 0;
}

/* ==========================================================================
   9. Strony błędów — sekcja 2.5 spisu parytetu

   Kod odpowiedzi stoi obok nagłówka i jest `aria-hidden`: dla czytnika ekranu
   liczba bez kontekstu jest szumem, a nagłówek mówi to samo słowami.
   ========================================================================== */

.strona-bledu {
  display: flex;
  gap: var(--odstep-4);
}

.kod-bledu {
  color: var(--marka);
  flex: 0 0 auto;
  font-size: var(--kod-bledu-krok);
  font-weight: 700;
  line-height: 1;
}

.strona-bledu h1 {
  margin-bottom: var(--odstep-2);
}

.strona-bledu p:last-of-type {
  margin-bottom: 0;
}

/* ==========================================================================
   10. Drobne klasy narzędziowe

   Istnieją dlatego, że polityka CSP `default-src 'self'` bez `unsafe-inline`
   (wymóg D7) nie wykona atrybutu `style`. Każdy napis, który ma być cichy
   albo w kolorze marki, bierze klasę — nigdy atrybut.
   ========================================================================== */

.tekst-cichy {
  color: var(--tekst-cichy);
}

.tekst-marka {
  color: var(--marka-ciemna);
}

/* Nagłówek w kolorze sukcesu — dołożone w U3. Wersja 1.0 maluje na zielono
   `Witaj w aplikacji Helper!`, `Wszystkie sukcesy` i oba nagłówki lejka
   (`text-success` Bootstrapa). Klasa własna, a nie `text-success`, bo kolor ma
   brać token `--sukces` (kontrast 6,77:1 na białym), a nie zmienną Bootstrapa.

   Kolor **nie jest** tu jedynym nośnikiem czegokolwiek (SC 1.4.1): to nagłówki,
   więc znaczenie niesie poziom znacznika i pogrubienie. */
.naglowek-zielony {
  color: var(--sukces);
  font-weight: 700;
}

/* ==========================================================================
   11. Użyteczność od 360 px
   ========================================================================== */

@media (max-width: 26em) {
  :root {
    --odstep-4: 1rem;
    --odstep-5: 1.25rem;
  }

  .karta {
    padding: var(--odstep-3);
  }

  /* Przy 360 px ikona obok tekstu zabiera trzecią część szerokości. */
  .stan-pusty {
    align-items: flex-start;
    flex-direction: column;
  }

  /* Dwie kolumny kodów zapasowych nie mieszczą się w 360 px — kod zawijałby
     się w środku, a kod zapasowy przepisuje się znak po znaku. */
  .kody-zapasowe {
    grid-template-columns: 1fr;
  }

  /* Kod odpowiedzi nad nagłówkiem, nie obok. */
  .strona-bledu {
    flex-direction: column;
    gap: var(--odstep-2);
  }

  /* Rząd formularzy CRM staje się kolumną. Przy 360 px dwa pola obok siebie
     mają po 150 px, czyli nie pomieszczą nawet napisu `— wybierz firmę —`. */
  .rzad-formularzy {
    align-items: stretch;
    flex-direction: column;
  }
}

/* Tabele nie rozpychają strony w poziomie — przewijają się we własnym
   pojemniku (`.table-responsive` Bootstrapa). Reguła stoi tu, a nie przy
   tabelach, bo dotyczy wszystkich, także tych z etapów U3–U6. */
.table-responsive {
  overflow-x: auto;
}
