/* kcms 5.0, panel redakcyjny
   Paleta i układ zgodne z zatwierdzoną makietą.
   Bez cieni: hierarchię budują obramowania, kontrast i odstępy. */

:root {
  --ink: #16161a;
  --graphite: #232329;
  --rail: #1a1a1f;

  /* Kolor alarmu: błędy, usuwanie, rzeczy pilne. Czerwony w każdym wariancie
     marki, bo przy błędzie niesie znaczenie, a nie tylko wygląd. */
  --red: #c0202e;
  --red-hot: #e02b3a;

  /* Kolor wiodący marki wdrożeniowej: przyciski, odnośniki, zaznaczenia.
     Domyślnie ten sam odcień co alarm, bo taki jest znak kotonski.pl.
     Wariant marki podmienia wyłącznie te dwie wartości. */
  --marka: #c0202e;
  --marka-mocna: #e02b3a;

  --paper: #f7f7f8;
  --white: #ffffff;

  /* Tło belki nagłówka. Ciemniejsze od tła strony, bo belka w kolorze tła
     zlewała się z przerwami między kartami i przy kilku sekcjach pod rząd
     nie było widać, gdzie zaczyna się następna.

     Rozjaśnione z #ececed, bo to najciemniejsze z jasnych teł i to na nim
     wychodziły najsłabsze kontrasty w całym panelu. Różnica względem tła
     strony zostaje widoczna, a szarości na belce mieszczą się w normie. */
  --belka: #f2f2f4;

  --line: #dedee2;
  --line-soft: #ececef;
  /* Stopień między czernią treści a szarością podpisów: nagłówki belek,
     które mają być czytelne jako tytuł sekcji, ale nie krzyczeć jak dane. */
  --ink-2: #45454f;

  /**
   * Dwa stopnie szarości tekstu, oba czytelne.
   *
   * Wcześniej `--muted-2` miało #9a9aa4, czyli 2,79:1 na bieli przy wymaganych
   * 4,5:1. Chodziło o podpowiedzi pod polami, nagłówki tabel i podpisy przy
   * danych, czyli o teksty, które redaktor czyta przy pierwszym kontakcie
   * z każdym formularzem. Zmierzone na dziewięciu ekranach panelu: to była
   * najczęstsza wada kontrastu w całym interfejsie.
   *
   * Wniosek ogólniejszy: **hierarchię buduje rozmiar i grubość, nie jasność**.
   * Tekst wyblakły do granicy czytelności nie jest „cichszy”, tylko trudniejszy,
   * a przy gorszym wzroku albo słabym monitorze po prostu znika. Dwa stopnie
   * zostają, ale oba mieszczą się w normie na każdym tle panelu.
   */
  --muted: #5f5f69;
  --muted-2: #6e6e79;
  --ok: #17734a;
  --ok-bg: #e6f4ec;
  --warn: #8a5a00;
  --warn-bg: #fdf3df;
  --info: #1c5a94;
  --info-bg: #e8f1f9;
  --err-bg: #fbe9eb;
  /* Obramowanie przycisku usuwania: jaśniejsze od napisu, żeby guzik nie
     wyglądał na wciśnięty, zanim ktokolwiek go dotknie. */
  --err-ramka: #e8b8bd;
  --ui: "Segoe UI", system-ui, -apple-system, sans-serif;
  --mono: ui-monospace, Consolas, "Cascadia Mono", monospace;

  /* Skala rozmiaru pisma panelu. Te same wartości co dotąd, ale w jednym
     miejscu, a nie rozsypane po ponad stu regułach: zmiana kroku (albo całości
     przy dostrajaniu czytelności) idzie tu, nie przez cały arkusz. Kroki są
     gęste, bo panel operuje drobnym pismem UI; nagłówki jednorazowe (tytuł
     ekranu, duże liczby) zostają literałami tam, gdzie stoją. */
  --fs-1: 11.5px;  /* najdrobniejsze: podpowiedzi, wersalikowe etykiety */
  --fs-2: 12px;    /* etykiety pól, drobny tekst pomocniczy */
  --fs-3: 12.5px;
  --fs-4: 13px;    /* podstawowy tekst interfejsu */
  --fs-5: 13.5px;
  --fs-6: 14px;
  --fs-7: 15px;    /* największy z powtarzalnych: wyróżnione etykiety */
}

/* Wariant marki wdrożeniowej.
   Podmieniamy wyłącznie kolor wiodący, bo układ, odstępy i typografia
   są tym samym produktem sprzedawanym pod dwoma znakami. Brąz e-parafii
   wzięty wprost z jej znaku graficznego, nie dobrany na oko. */
[data-marka="eparafia"] {
  --marka: #58362b;
  --marka-mocna: #74483a;
}

/**
 * Motyw ciemny.
 *
 * Podmiana samych zmiennych, bez ani jednej reguły układu: dzięki temu każdy
 * ekran, także ten dopisany za rok, dostaje ciemną wersję bez dokładania
 * czegokolwiek.
 *
 * Kolory dobrane od nowa, a nie odwrócone. Przyciemniona jasna paleta daje
 * szarości, które na czarnym tle wyglądają na brudne, a kolory znaczeniowe
 * (zielony, bursztynowy, czerwony) po prostu gasną. Tła stanów są tu ciemne
 * i nasycone, a napisy jaśniejsze niż w motywie jasnym.
 *
 * Tło nie jest czarne, tylko grafitowe: czysta czerń przy jasnym tekście daje
 * efekt drgania liter, zwłaszcza na tanich matrycach biurowych.
 */
:root {
  /* Źródło barw motywu ciemnego. Wartości leżą tutaj raz, a reguły niżej
     tylko przypisują je do zwykłych zmiennych. Dzięki temu poprawka odcienia
     jest w jednym miejscu, choć przypisania są dwa: dla wyboru wprost
     i dla ustawienia systemu. */
  --c-ink: #e8e8ec;
  --c-graphite: #16161a;
  --c-rail: #101014;
  --c-paper: #16161a;
  --c-white: #1d1d22;
  --c-belka: #24242b;
  --c-line: #34343d;
  --c-line-soft: #2a2a32;
  --c-ink-2: #b9b9c2;
  --c-muted: #a0a0ab;
  --c-muted-2: #74747f;
  --c-ok: #58c68d;
  --c-ok-bg: #16311f;
  --c-warn: #e0aa4a;
  --c-warn-bg: #33280f;
  --c-info: #6db2e8;
  --c-info-bg: #14293a;
  --c-err-bg: #3a1418;
  --c-err-ramka: #5e2b31;

  /* Czerwień z jasnego motywu na ciemnym tle robi się bura, więc jaśniejsza
     w obu odcieniach. Znaczenie zostaje to samo. */
  --c-red: #e04455;
  --c-red-hot: #f2596a;

  /* Brąz e-parafii rozjaśniony: w oryginale jest ciemniejszy od tła panelu
     i znak zniknąłby w tle. */
  --c-eparafia: #c08a6d;
  --c-eparafia-mocna: #d8a68a;
}

/* Przypisanie barw ciemnych. Wydzielone do zmiennej, żeby oba przypadki
   (wybór wprost i ustawienie systemu) korzystały z tych samych wartości. */
[data-motyw="ciemny"] {
  --ink: var(--c-ink);
  --graphite: var(--c-graphite);
  --rail: var(--c-rail);
  --paper: var(--c-paper);
  --white: var(--c-white);
  --belka: var(--c-belka);
  --line: var(--c-line);
  --line-soft: var(--c-line-soft);
  --ink-2: var(--c-ink-2);
  --muted: var(--c-muted);
  --muted-2: var(--c-muted-2);
  --ok: var(--c-ok);
  --ok-bg: var(--c-ok-bg);
  --warn: var(--c-warn);
  --warn-bg: var(--c-warn-bg);
  --info: var(--c-info);
  --info-bg: var(--c-info-bg);
  --err-bg: var(--c-err-bg);
  --err-ramka: var(--c-err-ramka);
  --red: var(--c-red);
  --red-hot: var(--c-red-hot);
  --marka: var(--c-red);
  --marka-mocna: var(--c-red-hot);
}
[data-motyw="ciemny"][data-marka="eparafia"] {
  --marka: var(--c-eparafia);
  --marka-mocna: var(--c-eparafia-mocna);
}

/**
 * Wybór „jak w systemie”.
 *
 * Nie ustawia atrybutu, więc rozstrzyga ustawienie Windowsa albo telefonu.
 * Warunek na braku atrybutu jest istotny: osoba, która wybrała jasny wprost,
 * ma dostać jasny nawet przy ciemnym systemie.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-motyw]) {
    --ink: var(--c-ink);
    --graphite: var(--c-graphite);
    --rail: var(--c-rail);
    --paper: var(--c-paper);
    --white: var(--c-white);
    --belka: var(--c-belka);
    --line: var(--c-line);
    --line-soft: var(--c-line-soft);
    --ink-2: var(--c-ink-2);
    --muted: var(--c-muted);
    --muted-2: var(--c-muted-2);
    --ok: var(--c-ok);
    --ok-bg: var(--c-ok-bg);
    --warn: var(--c-warn);
    --warn-bg: var(--c-warn-bg);
    --info: var(--c-info);
    --info-bg: var(--c-info-bg);
    --err-bg: var(--c-err-bg);
    --err-ramka: var(--c-err-ramka);
    --red: var(--c-red);
    --red-hot: var(--c-red-hot);
    --marka: var(--c-red);
    --marka-mocna: var(--c-red-hot);
  }
  :root:not([data-motyw])[data-marka="eparafia"] {
    --marka: var(--c-eparafia);
    --marka-mocna: var(--c-eparafia-mocna);
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--ui);
  font-size: var(--fs-6);
  line-height: 1.6;
}

a { color: var(--marka); }

/* Atrybut `hidden` przegrywa z każdą własną regułą ustawiającą `display`,
   bo styl przeglądarki ma najniższą wagę. Element chowany skryptem zostawał
   wtedy na ekranie, a przyczyna siedziała kilkaset linijek dalej, przy
   zupełnie innym elemencie. Jedna reguła tutaj zamiast łatania tego po kolei
   w każdym miejscu, w którym coś chowamy. */
[hidden] { display: none !important; }

/**
 * Widoczne zaznaczenie aktywnego pola.
 *
 * Nie z powodu przepisów, bo te dotyczą strony publicznej, a nie panelu:
 * po prostu przy wypełnianiu formularza tabulatorem trzeba widzieć, gdzie
 * się stoi. Obszar pisania w edytorze gasi tę obwódkę u siebie, bo tam
 * zaznacza ostrość własną ramką.
 *
 * Kierunek przesunięcia zależy od tego, czy element ma własną ramkę.
 */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--marka);
  outline-offset: 2px;
}

/* Elementy z własną ramką: obwódka wchodzi na nią. Przy przesunięciu na
   zewnątrz zostawała między nimi biała szczelina i zaznaczone pole miało dwie
   kreski zamiast jednej, przez co wyglądało grubiej, niż wynika z dwóch pikseli. */
button:focus-visible,
input:not(:where([type="checkbox"], [type="radio"])):focus-visible,
select:focus-visible,
textarea:focus-visible,
a.przycisk:focus-visible {
  outline-offset: -1px;
}

/* Wyjątek: przycisk wypełniony kolorem marki. Obwódka w środku wpadłaby
   w to samo tło i zaznaczenie zniknęłoby akurat na przycisku, który kończy
   pracę nad formularzem. Wraca więc na zewnątrz, na białe tło strony. */
.przycisk-glowny:focus-visible { outline-offset: 2px; }

.pomin-do-tresci {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--white);
  padding: 12px 18px;
  z-index: 100;
}
.pomin-do-tresci:focus { left: 0; }

/* ---------- logowanie ---------- */

.log-strona {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1.05fr 1fr;
}
.log-lewa {
  background: var(--graphite);
  color: #fff;
  padding: 48px 44px;
  display: flex;
  flex-direction: column;
}
/* Marginesy auto w kolumnie flex wypychają nazwę na środek w pionie,
   a stopka zostaje przy dolnej krawędzi. */
.log-lewa h1 {
  margin: auto 0;
  font-size: 32px;
  line-height: 1.25;
  font-weight: 300;
  letter-spacing: -0.01em;
}
.log-lewa .stopka { font-family: var(--mono); font-size: var(--fs-2); color: #6a6a76; line-height: 1.9; }
.log-lewa .stopka a { color: #9a9aa6; }
.log-prawa {
  background: var(--white);
  padding: 48px 44px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 16px;
}
.log-logo { display: block; width: 190px; max-width: 70%; height: auto; margin: 0 auto 22px; }

/* ---------- formularze ---------- */

/**
 * Wygląd pola: jedna reguła na cały panel.
 *
 * Celowo bez zawężenia do `.pole`. Pola stoją też w wierszach tabeli i w paskach
 * filtrów, a dopóki reguła obejmowała wyłącznie formularze, tamte dostawały
 * wygląd ręcznie w atrybucie `style` i każde miało własny rozmiar czcionki
 * i własne odstępy. Trzy wyglądy pola w jednym panelu to trzy razy dłuższa
 * nauka obsługi.
 *
 * Wyliczanie typów po kolei skończyło się tym, że datetime-local wypadł z listy
 * i wyglądał inaczej niż reszta. Odwracamy warunek: stylujemy każde pole poza
 * tymi, które rysuje system, więc nowy typ dostanie wygląd sam. Wyjątki siedzą
 * w :where(), żeby nie podbijały swoistości reguły: bez tego sam warunek waży
 * tyle co trzy klasy i nie da się go nadpisać klasą.
 */
input:not(:where([type="checkbox"], [type="radio"], [type="file"], [type="color"], [type="hidden"], [type="submit"])),
select,
textarea {
  border: 1px solid var(--line);
  padding: 10px 12px;
  font-size: var(--fs-6);
  font-family: var(--ui);
  background: var(--white);
  color: var(--ink);
}

/* Lista rozwijana z własną strzałką zamiast systemowej: systemowa ma w każdej
   przeglądarce inny rozmiar i inny odstęp, więc pole obok zwykłego wejścia
   tekstowego wyglądało bez powodu na wyższe albo węższe. */
select {
  appearance: none;
  padding-right: 34px;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8a95' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  background-size: 13px;
}
select:hover { border-color: var(--muted-2); }

.pole { display: flex; flex-direction: column; gap: 5px; }
.pole label { font-size: var(--fs-2); font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); }
/* Odnośnik w etykiecie pola (np. „Kod mapy z Google”) w barwie marki, żeby
   było widać, że to klikalne, a nie część wersalikowego napisu. */
.pole label a { color: var(--marka); text-decoration: none; }
.pole label a:hover { text-decoration: underline; }

/* Pole niosące nazwę całego wpisu: grubszym krojem, bo to ono nazywa rzecz,
   a pozostałe pola karty tylko ją doprecyzowują. */
.pole-mocne { font-weight: 700; }

/* Podpis grupy pól, w tej samej formie co etykieta pojedynczego pola: grupa
   opcji jest dla czytającego takim samym ustawieniem jak pole tekstowe. */
.etykieta-grupy {
  font-size: var(--fs-2); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.1em; color: var(--muted); padding: 0;
}

/* Dwa pola obok siebie, gdy odpowiadają na to samo pytanie. Na wąskim ekranie
   wracają jedno pod drugie, bo dwie kolumny na telefonie to dwa ścięte pola. */
.pola-para { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }
@media (max-width: 760px) { .pola-para { grid-template-columns: 1fr; } }

/* === WYBÓR TYPU KATEGORII ===
   Dwie osobne figury: rząd kafli i panel z ustawieniami pod nim. Bez ramki
   wspólnej i bez sklejania jednego z drugim. Próby zrośnięcia kafla z panelem
   kończyły się uskokiem na krawędzi, bo zaokrąglenia i szerokości kolumn liczą
   się niezależnie. Obie figury są na pełną szerokość karty, więc zgadzają się
   same z siebie, przy każdym oknie. */

/* === KAFLE TYPU KATEGORII ===
   Cztery możliwości obok siebie, każda w barwie swojego typu, tej samej co
   plakietka w wykazie struktury. Kropka wyboru u góry, nad ikoną: przy czterech
   kaflach w rzędzie oko szuka zaznaczenia w jednej linii. */
/* Fieldset tylko wiąże grupę dla czytnika ekranu, całe rysowanie robi siatka
   w środku: sam fieldset dokłada własne wcięcie poziome, inne w każdej
   przeglądarce, i rząd kafli przestawał się zgadzać z blokiem pod nim. */
.grupa-typow { border: 0; padding: 0; margin: 0; min-inline-size: 0; }
.grupa-typow > .etykieta-grupy { display: block; margin-bottom: 8px; }

.typy-kafle { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
@media (max-width: 900px) { .typy-kafle { grid-template-columns: repeat(2, 1fr); } }

.typ-kafel {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 7px; padding: 14px 12px 16px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--white); cursor: pointer;
}

.typ-kafel:hover { background: var(--paper); }
.typ-kafel input { margin: 0; accent-color: var(--akcent); }
/* Obwódka wejścia klawiaturą w barwie kafla: czerwona na bursztynowym tle
   wyglądała jak ostrzeżenie. */
.typ-kafel input:focus-visible { outline: 2px solid var(--akcent); outline-offset: 2px; }
.typ-kafel svg { width: 26px; height: 26px; color: var(--akcent); }
.typ-kafel b { font-size: var(--fs-4); color: var(--ink); }
.typ-kafel .wskazowka { text-align: center; }

/* Wybrany kafel bierze barwę swojego typu na ramkę i na tło. */
.typ-kafel:has(input:checked) { border-color: var(--akcent); background: var(--akcent-tlo); }

.typ-kafel-naglowek { --akcent: var(--ink-2); --akcent-tlo: var(--belka); }
.typ-kafel-artykuly { --akcent: var(--info); --akcent-tlo: var(--info-bg); }
.typ-kafel-tekst    { --akcent: var(--ok);   --akcent-tlo: var(--ok-bg); }
.typ-kafel-link     { --akcent: var(--warn); --akcent-tlo: var(--warn-bg); }

/* === USTAWIENIA WYBRANEGO TYPU ===
   Pola dobrane do zaznaczonego kafla, tuż pod nim. Przełącza je sam CSS przez
   `:has()`, więc działa bez skryptu, tak jak reszta tego formularza. Wcześniej
   wszystkie cztery zestawy stały pod sobą z dopiskiem „(typ: odnośnik)”
   i trzeba było zgadywać, które z nich w ogóle dotyczą tej kategorii.

   Blok jest przedłużeniem wybranego kafla: bierze jego tło, a od kafli dzieli
   go jedna kreska. Własnej ramki nie ma, bo zamyka go ramka pojemnika. */
.ustawienia-typu,
.gdy-link, .gdy-tresc, .gdy-artykuly, .gdy-uklad,
.napis-gdy-tekst, .napis-gdy-artykuly { display: none; }

/* Blok pokazuje się dla każdego typu poza nagłówkiem, który nie ma ustawień. */
.wybor-typu:has(.typ-kafel-link input:checked)     .ustawienia-typu,
.wybor-typu:has(.typ-kafel-artykuly input:checked) .ustawienia-typu,
.wybor-typu:has(.typ-kafel-tekst input:checked)    .ustawienia-typu {
  display: flex; flex-direction: column; gap: 16px;
}

/* Części w środku bloku, dobrane do typu. Edytor treści obsługuje dwa typy
   naraz: przy stronie z tekstem jest jej treścią, przy wykazie wstępem. */
.wybor-typu:has(.typ-kafel-link input:checked)     .gdy-link,
.wybor-typu:has(.typ-kafel-artykuly input:checked) .gdy-uklad,
.wybor-typu:has(.typ-kafel-artykuly input:checked) .gdy-artykuly,
.wybor-typu:has(.typ-kafel-artykuly input:checked) .gdy-tresc,
.wybor-typu:has(.typ-kafel-tekst input:checked)    .gdy-tresc {
  display: flex; flex-direction: column; gap: 12px;
}
.wybor-typu:has(.typ-kafel-tekst input:checked)    .napis-gdy-tekst { display: inline; }
.wybor-typu:has(.typ-kafel-artykuly input:checked) .napis-gdy-artykuly { display: inline; }
.wybor-typu:has(.typ-kafel-artykuly input:checked) label.napis-gdy-artykuly { display: flex; }

/* Kafle układu wykazu: ten sam wygląd co kafle typu, tylko bez barw. Rysunek
   zamiast samego napisu, bo „kafelki z wyróżnieniem" trzeba sobie wyobrazić. */

/* Kafle układu stoją w barwnym panelu, więc nie mają własnego białego tła:
   biały prostokąt na niebieskim czytał się jak osobna karta, a to jest jedno
   ustawienie w środku sekcji. Wybór niesie kropka i ciemniejszy odcień tego
   samego błękitu. Siatka zawija się sama, bo układów ma z czasem przybyć. */
.kafle-ukladu { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.typ-kafel-uklad {
  --akcent: var(--info);
  padding: 12px 10px 14px;
  background: transparent;
  border-color: color-mix(in srgb, var(--info) 22%, transparent);
}
.typ-kafel-uklad b { font-size: var(--fs-3); font-weight: 600; }
.typ-kafel-uklad:hover { background: color-mix(in srgb, var(--info) 8%, transparent); }
.typ-kafel-uklad:has(input:checked) {
  background: color-mix(in srgb, var(--info) 18%, transparent);
  border-color: color-mix(in srgb, var(--info) 45%, transparent);
}

/* Pole na jedną liczbę nie ma zajmować połowy karty. */
.pole-waskie { max-width: 260px; }

.ustawienia-typu {
  margin-top: 8px;
  padding: 16px;
  border: 1px solid var(--akcent-typu, var(--line));
  border-radius: 8px;
  background: var(--tlo-typu, var(--paper));
}

/* Odstęp nad wyborem typu: to najważniejsza decyzja w tym formularzu i nie ma
   się zlewać z polami nad nią. */
.wybor-typu { margin-top: 12px; }
.wybor-typu:has(.typ-kafel-link input:checked)     { --akcent-typu: var(--warn); --tlo-typu: var(--warn-bg); }
.wybor-typu:has(.typ-kafel-artykuly input:checked) { --akcent-typu: var(--info); --tlo-typu: var(--info-bg); }
.wybor-typu:has(.typ-kafel-tekst input:checked)    { --akcent-typu: var(--ok);   --tlo-typu: var(--ok-bg); }

/* Tekst w barwnym bloku dopasowany do tła, żeby nie robił się brudny: etykiety
   i legendy w ciemnym odcieniu barwy typu, podpowiedzi jeszcze ciemniejsze,
   bliżej czerni. Szary domyślny na kolorowym tle wygląda jak zabrudzenie.
   Dotyczy boksów i struktury strony, bo obie używają `--akcent-typu`. */
.ustawienia-typu .pole label,
.ustawienia-typu .pole-podgrupa,
.ustawienia-typu legend,
.ustawienia-typu .etykieta-grupy {
  color: color-mix(in srgb, var(--akcent-typu, var(--ink-2)) 70%, var(--ink));
}
.ustawienia-typu .wskazowka {
  color: color-mix(in srgb, var(--akcent-typu, var(--ink-2)) 26%, var(--ink));
}

/* Pola w środku na bieli, żeby odcinały się od barwnego tła bloku. */
.ustawienia-typu input,
.ustawienia-typu select,
.ustawienia-typu textarea { background: var(--white); }

/* === RODZAJ BOKSU ===
   Ten sam schemat kafli co typ kategorii wyżej, tylko dla czterech rodzajów
   boksu, każdy w innej barwie. Pola dobrane do rodzaju siedzą w bloku pod
   kaflami i przełącza je sam CSS przez `:has()`, bez skryptu. */
.typ-kafel-tresc   { --akcent: var(--ok);     --akcent-tlo: var(--ok-bg); }
.typ-kafel-liczby  { --akcent: var(--info);   --akcent-tlo: var(--info-bg); }
.typ-kafel-kafelki { --akcent: var(--ink-2);  --akcent-tlo: var(--belka); }
.typ-kafel-film    { --akcent: var(--red);    --akcent-tlo: var(--err-bg); }
.typ-kafel-mapa    { --akcent: var(--warn);   --akcent-tlo: var(--warn-bg); }

.wybor-typu:has(.typ-kafel-tresc input:checked)   { --akcent-typu: var(--ok);    --tlo-typu: var(--ok-bg); }
.wybor-typu:has(.typ-kafel-liczby input:checked)  { --akcent-typu: var(--info);  --tlo-typu: var(--info-bg); }
.wybor-typu:has(.typ-kafel-kafelki input:checked) { --akcent-typu: var(--ink-2); --tlo-typu: var(--belka); }
.wybor-typu:has(.typ-kafel-film input:checked)    { --akcent-typu: var(--red);   --tlo-typu: var(--err-bg); }
.wybor-typu:has(.typ-kafel-mapa input:checked)    { --akcent-typu: var(--warn);  --tlo-typu: var(--warn-bg); }

/* Blok ustawień boksu pokazuje się dla każdego rodzaju: każdy ma swoje pola. */
.wybor-typu:has(.typ-kafel-tresc input:checked)   .ustawienia-boksu,
.wybor-typu:has(.typ-kafel-liczby input:checked)  .ustawienia-boksu,
.wybor-typu:has(.typ-kafel-kafelki input:checked) .ustawienia-boksu,
.wybor-typu:has(.typ-kafel-film input:checked)    .ustawienia-boksu,
.wybor-typu:has(.typ-kafel-mapa input:checked)    .ustawienia-boksu {
  display: flex; flex-direction: column; gap: 16px;
}

/* Części w środku bloku, dobrane do rodzaju: widać tylko tę pasującą. */
.gdy-b-tresc, .gdy-b-liczby, .gdy-b-kafelki, .gdy-b-film, .gdy-b-mapa { display: none; }
.wybor-typu:has(.typ-kafel-tresc input:checked)   .gdy-b-tresc,
.wybor-typu:has(.typ-kafel-liczby input:checked)  .gdy-b-liczby,
.wybor-typu:has(.typ-kafel-kafelki input:checked) .gdy-b-kafelki,
.wybor-typu:has(.typ-kafel-film input:checked)    .gdy-b-film,
.wybor-typu:has(.typ-kafel-mapa input:checked)    .gdy-b-mapa {
  display: flex; flex-direction: column; gap: 16px;
}

/* Pojedynczy przełącznik w jednej linii z napisem, bez wersalikowej etykiety
   nad nim: to zdanie, a nie osobne ustawienie z tytułem. */
.opcja-plaska {
  display: flex; gap: 8px; align-items: center;
  font-size: var(--fs-4); color: var(--ink); cursor: pointer;
}

/* Grupa opcji zachowuje się jak zwykłe pole formularza. */
.grupa-opcji { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 5px; }

/* Kategoria nadrzędna przygaszona, gdy pozycja stoi poza menu: wtedy nic nie
   zmienia, bo poza menu nie ma czego zagnieżdżać. Przygaszona, a nie wyłączona:
   wyłączone pole nie idzie w żądaniu, więc zapis po cichu wyrzuciłby przypisanie
   do rodzica, a wykaz „Poza menu" pokazuje przy pozycji, gdzie leży. */
.zakladki-grupa:has(input[name="w_menu"][value="0"]:checked) .pole-rodzic { opacity: 0.5; }
.pole-rodzic { transition: opacity 0.15s; }

/* W kolumnie formularza pole zajmuje całą szerokość; w wierszu tabeli
   czy w pasku filtrów szerokość ustala kontekst, nie pole. */
.pole input:not(:where([type="checkbox"], [type="radio"], [type="file"], [type="color"])),
.pole select,
.pole textarea { width: 100%; }

/**
 * Ustawienia w jednej linii z etykietą.
 *
 * Dla ustawień, które są jedną liczbą albo jednym słowem. Etykieta nad polem
 * na całą szerokość karty robi z takiego ustawienia pozycję ważniejszą, niż
 * jest, a lista trzech liczb pod sobą rozciąga kartę na pół ekranu.
 *
 * Siatka stoi na wspólnym pojemniku, a same pola mają display: contents,
 * więc etykiety, pola i jednostki ze wszystkich wierszy trafiają do tych samych
 * kolumn. Przy osobnej siatce na każdy wiersz szerokość kolumny wyznaczała
 * własna etykieta i pola stały w trzech różnych miejscach.
 *
 * justify-content trzyma całość przy lewej krawędzi: rozciągnięta na szerokość
 * karty zostawiała między etykietą a polem pół ekranu pustki.
 */
.pola-liniowe {
  display: grid;
  grid-template-columns: max-content minmax(90px, 120px) max-content;
  justify-content: start;
  align-items: center;
  gap: 10px 14px;
}
.pole-liniowo { display: contents; }
.pole-liniowo label { text-transform: none; letter-spacing: 0; font-size: var(--fs-4); font-weight: 400; color: var(--ink); }
.pole-liniowo input { width: 100%; text-align: right; font-variant-numeric: tabular-nums; }
.pole-liniowo .pole-sufiks { font-size: var(--fs-4); color: var(--muted); }
.pole-liniowo .wskazowka { grid-column: 2 / -1; margin-top: -4px; }

/* Pole w wierszu tabeli albo w pasku nad wykazem: ten sam wygląd, mniej
   miejsca, bo stoi obok przycisków, a nie pod własną etykietą. */
.pole-male,
.pole-male input,
.pole-male select { padding: 6px 10px; font-size: var(--fs-4); }

/* Pasek szukania w nagłówku karty. `stretch` zamiast `center`, bo przyciski
   i pole liczą swoją wysokość z innych składników: pole z wysokości wiersza
   ustalanej przez przeglądarkę, przycisk z własnych odstępów. Wyrównane środkiem
   różniły się wtedy o kilka pikseli na górze i na dole. */
.pasek-szukania {
  display: flex; gap: 6px; align-items: stretch;
  text-transform: none; letter-spacing: 0; font-weight: 400;
}

/* Pole na wartość, którą się przepisuje znak po znaku, nie czyta zdaniami:
   kod koloru, numer. Krój o stałej szerokości nie pozwala pomylić zera z O. */
.pole-kod { font-family: var(--mono); }

/* Podgląd mapy dojazdu: pokazuje, że wklejony adres prowadzi tam, gdzie trzeba.
   Sam adres z Google nie mówi o tym nic, bo to ciąg kilkuset znaków. */
.mapa-podglad { border: 1px solid var(--line); line-height: 0; }
.mapa-podglad iframe { width: 100%; height: 260px; border: 0; }

/* Próbnik koloru. Przeglądarka rysuje jego wnętrze sama, więc dostaje
   wyłącznie ramkę i rozmiar, żeby stał w jednej linii z polem obok. */
/* Kropka w polu wyboru i ptaszek w kwadraciku rysuje przeglądarka i domyślnie
   robi je błękitne, czyli w kolorze, którego w panelu nie ma nigdzie indziej.
   Jedna właściwość ustawia to na kolor marki, więc zmienia się razem z nią. */
input[type="checkbox"],
input[type="radio"] { accent-color: var(--marka); }

input[type="color"] {
  width: 38px; height: 36px;
  border: 1px solid var(--line);
  padding: 2px;
  background: var(--white);
  cursor: pointer;
}
/* Pole, które jest najważniejsze na ekranie: tytuł wpisu, nazwa kategorii.
   Wygląda jak nagłówek, którym się stanie na stronie. */
.pole input.pole-mocne { font-size: 17px; font-weight: 700; padding: 12px; }

/* Podpis pod polem jaśniejszy od zwykłego tekstu pomocniczego: to przypis
   do jednego pola, czytany raz, a nie treść ekranu. Reguła bez rodzica, bo
   wskazówka wisi też pod wgrywarką, która polem formularza nie jest. */
/* Podpowiedź pod polem. To najczęściej czytany drobny tekst w panelu: mówi,
   co wpisać i dlaczego, więc redaktor patrzy na nią przy pierwszym kontakcie
   z każdym formularzem. Dwanaście i pół punktu zamiast jedenastu i pół, bo
   przy takiej roli oszczędzanie na rozmiarze jest oszczędzaniem na zrozumieniu. */
.wskazowka { font-size: var(--fs-3); color: var(--muted-2); line-height: 1.55; }
.wskazowka b { font-weight: 600; }
.pole .wskazowka b { color: var(--ink); }

.przycisk {
  font-family: var(--ui);
  font-size: var(--fs-4);
  padding: 10px 16px;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--ink);
  font-weight: 500;
  cursor: pointer;
  /* Przyciskiem bywa też odnośnik, więc zdejmujemy podkreślenie
     i wyrównujemy tekst tak, jak w elemencie button.
     Wyśrodkowanie flexem, a nie wysokością wiersza: przy polskich literach
     z ogonkami i z kreskami nad literami pudełko wiersza rośnie w dół, więc
     napis liczony wysokością wiersza siada odrobinę za wysoko. */
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  line-height: 1.3;
}
/* Stan najechania dla zwykłego przycisku. Musi stać przed odmianami, bo te
   mają własne reguły o tej samej swoistości i wygrywają kolejnością. */
.przycisk:hover { border-color: var(--marka); color: var(--marka); }

/* Przycisk bez możliwości działania: wygaszony i bez reakcji na najechanie.
   Strzałka kolejności przy pierwszej pozycji nie ma dokąd przesunąć, a klikana
   wracała na ten sam ekran bez żadnej zmiany, co czyta się jak zgubiony zapis. */
.przycisk:disabled { color: var(--muted-2); border-color: var(--line-soft); cursor: default; }
.przycisk:disabled:hover { border-color: var(--line-soft); color: var(--muted-2); }
.przycisk-glowny { background: var(--marka); border-color: var(--marka); color: #fff; font-weight: 600; }
.przycisk-niebezpieczny { color: var(--red); border-color: var(--err-ramka); }
/* Kolor i obramowanie powtórzone celowo: bez nich reguła bazowa dla najechania
   przemalowałaby przycisk usuwania na kolor marki, a to ma zostać czerwone. */
.przycisk-niebezpieczny:hover { background: var(--err-bg); color: var(--red); border-color: var(--red); }
/* Przywracanie z kosza: zielony, bo to jedyne działanie w tabeli, które coś
   odzyskuje, a stoi obok czerwonego, które kasuje bez odwrotu. */
.przycisk-odwrotny:hover { background: var(--ok-bg); color: var(--ok); border-color: var(--ok); }
.przycisk.maly { padding: 5px 10px; font-size: var(--fs-4); line-height: 1; }

/* Przycisk zwijania gałęzi. Szerokość równa pustemu miejscu przy pozycjach
   bez potomków, żeby nazwy w kolumnie zaczynały się w tej samej linii. */
.zwijak {
  width: 20px; height: 20px; flex-shrink: 0;
  display: grid; place-items: center;
  border: 1px solid var(--line); background: var(--white);
  color: var(--muted); font-size: var(--fs-1); line-height: 1; cursor: pointer; padding: 0;
}
.zwijak:hover { border-color: var(--muted-2); color: var(--ink); }
.zwijak svg { width: 11px; height: 11px; transition: transform 0.15s; }
.zwijak[aria-expanded="false"] svg { transform: rotate(-90deg); }
/* Puste miejsce dokładnie rozmiaru rozwijaczka: nazwy pozycji bez potomków
   mają stać w tej samej kolumnie co nazwy grup. */
.zwijak-pusty { width: 20px; height: 20px; flex-shrink: 0; display: inline-block; }

/* === DRZEWO STRUKTURY ===
   Samo wcięcie nie pokazywało zagnieżdżenia: przy dziewiętnastu pozycjach
   drzewo czytało się jak płaska lista, bo poziomy różniło dwadzieścia parę
   pikseli i nic poza tym. Kreska na każdy poziom, wysoka na cały wiersz,
   łączy się z kreską wiersza obok i rysuje pion, po którym widać, gdzie
   grupa się zaczyna i gdzie kończy. */
.drzewo-komorka { padding: 0 15px 0 0; }
.drzewo-wiersz { display: flex; align-items: stretch; min-height: 38px; }
.drzewo-kreska { width: 22px; flex-shrink: 0; border-right: 1px solid var(--line); }
.drzewo-tresc { display: flex; align-items: center; gap: 7px; padding: 7px 0 7px 13px; min-width: 0; }
/* Nazwa w jednej linii, zawsze. Gdy zabraknie miejsca, ustępuje adres
   odnośnika, a nie nazwa: adres jest dopiskiem, nazwa jest treścią wiersza,
   a złamana w połowie rozbija kolumnę i całe drzewo przestaje się skanować. */
.drzewo-etykieta { display: flex; align-items: baseline; gap: 8px; min-width: 0; white-space: nowrap; }
.drzewo-etykieta a { color: inherit; text-decoration: none; flex: 0 0 auto; }
.drzewo-etykieta a:hover { color: var(--marka); text-decoration: underline; }
.drzewo-etykieta .meta { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* Szare tło na pierwszym poziomie, czyli na pozycjach menu głównego.
   Tło mówi o głębokości, nie o tym, czy pozycja ma potomków: dzięki temu
   szare wiersze czyta się jako menu, a wcięte jako jego zawartość.
   Bez pogrubienia, bo grubość napisu ma w panelu znaczyć jedno i to samo
   wszędzie, a wyjątek w jednej tabeli każe się zastanawiać, o co chodzi.

   Odcień belki, nie papieru: papier ma trzy procent różnicy od bieli, tyle
   samo co podświetlenie wiersza pod kursorem, więc jedno zlewało się z drugim
   i z tłem karty naraz. Belka jest tym samym odcieniem, którym w całym panelu
   oznaczamy nagłówek sekcji, a pozycja menu głównego jest właśnie nagłówkiem
   swojej części struktury. */
tr.drzewo-poziom-1 > td {
  background: var(--belka);
  /* Kreska wiersza jest w kolorze bliskim belce, więc na szarym paśmie
     znikała i kilka pozycji menu pod rząd zlewało się w jeden blok.
     Mocniejsza kreska nad i pod: to granica sekcji, nie granica wiersza
     w środku sekcji, a przy zwiniętym drzewie właśnie ona niesie podział. */
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

/* Podświetlenie pod kursorem musi być widoczne także na szarych wierszach.
   Tło komórki zakrywa tło wiersza, więc zwykła reguła dla tr tu nie sięga. */
tbody tr.drzewo-poziom-1:hover > td { background: var(--line); }

/* Zakładki ustawień: zwykłe odnośniki, żeby dało się je otworzyć w nowej karcie.
   Odstęp od nagłówka strony jest tutaj, a nie w samym nagłówku: tytuł ekranu
   i pasek zakładek to dwa poziomy nawigacji i sklejone wyglądają jak jeden. */
.zakladki { display: flex; gap: 2px; margin-top: 16px; padding: 0 22px; border-bottom: 1px solid var(--line); background: var(--paper); flex-wrap: wrap; }
.zakladki a { padding: 11px 15px; font-size: var(--fs-4); color: var(--muted); text-decoration: none; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.zakladki a:hover { color: var(--ink); }
.zakladki a.wybrana { color: var(--ink); font-weight: 700; border-bottom-color: var(--marka); background: var(--white); }

/* Zamknięcie formularza: przycisk zapisu przy prawej krawędzi, czyli tam,
   dokąd doprowadza czytanie ostatniego pola. Przy lewej ginie w pionowej
   linii etykiet i wygląda jak kolejna pozycja formularza. */
.stopka-formularza { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }

/**
 * Formularz nowego tagu.
 *
 * Trzy elementy w jednej linii, wyrównane dolną krawędzią pola. Próbnik koloru
 * dostaje tę samą wysokość co pole tekstowe: przeglądarka rysuje jego wnętrze
 * sama i bez tego jest o kilka pikseli niższy, co przy sąsiedztwie przycisku
 * widać od razu.
 */
.tag-nowy { display: flex; flex-direction: column; gap: 6px; }
.tag-nowy-linia { display: flex; gap: 12px; align-items: end; flex-wrap: wrap; }
.tag-nowy-linia .pole:first-of-type { flex: 1; min-width: 220px; }
.tag-nowy-linia input[type="color"] { width: 52px; height: 40px; }
.tag-nowy-linia .przycisk { height: 40px; }

/* Nazwisko wersalikami na wykazach osób. Odstęp z boku zamiast spacji w treści,
   bo spacja przed elementem znika przy zawijaniu wiersza. */
.nazwisko { text-transform: uppercase; margin-left: 0.35em; }

.tag-podglad { display: inline-block; font-size: var(--fs-1); font-weight: 700; letter-spacing: 0.07em;
               text-transform: uppercase; padding: 4px 9px; }

/* Gwiazdka: skrót do szybkiego dodawania artykułu w tej kategorii. */
.gwiazdka {
  border: 0; background: none; padding: 4px; margin-right: 2px;
  color: var(--muted-2); cursor: pointer; vertical-align: middle;
}
.gwiazdka svg { width: 15px; height: 15px; display: block; }
/* Cała gwiazdka w szarości: o stanie mówi wypełnienie, nie barwa. Skrót do
   kategorii jest wygodą jednej osoby, a nie stanem treści, więc nie ma powodu,
   żeby przyciągał wzrok mocniej niż liczba artykułów obok.

   Najechanie pokazuje stan po kliknięciu: pusta ciemnieje, czyli zapowiada
   wypełnienie, a wypełniona blednie, czyli zapowiada zdjęcie skrótu. */
.gwiazdka:hover { color: var(--ink-2); }
.gwiazdka.wybrana { color: var(--ink-2); }
.gwiazdka.wybrana:hover { color: var(--muted-2); }

/* Podmenu pulpitu: wcięcie i pionowa kreska pokazują podległość, więc nie
   trzeba nad nim osobnego nagłówka grupy. */
.szyna-podmenu { border-left: 1px solid #2f2f38; margin: 2px 0 6px 16px; }
.szyna-podmenu a { padding-left: 13px; border-left: 0; }
.szyna-skrot { font-size: var(--fs-3); padding-top: 6px; padding-bottom: 6px; color: #a9a9b4; }
.szyna-skrot svg { flex-shrink: 0; opacity: 0.7; }

/* Wejście do wnętrza kategorii. Kolor marki i biały napis, bo to najczęściej
   klikane miejsce na tym ekranie i ma być widoczne z drugiego końca tabeli.

   Stała najmniejsza szerokość i cyfry o równej szerokości: bez tego pudełko
   rosłoby razem z liczbą i dział z dwoma wpisami stałby inaczej niż dział
   ze stoma. Napis pośrodku, więc jedno- i trzycyfrowe liczby siedzą tak samo. */
.wejscie {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 46px; padding: 5px 10px; border-radius: 6px;
  background: var(--marka); color: #fff; text-decoration: none;
  font-size: var(--fs-3); font-weight: 600; font-variant-numeric: tabular-nums;
}
/* Ciemniejszy odcień marki przy najechaniu, ten sam, co przy przycisku
   głównym: jedno zachowanie dla wszystkiego, co jest wypełnione kolorem. */
.wejscie:hover { background: var(--marka-mocna); color: #fff; }

/* Przeciąganie wierszy */
.uchwyt { color: var(--muted-2); cursor: grab; font-family: var(--mono); padding: 0 4px; user-select: none; }
.uchwyt:active { cursor: grabbing; }
.wiersz-przeciagany { opacity: 0.45; }
.wiersz-cel td { border-top: 2px solid var(--marka); }

.stan-zapisu {
  position: fixed; right: 20px; bottom: 20px; z-index: 60;
  background: var(--graphite); color: #fff; padding: 11px 16px; font-size: var(--fs-4);
}
.stan-zapisu.stan-blad { background: var(--red); }

/* Typ kategorii: kolor niesie znaczenie, ale nie jest jedynym nośnikiem,
   bo obok zawsze stoi nazwa typu. */
/* Stała szerokość, żeby ramki w kolumnie tworzyły równą pionową krawędź.
   Przy szerokości dopasowanej do tekstu lista wygląda na poszarpaną. */
/* Typ kategorii: własne tło i własny kolor napisu dla każdego z czterech
   rodzajów. Wypełnienie zamiast obramowania, bo na szarym paśmie pozycji menu
   głównego kontur gubił się w tle i plakietka wyglądała na wygaszoną.

   Para „blade tło, mocny napis" zamiast koloru pełnego: te same zmienne
   działają w motywie jasnym i ciemnym, gdzie role się odwracają, więc napis
   zostaje czytelny bez osobnego zestawu kolorów. Sam kolor niczego nie niesie:
   nazwa typu stoi w plakietce napisana wprost. */
.typ { display: inline-block; min-width: 96px; text-align: center;
       font-size: var(--fs-1); font-weight: 700; text-transform: uppercase;
       letter-spacing: 0.07em; padding: 4px 8px; border: 0; border-radius: 6px;
       background: var(--line); color: var(--ink-2); }
.typ-artykuly { background: var(--info-bg); color: var(--info); }
.typ-tekst { background: var(--ok-bg); color: var(--ok); }
.typ-link { background: var(--warn-bg); color: var(--warn); }
/* Nagłówek grupy jest jedynym typem bez własnej barwy, bo sam nie ma strony.
   Szarość ciemniejsza od tła pozycji menu głównego, inaczej plakietka znikała
   akurat w tych wierszach, w których nagłówków jest najwięcej. */
.typ-naglowek { background: var(--line); color: var(--ink-2); }
/* Biel napisu powtórzona, bo reguła bazowa dla najechania ustawia kolor tekstu
   na kolor marki, a tu jest on tłem: napis zniknąłby w przycisku. */
.przycisk-glowny:hover { background: var(--marka-mocna); border-color: var(--marka-mocna); color: #fff; }
.przycisk-szeroki { width: 100%; padding: 12px; }

.komunikat { padding: 11px 14px; font-size: var(--fs-5); display: flex; gap: 9px; align-items: flex-start; }
.komunikat-blad { background: var(--err-bg); border-left: 3px solid var(--red); }
.komunikat-ok { background: var(--ok-bg); border-left: 3px solid var(--ok); }
.komunikat-info { background: var(--info-bg); border-left: 3px solid var(--info); }
.komunikat-uwaga { background: var(--warn-bg); border-left: 3px solid #d9a441; }

.ip-info { font-size: var(--fs-1); color: var(--muted); font-family: var(--mono); display: flex; align-items: center; gap: 7px; }

/* ---------- układ panelu ---------- */

.panel { display: flex; min-height: 100vh; }

/* Kreska przy prawej krawędzi widoczna tylko w motywie ciemnym: tam szyna
   i obszar roboczy mają zbliżone tło i bez niej granica ginie. W jasnym
   granicę rysuje sama różnica czerni i bieli. */
.szyna { width: 218px; flex-shrink: 0; background: var(--rail); display: flex; flex-direction: column; }
[data-motyw="ciemny"] .szyna { border-right: 1px solid var(--line); }
@media (prefers-color-scheme: dark) {
  :root:not([data-motyw]) .szyna { border-right: 1px solid var(--line); }
}
/* Ta sama wysokość co pasek górny, żeby obie linie oddzielające leżały
   na jednym poziomie. Przy różnych wysokościach uskok rzuca się w oczy. */
/**
 * Głowa szyny ze znakiem.
 *
 * Kreska pod spodem w kolorze marki zastępuje szarą granicę: czerwień zostaje
 * akcentem, zamiast wypełniać całą płaszczyznę.
 *
 * Kreska ma dokładnie taką samą grubość i leży na tej samej wysokości co ta
 * pod paskiem górnym, bo obie ciągną się przez całą szerokość ekranu i różnica
 * jednego piksela na styku widać od razu.
 *
 * Rachunek: przez `box-sizing: border-box` obramowanie wlicza się w wysokość,
 * więc pasek górny o `min-height: 52px` kończy się na 52, a jego kreska zajmuje
 * 51..52. Tutaj znak ma 51 pikseli i 1 piksel kreski, czyli to samo.
 *
 * Grubsza kreska po tej stronie kusi, bo czerwień na ciemnym tle jest mniej
 * widoczna niż szarość na bieli, ale wtedy schodzi niżej niż sąsiadka i całość
 * wygląda na krzywo złożoną.
 */
.szyna-gora {
  display: block;
  border-bottom: 1px solid var(--marka);
  transition: border-color 0.12s;
}

/* Po najechaniu na znak kreska rozjaśnia się do mocniejszej czerwieni.
   Warunek na rodzicu, bo obramowanie należy do głowy szyny, a nie do samego
   odnośnika: gdyby siedziało na odnośniku, przesunęłoby napis o piksel. */
.szyna-gora:has(.szyna-znak:hover) { border-bottom-color: var(--marka-mocna); }
/* Znak na całą szerokość szyny, napis pośrodku. Mała plakietka przy lewej
   krawędzi, z numerem wersji obok, wyglądała jak naklejka na czarnym tle,
   a nie jak znak produktu. */
/* Selektor z nazwą elementu, bo zwykła reguła dla odnośników w szynie ma
   wyższą swoistość i inaczej narzuciłaby znakowi swoje odstępy i kolor. */
/* Selektor z nazwą elementu, bo zwykła reguła dla odnośników w szynie ma
   wyższą swoistość i inaczej narzuciłaby znakowi swoje odstępy i kolor. */
.szyna a.szyna-znak {
  min-height: 51px;
  display: flex; align-items: center;
  padding: 0 16px;
  font-family: var(--mono); font-size: var(--fs-7); font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: #fff; text-decoration: none;
  border-left: 0;
  transition: background-color 0.12s;
}

/* Ten sam odruch co przy pozycjach menu: tło jaśnieje, napis zostaje biały.
   Czerwony napis na prawie czarnym tle daje kontrast 4,1 : 1 i robi się mętny,
   a przy okazji znaczy co innego niż wszędzie indziej w panelu, gdzie czerwień
   niesie alarm albo działanie. */
.szyna a.szyna-znak:hover { background: #23232a; color: #fff; }
/* Nagłówki grup w szynie: „Moduły” i „Administracja”.
 *
 * Mają być ciche, bo nie są pozycjami menu, tylko podpisami nad nimi. Cisza
 * ma jednak granicę: przy #6a6a76 wychodziło 3,25:1 przy wymaganych 4,5:1.
 * Stąd #82828d, czyli 4,56:1, najciemniejszy odcień mieszczący się w normie
 * na tle szyny. Resztę wyciszenia bierze grubość pisma, obniżona z 600 do 500,
 * bo grubość nie ma progu, którego nie wolno przekroczyć.
 *
 * Rozmiar podniesiony z dziesięciu punktów: napis wersalikami z rozstrzeleniem
 * czyta się trudniej niż zwykły, a to on nazywa całą grupę pozycji pod spodem. */
.szyna-grupa { font-size: var(--fs-2); text-transform: uppercase; letter-spacing: 0.14em; color: #82828d; padding: 20px 16px 8px; font-weight: 500; }
.szyna a { display: flex; align-items: center; gap: 10px; padding: 9px 16px; color: #c3c3cc; text-decoration: none; border-left: 3px solid transparent; font-size: var(--fs-5); }
.szyna a:hover { background: #23232a; color: #fff; }
.szyna a.wybrana { background: #26262e; color: #fff; border-left-color: var(--marka-mocna); font-weight: 600; }
/* Numer wersji i marka na dole szyny. Rozjaśnione z #5d5d68, bo dawało
   2,67:1 na tle szyny: to jest napis, po który sięga się przy zgłoszeniu
   awarii, więc musi dać się odczytać, a nie tylko domyślić. */
.szyna-stopka { margin-top: auto; padding: 16px; font-family: var(--mono); font-size: var(--fs-2); color: #8a8a95; line-height: 1.7; border-top: 1px solid #2a2a31; }

.praca { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.pasek-gorny {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 22px; min-height: 52px; background: var(--white); border-bottom: 1px solid var(--line);
}
.okruszki { font-size: var(--fs-3); color: var(--muted); display: flex; gap: 7px; align-items: center; flex-wrap: wrap; }
/* Ostatni krok ścieżki bywa treścią wpisu, a komunikat ma prawo mieć pięćset
   znaków. Ucinamy wielokropkiem, zamiast łamać pasek na dwa wiersze albo
   przycinać w pół słowa. Pełny tekst zostaje w kodzie strony, więc czytnik
   ekranu przeczyta go w całości. */
.okruszki b {
  color: var(--ink); font-weight: 600;
  max-width: min(52ch, 100%);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.okruszki a { color: var(--muted); text-decoration: none; }
.okruszki a:hover { color: var(--ink); }
.kto { display: flex; align-items: center; gap: 8px; font-size: var(--fs-3); }
.kto .profil { display: flex; align-items: center; gap: 8px; color: var(--ink); text-decoration: none; padding: 4px; }
.kto .profil:hover { color: var(--marka); }
.kto .profil:hover .awatar { background: var(--marka); }
.kto .rola { color: var(--muted-2); font-size: var(--fs-2); }
.awatar { width: 26px; height: 26px; background: var(--graphite); color: #fff; display: grid; place-items: center; font-size: var(--fs-2); font-weight: 700; font-family: var(--mono); }

.naglowek-strony { padding: 22px 22px 0; display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.naglowek-strony h1 { margin: 0; font-size: 23px; font-weight: 700; letter-spacing: -0.01em; }
.naglowek-strony .podtytul { font-size: var(--fs-4); color: var(--muted); margin-top: 3px; }

/**
 * Fakty o rekordzie w delikatnych ramkach, zamiast jednego zdania rozdzielonego
 * kropkami. Każdy da się złapać wzrokiem osobno, a granice ramek pokazują,
 * gdzie kończy się jedna informacja, a zaczyna druga.
 *
 * Ramka jest jasna, a napis szary: to podpis pod tytułem, nie treść, i nie ma
 * przeciągać uwagi z nagłówka na siebie.
 */
.znaczniki { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
.znacznik {
  font-size: var(--fs-2); color: var(--muted);
  padding: 3px 9px;
  border: 1px solid var(--line);
  background: var(--white);
}
.znacznik b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.akcje { display: flex; gap: 8px; flex-wrap: wrap; }

.tresc-strony { padding: 20px 22px 32px; display: flex; flex-direction: column; gap: 18px; }


/**
 * Komunikat po zapisie.
 *
 * W kodzie strony stoi na samej górze, żeby czytnik ekranu podał go od razu
 * po przeładowaniu. Na ekranie ma być pod nagłówkiem i zakładkami, bo dotyczy
 * treści, a nie całego panelu, i nad tytułem wygląda jak komunikat systemowy.
 *
 * Stąd kolejność ustawiana we `flex`. Ujemne wartości, a nie dodatnie: elementy
 * bez własnej reguły mają `order: 0`, więc każdy nowy blok w widoku ustawi się
 * po komunikacie, a nie przed nagłówkiem.
 */
main#tresc { display: flex; flex-direction: column; }
main#tresc > .naglowek-strony { order: -3; }
main#tresc > .zakladki { order: -2; }
.komunikat-globalny { order: -1; padding: 18px 22px 0; }

/* ---------- karty, kafle, tabele ---------- */

/**
 * Zestawienie zawartości serwisu w prawej kolumnie pulpitu.
 *
 * Kafelki dwa na dwa wewnątrz karty, każdy jest wejściem do swojego działu.
 * Kreski rysują same komórki, a nie odstępy między nimi, więc całość czyta się
 * jak jedna tabliczka, a nie jak cztery osobne pudełka w pudełku.
 */
.zestawienie { display: grid; grid-template-columns: 1fr 1fr; }
.zestawienie a {
  display: flex; flex-direction: column; gap: 2px;
  padding: 13px 15px;
  border-right: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
  text-decoration: none; color: var(--ink);
}
.zestawienie a:nth-child(2n) { border-right: 0; }
.zestawienie a:nth-last-child(-n+2) { border-bottom: 0; }
.zestawienie a:hover { background: var(--paper); }
.zestawienie b { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; line-height: 1.1; }
.zestawienie span { font-size: var(--fs-2); color: var(--muted); }

/* Wiersz z zaległością na całą szerokość karty i w kolorze alarmu: to jedyna
   liczba, która mówi „zrób coś”, a nie „tyle tego jest”. Nieparzysta liczba
   pozycji rozjeżdżałaby siatkę, więc bierze obie kolumny naraz. */
.zestawienie .zestawienie-pilne { grid-column: 1 / -1; border-right: 0; }
.zestawienie .zestawienie-pilne b { color: var(--red); }
/* Zegar na pulpicie. Cyfry o stałej szerokości, bo inaczej całość drga przy
   każdej zmianie sekundy: w większości krojów jedynka jest węższa od reszty. */
.zegar {
  margin: 0;
  text-align: center;
  font-family: var(--mono);
  font-size: 40px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  /* Jaśniej niż treść: zegar nie niesie niczego, co wymaga decyzji, więc nie
     ma powodu, żeby ciągnął wzrok mocniej niż tytuły artykułów obok. */
  color: var(--muted);
  line-height: 1.2;
}
.zegar-data { margin: 2px 0 0; text-align: center; font-size: var(--fs-3); color: var(--muted); }
/* Ostatnie logowanie oddzielone kreską: to nie jest część zegara, tylko
   informacja o poprzedniej wizycie, która akurat też jest datą. */
.zegar-stopka {
  margin: 12px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--line-soft);
  text-align: center;
  font-size: var(--fs-1);
  color: var(--muted-2);
}
.zegar-stopka b { color: var(--muted); font-weight: 600; font-variant-numeric: tabular-nums; }

.kolumny { display: grid; grid-template-columns: 1.55fr 1fr; gap: 14px; align-items: start; }

/* Obie kolumny kończą się na jednej wysokości. Do ekranów, na których stoją
   dwie karty o zbliżonej zawartości i nierówne dolne krawędzie rzucają się
   w oczy. Domyślnie zostaje `start`, bo przy karcie z dwoma wierszami obok
   długiej listy rozciąganie robi z niej pustą białą płachtę. */
.kolumny-rowne { align-items: stretch; }

.karta { background: var(--white); border: 1px solid var(--line); }
/* Belka nagłówka na własnym tle, nie na bieli karty: sama wersalikowa,
   rozstrzelona etykieta ginęła w jednolitej płaszczyźnie i karta zaczynała się
   dopiero przy pierwszym polu. Kreska pod belką w kolorze obramowania, a nie
   jaśniejsza: to granica sekcji, a nie granica wiersza w środku sekcji. */
.karta-naglowek {
  padding: 11px 15px; border-bottom: 1px solid var(--line); background: var(--belka);
  font-size: var(--fs-2); font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--ink-2); display: flex; justify-content: space-between; align-items: center; gap: 10px;
}
.karta-naglowek a { text-transform: none; letter-spacing: 0; font-size: var(--fs-3); font-weight: 600; text-decoration: none; }
.karta-tresc { padding: 14px 15px; display: flex; flex-direction: column; gap: 11px; }

/* Karta zwijana: nagłówek jest przyciskiem <summary>, treść chowa się do
   kliknięcia. Domyślnie zwinięta, bo to zapis do wglądu, a nie treść pracy.
   Strzałka po prawej obraca się przy otwarciu. Działa bez skryptu, natywnym
   <details>, jak reszta rozwijanych sekcji panelu. */
.karta-zwijana > summary { cursor: pointer; list-style: none; }
.karta-zwijana > summary::-webkit-details-marker { display: none; }
.karta-zwijana > summary:hover { color: var(--ink); }
.karta-zwijana > summary:focus-visible { outline: 2px solid var(--marka); outline-offset: -2px; }
.karta-zwijana > summary .karta-strzalka { color: var(--muted-2); transition: transform 0.15s; }
.karta-zwijana[open] > summary .karta-strzalka { transform: rotate(90deg); }
.karta-zwijana[open] > summary { border-bottom: 1px solid var(--line); }

table { border-collapse: collapse; width: 100%; font-size: var(--fs-4); }
/* Nagłówki tabeli zostają na bieli: tabela zwykle stoi zaraz pod nagłówkiem
   karty i dwa szare pasy jeden na drugim zlewały się w jeden gruby blok. */
/* Wysokość wiersza jest wpisana na sztywno i jest wielokrotnością czterech,
   i to nie jest ozdoba. Bez własnej interlinii wiersz wychodził 43,8 punktu,
   a Windows rysuje panel przy powiększeniu 125 albo 150 procent. Wysokość
   ułamkowa zaokrągla się wtedy raz w górę, raz w dół, zależnie od tego, na
   jakiej wysokości ekranu wiersz akurat stoi, więc sąsiednie wiersze różniły
   się o piksel i było to gołym okiem widać. Przy 44 punktach 125 procent daje
   równe 55, a 150 procent równe 66, więc wszystkie wiersze wypadają identycznie.

   Zmieniając odstępy w wierszu: `padding` razy dwa plus interlinia plus kreska
   ma dawać liczbę podzielną przez cztery. Tu 20 + 23 + 1 = 44, w nagłówku
   18 + 17 + 1 = 36. */
th {
  text-align: left; font-size: var(--fs-1); text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--muted-2); font-weight: 700;
  padding: 9px 15px; line-height: 17px;
  border-bottom: 1px solid var(--line-soft);
}
td {
  padding: 10px 15px; line-height: 23px;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: middle;
}

/* Podświetlenie wiersza pod kursorem. Przy szerokiej tabeli oko gubi się
   w drodze od tytułu do przycisków przy prawej krawędzi, a tło trzyma je
   w jednej linii. Kolor tła strony, nie mocniejszy: to podpowiedź, gdzie
   jestem, a nie zaznaczenie. */
tbody tr:hover { background: var(--paper); }
/* Ostatni wiersz bez kreski na dole, bo zamyka go krawędź karty. Kreska
   traci barwę, a nie grubość: zdjęta w całości zabierała ze sobą swój piksel.
   To była jednak tylko połowa sprawy, drugą opisuje uwaga przy `td` wyżej. */
tr:last-child td { border-bottom-color: transparent; }
td.tytul { font-weight: 600; }
/* Wiersze tabeli są w całości klikalne, więc podkreślenie przy każdej nazwie
   robi z listy gąszcz linii. Pojawia się dopiero przy najechaniu. */
td.tytul a { color: inherit; text-decoration: none; }
td.tytul a:hover { color: var(--marka); text-decoration: underline; }
/* Druga linia w wierszu: kategoria, autor, data, adres e-mail. Pismem
   interfejsu i w jaśniejszej szarości, bo to podpis pod tytułem, a nie dane
   do przepisania znak po znaku. Krój maszynowy zostaje tam, gdzie faktycznie
   liczy się równa szerokość znaków, czyli w klasie .liczbowo. */
td .meta { font-size: var(--fs-2); color: var(--muted-2); font-family: var(--ui); font-weight: 400; }
td .meta-nazwa { font-size: var(--fs-2); }
.liczbowo { font-variant-numeric: tabular-nums; font-family: var(--mono); font-size: var(--fs-2); color: var(--muted); }

/* Kropka w miejscu wartości, której dla tego wiersza po prostu nie ma.
   Pusta komórka wygląda na brakujące dane, a kreska czytana jest jako minus. */
.pusta-komorka { color: var(--muted-2); }

/* Kolumna z działaniami dosunięta do prawej krawędzi tabeli: przyciski
   kończą wiersz i nie zostawiają po sobie pustego pasa. */
th.do-prawej, td.do-prawej { text-align: right; }

/* Plakietka nie może podwyższać wiersza tabeli, a domyślnie to robi: jako
   element liniowo-blokowy wchodzi do linii tekstu razem ze swoimi obwódkami
   i wypycha ją ponad interlinię komórki. Wiersz robił się wtedy wyższy
   i ułamkowy, a przy powiększeniu ekranu sąsiednie wiersze zaokrąglały się
   różnie i jeden wychodził niższy od drugiego.

   Własna interlinia daje plakietce 16 plus dwa razy 3, czyli 22 punkty,
   a ujemny odstęp po 3 z góry i z dołu zdejmuje z linii dokładnie to, co
   dokłada wypełnienie. Linia zostaje przy 23 punktach komórki, wiersz przy 44,
   a sama plakietka wygląda tak samo jak wcześniej. */
.plakietka {
  display: inline-block;
  font-size: var(--fs-1); font-weight: 700;
  padding: 3px 8px; line-height: 16px; margin: -3px 0;
  vertical-align: middle;
  text-transform: uppercase; letter-spacing: 0.06em; white-space: nowrap;
}
/* Plakietka w kolumnie wykazu: wszystkie tej samej szerokości, napis pośrodku.
   Przy różnych szerokościach kolumna wygląda na poszarpaną, bo lewa krawędź
   się zgadza, a prawa skacze przy każdym wierszu. Szerokość mieści najdłuższy
   napis, czyli „administrator”. */
.plakietka-kolumna { display: inline-flex; justify-content: center; min-width: 118px; }

/* Plakietka i dopisek pod nią jako jeden słupek wyrównany do środka, żeby
   dopisek stał pod napisem, a nie przy krawędzi komórki. */
.stan-kolumna { display: inline-flex; flex-direction: column; align-items: center; gap: 3px; }
.stan-kolumna .meta { text-align: center; }

.plakietka-opublikowany { background: var(--ok-bg); color: var(--ok); }
.plakietka-roboczy { background: var(--warn-bg); color: var(--warn); }
.plakietka-zaplanowany { background: var(--info-bg); color: var(--info); }
.plakietka-pilny { background: var(--err-bg); color: var(--red); }

/* Plakietka rodzaju boksu w barwie typu, ta sama co kafle w formularzu:
   redaktor wiąże kolor z rodzajem raz i rozpoznaje go potem na wykazie. */
.plakietka-typ-tresc   { background: var(--ok-bg);   color: var(--ok); }
.plakietka-typ-liczby  { background: var(--info-bg); color: var(--info); }
.plakietka-typ-kafelki { background: var(--belka);   color: var(--ink-2); }
.plakietka-typ-film    { background: var(--err-bg);  color: var(--red); }
.plakietka-typ-mapa    { background: var(--warn-bg); color: var(--warn); }

/* Wszystkie plakietki rodzaju tej samej szerokości, napis wyśrodkowany:
   kolumna czyta się jako równy słupek, a nie poszarpana krawędź. */
[class*="plakietka-typ-"] { display: inline-flex; justify-content: center; min-width: 62px; }

.para { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; font-size: var(--fs-4); }
.para span:first-child { color: var(--muted); }
.para span:last-child { font-family: var(--mono); font-size: var(--fs-2); }

.pusto { padding: 26px 15px; text-align: center; color: var(--muted); font-size: var(--fs-4); }

/* ---------- okno wygasającej sesji ---------- */

.zaslona { position: fixed; inset: 0; background: rgba(22, 22, 26, 0.55); display: grid; place-items: center; padding: 20px; z-index: 50; }
.okno { width: 100%; max-width: 430px; background: var(--white); border: 1px solid var(--line); }
.okno-naglowek { padding: 15px 18px; border-bottom: 1px solid var(--line-soft); font-weight: 700; font-size: var(--fs-7); display: flex; align-items: center; gap: 10px; }
.okno-tresc { padding: 16px 18px; display: flex; flex-direction: column; gap: 12px; font-size: var(--fs-5); }
.okno-tresc p { margin: 0; }
.odliczanie { font-family: var(--mono); font-size: 30px; font-weight: 700; color: var(--red); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.okno-stopka { padding: 13px 18px; border-top: 1px solid var(--line-soft); display: flex; gap: 9px; justify-content: flex-end; }

/* ---------- telefon ---------- */

/* Przełącznik menu istnieje tylko na wąskich ekranach. Na szerokich znika
   całkowicie, a nie jedynie z pola widzenia: element schowany za krawędź
   ekranu nadal łapałby tabulator i mylił osoby korzystające z klawiatury. */
.szyna-przelacznik { display: none; }
.szyna-przycisk { display: none; }

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

@media (max-width: 720px) {
  .log-strona { grid-template-columns: 1fr; }
  .log-lewa { padding: 28px 22px; gap: 20px; }
  .log-prawa { padding: 28px 22px; }

  .panel { flex-direction: column; }

  /* Szyna chowa się pod przyciskiem; rozwijamy ją bez JavaScriptu,
     zwykłym polem wyboru, żeby działała także przy zablokowanych skryptach. */
  .szyna { width: 100%; }
  .szyna nav { display: none; }
  .szyna-przelacznik:checked ~ nav { display: block; }
  .szyna-przycisk {
    display: flex; align-items: center; gap: 9px; cursor: pointer;
    padding: 12px 16px; color: #c3c3cc; font-size: var(--fs-5);
  }
  /* Widoczny dla klawiatury i czytnika ekranu, ale poza polem widzenia:
     obsługę przejmuje etykieta obok, która wygląda jak przycisk. */
  .szyna-przelacznik { display: block; position: absolute; left: -9999px; }
  .szyna-przelacznik:focus-visible + .szyna-przycisk { outline: 2px solid var(--marka); outline-offset: -2px; }
  .szyna-stopka { display: none; }

  .naglowek-strony { padding: 16px 16px 0; }
  .tresc-strony { padding: 14px 16px 90px; }
  .komunikat-globalny { padding: 14px 16px 0; }

  /**
   * Pasek górny na telefonie.
   *
   * Ścieżka i dane osoby nie mieszczą się obok siebie w 390 punktach, więc
   * schodzą pod siebie. Ze ścieżki zostaje ostatni krok: pozostałe to i tak
   * ta sama droga, którą widać w menu, a nazwa bieżącego ekranu mówi, gdzie
   * się jest. Znika też rola przy nazwisku, bo swoją rolę się zna.
   */
  .pasek-gorny { padding: 8px 16px; flex-wrap: wrap; gap: 6px 12px; align-items: center; }
  .okruszki a, .okruszki span[aria-hidden] { display: none; }
  .kto .rola { display: none; }

  /* Zakładki formularza przewijają się w poziomie zamiast łamać na dwa
     wiersze: pasek zakładek złamany w pół przestaje wyglądać jak pasek. */
  .zakladki, .zakladki-formularza {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: thin;
  }
  .zakladki a, .zakladki-formularza button { flex-shrink: 0; }

  /* Pasek stanu nad formularzem: suwak i pola pod sobą, bo obok siebie
     wypychały wybór kategorii poza ekran. */
  .pasek-stanu { flex-wrap: wrap; }
  .pasek-stanu-kreska { display: none; }
  .pasek-stanu-kategoria { width: 100%; }

  /* Nagłówek karty z filtrem albo szukaniem: nazwa w jednym wierszu,
     narzędzia pod nią. */
  .karta-naglowek { flex-wrap: wrap; }
  .pasek-szukania { width: 100%; }
  .pasek-szukania input { flex: 1; min-width: 0; }

  /* Kafelki liczb jeden pod drugim: dwie kolumny w 390 punktach zostawiają
     na nazwę działu tyle miejsca, że łamie się na trzy wiersze. */
  .zestawienie { grid-template-columns: 1fr; }
  .zestawienie a { border-right: 0; }
  .zestawienie a:not(:last-child) { border-bottom: 1px solid var(--line-soft); }

  /* Tabele zamieniamy w karty: dwie kolumny na telefonie nie mieszczą
     nawet krótkiego tytułu, a poziome przewijanie gubi kontekst wiersza. */
  table, thead, tbody, tr, th, td { display: block; }
  thead { display: none; }
  tr { border-bottom: 1px solid var(--line-soft); padding: 10px 0; }
  td { border: 0; padding: 3px 15px; }

  .akcje { width: 100%; }
  .akcje .przycisk { flex: 1; }

  /* Na telefonie wyrównanie do prawej nie ma czego porządkować, a szeroki
     przycisk łatwiej trafić kciukiem. */
  .stopka-formularza .przycisk { flex: 1; }

  /* Wiersz pliku: rozmiar ustępuje miejsca nazwie, a terminy schodzą pod
     siebie, bo dwa pola daty obok siebie nie mieszczą się w 390 punktach. */
  .pliki-waga { display: none; }
  .pliki-pozycja:has(.pliki-przelacz:checked) .pliki-terminy { padding-left: 14px; }
  .pliki-terminy .pole input { width: 100%; }
  .pliki-terminy .pole { flex: 1; min-width: 150px; }

  /* Przełącznik segmentowy przewija się w poziomie, tak samo jak zakładki.
     Pięć filtrów stanu wpisu ma razem ponad sześćset punktów i rozpychało całą
     stronę: pasek przewijania pojawiał się przy oknie, więc w bok jechał także
     nagłówek. Zawijanie odpada, bo złamany w pół przestaje wyglądać na jeden
     przełącznik. */
  .segmenty {
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: thin;
  }
  .segment-link, .segment span { flex-shrink: 0; }
  .media-szukanie { width: 100%; }

  /**
   * Obszary dotykowe.
   *
   * Odnośniki w tabelach i w drzewie struktury miały od 17 do 23 punktów
   * wysokości, przy dwudziestu czterech wymaganych przez WCAG 2.2 dla celów
   * wskaźnika. Przy myszy to nie przeszkadza, przy kciuku owszem: trafienie
   * obok otwiera sąsiedni wpis, czyli w wykazie artykułów „wszedłem nie w ten
   * wpis i zaraz go zmienię”.
   *
   * Wysokość bierze się z `min-height` i wyśrodkowania, a nie z odstępów:
   * odstępy rozpychałyby też wiersze, w których tekst jest długi i sam ma
   * już swoją wysokość.
   */
  td a,
  .drzewo-komorka a,
  .drzewo-komorka button,
  .okruszki a {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
  }

  /* Przyciski przy pozycjach drzewa i wylogowanie w pasku górnym: te same
     dwadzieścia cztery punkty. Zwijak i gwiazdka są kwadratowe, więc dostają
     wymiar w obie strony, a nie samą wysokość. */
  .zwijak,
  .gwiazdka { min-width: 24px; min-height: 24px; }
  .kto a,
  .karta-naglowek a { display: inline-flex; align-items: center; min-height: 24px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

.tag-wybor { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; }
.tag-wybor input { margin: 0; }

/* ---------- formularz podzielony na zakładki ---------- */

/* Pasek nad zakładkami. Publikacja i kategoria przesądzają o tym, czy wpis
   pojawi się na stronie, więc zostają na wierzchu niezależnie od tego,
   którą sekcję redaktor ma otwartą. */
.pasek-stanu {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  padding: 12px 15px;
  margin-bottom: 18px;
  background: var(--white);
  border: 1px solid var(--line);
  border-left: 3px solid var(--ink);
}

/* Kategoria stoi w pasku, a nie w formularzu, więc etykieta idzie obok pola,
   a nie nad nim: pełnowymiarowe pole rozpychało pasek na dwa razy wyższy
   niż reszta jego zawartości. */
/* min-width: 0 na obu poziomach, bo pole wyboru ma szerokość najdłuższej
   pozycji listy, a ścieżki kategorii bywają długie. Bez tego rozpychałoby
   pasek i całą stronę w poziomie. */
.pasek-stanu-kategoria {
  flex-direction: row; align-items: center; gap: 9px;
  flex: 1 1 300px; max-width: 560px; min-width: 0;
}
.pasek-stanu-kategoria label { white-space: nowrap; }
.pasek-stanu-kategoria select { padding: 7px 10px; font-size: var(--fs-4); min-width: 0; }
.pasek-stanu-kreska { width: 1px; align-self: stretch; min-height: 30px; background: var(--line); }
.pasek-stanu-uwaga { display: flex; align-items: center; gap: 9px; margin-left: auto; font-size: var(--fs-2); color: var(--muted); }

.przelacznik { display: inline-flex; align-items: center; gap: 8px; font-size: var(--fs-4); cursor: pointer; }
.przelacznik input { margin: 0; flex-shrink: 0; }

/* Suwak włącz/wyłącz.
   Jedyny zaokrąglony element w panelu, i to celowo: taki kształt czyta się
   od razu jako przełącznik, a publikacja to decyzja, przy której nie chcemy
   sekundy wahania. Pole wyboru zostaje w drzewie, bo to ono niesie stan
   i wysyła się z formularzem; przykrywamy je tylko wizualnie. */
.przelacznik-duzy { display: inline-flex; align-items: center; gap: 11px; cursor: pointer; }
.przelacznik-duzy input {
  position: absolute;
  width: 1px; height: 1px;
  margin: 0;
  opacity: 0;
}
.przelacznik-tor {
  position: relative;
  width: 44px; height: 24px;
  flex-shrink: 0;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  transition: background 0.15s, border-color 0.15s;
}
.przelacznik-tor::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--muted-2);
  transition: transform 0.15s, background 0.15s;
}
.przelacznik-duzy input:checked + .przelacznik-tor { background: var(--ok); border-color: var(--ok); }
.przelacznik-duzy input:checked + .przelacznik-tor::after { transform: translateX(20px); background: var(--white); }
.przelacznik-duzy input:focus-visible + .przelacznik-tor { outline: 2px solid var(--marka); outline-offset: 2px; }

/* Nazwa i przełącznik nagłówka w jednej linii: pole rośnie, przełącznik stoi
   przy prawej krawędzi. Na wąskim ekranie przełącznik schodzi pod pole. */
.nazwa-rzad { display: flex; align-items: center; gap: 16px; }
.nazwa-rzad > input { flex: 1; min-width: 0; }
.przelacznik-inline { flex-shrink: 0; }
/* Napis stoi w .pole, więc łapie styl etykiety pola (wielkie litery, szary).
   Cofamy to, żeby czytał się jak podpis przełącznika „Publikacja”, nie jak
   nagłówek pola: normalny tekst, ciemny, bez rozstrzelenia. */
.przelacznik-inline .przelacznik-napis b {
  font-size: var(--fs-4); white-space: nowrap;
  text-transform: none; letter-spacing: 0;
  color: var(--ink); font-weight: 600;
}
@media (max-width: 620px) {
  .nazwa-rzad { flex-wrap: wrap; }
  .przelacznik-inline { margin-top: 2px; }
}

/* Linia dzieląca części w karcie ustawień: lokalizacja i kod nad nią, odnośnik
   pod. Cieńsza i jaśniejsza niż obramowanie karty, bo dzieli w środku sekcji. */
.linia-pola { border: 0; border-top: 1px solid var(--line-soft); margin: 4px 0; }

/* Podgrupa pól w karcie: mały nagłówek nad zestawem, jak „Odnośnik”. Ta sama
   wersalikowa forma co etykieta pola, żeby czytało się jak część formularza. */
.pole-podgrupa {
  font-size: var(--fs-2); font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--ink-2);
}

/**
 * Suwak w wierszu tabeli, wysyłany zwykłym formularzem.
 *
 * Przycisk, a nie pole wyboru, bo bez skryptu pole wyboru samo niczego nie
 * wysyła, a panel ma działać także z wyłączonym JavaScriptem. Stan niesie
 * aria-pressed, więc czytnik ekranu mówi „wciśnięty”, a nie samo „przycisk”.
 */
.suwak-wiersza { border: 0; background: none; padding: 3px; cursor: pointer; display: inline-flex; }
.suwak-wiersza .tor {
  position: relative;
  width: 34px; height: 19px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  transition: background 0.15s, border-color 0.15s;
}
.suwak-wiersza .tor::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--muted-2);
  transition: transform 0.15s, background 0.15s;
}
.suwak-wiersza[aria-pressed="true"] .tor { background: var(--ok); border-color: var(--ok); }
.suwak-wiersza[aria-pressed="true"] .tor::after { transform: translateX(15px); background: var(--white); }

.przelacznik-napis b { display: block; font-size: var(--fs-4); font-weight: 600; }
/* Napis pod nazwą zmienia się razem z suwakiem. Sam suwak niesie tę samą
   informację dla czytnika ekranu, więc tutaj jest wyłącznie dla oka. */
/* Podpis pod suwakiem bierze się z atrybutów, bo suwak stoi już na pięciu
   ekranach i wszędzie znaczy co innego: publikację wpisu, widoczność alertu,
   dostęp do panelu. Wcześniej treść była wpisana w styl, więc na koncie
   użytkownika czytało się „wyłączona, wpis roboczy”. */
.przelacznik-stan { font-size: var(--fs-1); color: var(--muted); }
.przelacznik-stan::after { content: attr(data-wylaczony); }
.przelacznik-duzy input:checked ~ .przelacznik-napis .przelacznik-stan::after { content: attr(data-wlaczony); }
.przelacznik-duzy input:checked ~ .przelacznik-napis .przelacznik-stan { color: var(--ok); }

.pole-obok { display: flex; gap: 22px; flex-wrap: wrap; }

/* Przełącznik z wyjaśnieniem, ustawiony jak kafelek.
   „Galeria na wykazie" nic nie mówi osobie, która widzi to pierwszy raz,
   a goły wiersz z kwadracikiem gubi się między polami. */
.opcje { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: 10px; }
.opcja {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  padding: 13px 15px 13px 12px;
  border: 1px solid var(--line);
  /* Pasek przy lewej krawędzi, niewidoczny do czasu wyboru. Rezerwujemy jego
     miejsce od razu, bo dokładany dopiero przy zaznaczeniu przesuwałby treść
     kafla o trzy piksele w prawo i wybór wyglądałby jak drgnięcie. */
  border-left: 3px solid var(--line);
  background: var(--white);
  cursor: pointer;
}
.opcja:hover { border-color: var(--muted-2); }

/**
 * Wybrany kafel.
 *
 * Znak wyboru niosą trzy rzeczy naraz: pasek w kolorze marki, ciemniejsza
 * ramka i mocniejszy tytuł. Sam kolor nie wystarcza, bo przy daltonizmie bywa
 * nie do odróżnienia, a tło zostaje białe: szare wyglądało jak pole wyłączone,
 * czyli dokładnie odwrotnie, niż znaczy.
 */
.opcja:has(input:checked) { border-color: var(--muted-2); border-left-color: var(--akcent, var(--marka)); }
.opcja:has(input:checked) b { font-weight: 700; }

/* Kafel może dostać własny kolor akcentu przez --akcent, żeby zgadzał się
   z plakietką tej samej rzeczy na wykazie: rola redaktora jest tam bursztynowa,
   administratora niebieska. Bez tego kropka wyboru i plakietka na sąsiednim
   ekranie mówiłyby o tym samym dwoma różnymi kolorami. */
.opcja input {
  margin: 2px 0 0; flex-shrink: 0; width: 15px; height: 15px;
  accent-color: var(--akcent, var(--marka));
}
.opcja > span { font-size: var(--fs-1); color: var(--muted); line-height: 1.45; }
.opcja b { display: block; margin-bottom: 2px; font-size: var(--fs-5); font-weight: 600; color: var(--ink); }

/* Podgląd ikony strony obok pola wgrywania, żeby było widać, co jest ustawione. */
.opcja-ikony { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; }
.opcja-ikony img { border: 1px solid var(--line); background: var(--paper); padding: 6px; flex-shrink: 0; }
.opcja-ikony-brak {
  display: grid; place-items: center;
  width: 78px; height: 78px; flex-shrink: 0;
  border: 1px dashed var(--line);
  color: var(--muted-2); font-size: var(--fs-1);
}
.pole-siatka { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }

.formularz-hasla { display: flex; flex-direction: column; gap: 14px; }

/* Kreska rozdzielająca grupy pól w jednej karcie. Zamiast nagłówka, który
   przy polu „Nowe hasło" powtarzałby jego własną etykietę dwa centymetry
   wyżej. Odstępy większe niż między polami, bo to właśnie one niosą podział. */
.rozdzielnik { border: 0; border-top: 1px solid var(--line-soft); margin: 4px 0; }

/* Nazwa grupy pól wewnątrz karty: półpiętro między nagłówkiem karty
   a etykietą pola, więc cichsza od obu. Nie wersalikami, bo tych używa już
   belka karty i etykiety pól. */
.podtytul-sekcji { margin: 0; font-size: var(--fs-4); font-weight: 600; color: var(--ink); }
/* Zdanie objaśniające pod nazwą grupy: dotyczy całej sekcji, więc stoi przy
   jej nazwie, a nie pod pierwszym polem, gdzie wyglądałoby na podpis do niego. */
.podtytul-sekcji span { display: block; font-size: var(--fs-1); font-weight: 400; color: var(--muted-2); }

.pole-zestaw { border: 0; padding: 0; margin: 0; }
.pole-zestaw legend {
  padding: 0; margin-bottom: 7px;
  font-size: var(--fs-2); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.1em; color: var(--muted);
}
/* Pusty stan wewnątrz sekcji: obramowana płachta, a nie luźne zdanie.
   Samo zdanie w kolorze podpisów ginęło między polem wgrywania a resztą
   formularza i wyglądało jak kolejna wskazówka, a nie jak stan „nic tu nie ma”. */
.pusto-w-polu {
  margin: 0;
  padding: 20px 15px;
  text-align: center;
  font-size: var(--fs-4);
  color: var(--muted);
  background: var(--paper);
  border: 1px dashed var(--line);
}
/* Krótka lista nie ma powodu ciągnąć się przez całą szerokość karty. */
.pole-waskie { max-width: 340px; }

/* Pasek zakładek pojawia się dopiero, gdy skrypt go ożywi. Bez skryptu
   sekcje leżą jedna pod drugą i nie ma czym przełączać. */
.zakladki-grupa { display: flex; flex-direction: column; gap: 18px; }
.zakladki-grupa .zakladki-formularza { display: none; }
.zakladki-grupa.zakladki-gotowe { gap: 0; }
.zakladki-grupa.zakladki-gotowe .zakladki-formularza { display: flex; }
/* Z zakładkami nazwa sekcji stoi już na przycisku, więc nagłówek karty
   powtarzałby ją drugi raz tuż pod spodem. */
.zakladki-gotowe .zakladka-panel > .karta-naglowek { display: none; }

.zakladki-formularza { padding: 0; gap: 2px; border-bottom: 1px solid var(--line); background: transparent; }
.zakladki-formularza button {
  position: relative;
  padding: 10px 16px;
  border: 1px solid transparent;
  border-bottom: 0;
  margin-bottom: -1px;
  background: transparent;
  font-family: var(--ui);
  font-size: var(--fs-4);
  color: var(--muted);
  cursor: pointer;
}
.zakladki-formularza button:hover { color: var(--ink); }
.zakladki-formularza button[aria-selected="true"] {
  color: var(--ink);
  font-weight: 700;
  background: var(--white);
  border-color: var(--line);
}
/* Wybrana zakładka zrasta się z kartą pod spodem: kreska pod nią znika. */
.zakladki-formularza button[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--white);
}

/* Kropka przy nazwie sekcji, w której serwer znalazł problem. Kolor jej nie
   niesie: przy tej zakładce i tak otwiera się komunikat z treścią błędu. */
.zakladka-kropka {
  display: inline-block;
  width: 7px; height: 7px;
  margin-left: 5px;
  border-radius: 50%;
  background: var(--red);
}

/* Wyrównanie do środka, bo obok przycisków stoją też plakietki, a te bez
   tego rozciągały się na całą wysokość przycisku i robiły z jednego słowa
   kolorowy prostokąt wielkości guzika. */
.akcje-dolne { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
/* Usuwanie i przenoszenie do kosza przy prawej krawędzi, tak samo we
   wszystkich formularzach: to jedyne przyciski, których nie da się cofnąć,
   więc nie mają stać tam, gdzie ręka wraca po zapisie. */
.akcje-dolne-prawo { justify-content: flex-end; }

/* ---------- zdjęcia i pliki ---------- */

/* Pole wyboru plików chowamy dopiero wtedy, gdy skrypt zbuduje obszar
   do przeciągania. Bez skryptu zostaje zwykłe pole, którym też da się pracować. */
.wgrywarka input[type="file"] { font-size: var(--fs-4); }
.wgrywarka-pole { display: none; }
.wgrywarka-gotowa input[type="file"] { position: absolute; width: 1px; height: 1px; opacity: 0; }

.wgrywarka-gotowa .wgrywarka-pole {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 26px 18px;
  border: 2px dashed var(--line);
  background: var(--paper);
  color: var(--muted);
  font-size: var(--fs-2);
  text-align: center;
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
}
.wgrywarka-gotowa .wgrywarka-pole b { font-size: var(--fs-5); font-weight: 600; color: var(--ink); }
.wgrywarka-gotowa .wgrywarka-pole:hover { border-color: var(--muted-2); background: var(--white); }
/* Podświetlenie obszaru, nad którym trzymamy przeciągany plik. To zaproszenie
   do upuszczenia, a nie ostrzeżenie, więc kolor marki, nie alarmu. */
.wgrywarka-nad .wgrywarka-pole { border-color: var(--marka); background: var(--white); }
.wgrywarka-znak { color: var(--muted-2); }
.wgrywarka-gotowa input[type="file"]:focus-visible + .wgrywarka-pole { outline: 2px solid var(--marka); outline-offset: 2px; }

.wgrywarka-lista { list-style: none; margin: 9px 0 0; padding: 0; display: flex; flex-direction: column; gap: 3px; }
.wgrywarka-lista li { display: flex; justify-content: space-between; gap: 12px; font-size: var(--fs-3); padding: 5px 9px; background: var(--paper); }
.wgrywarka-lista b { font-weight: 600; }
.wgrywarka-lista span { color: var(--muted); font-family: var(--mono); font-size: var(--fs-1); }

/* Podczas zmniejszania zdjęć formularz czeka; kursor mówi o tym wprost,
   bo bez tego pierwsze kliknięcie w Zapisz wygląda na nieskuteczne. */
.formularz-pracuje { cursor: progress; }
.formularz-pracuje button[type="submit"] { opacity: 0.55; }

/* Wykaz plików migracji. Pismem o stałej szerokości, bo nazwy różnią się
   numerem na początku i tak zestawione czyta się je jak listę wersji. */
.lista-plikow {
  list-style: none; margin: 0; padding: 0;
  font-family: var(--mono); font-size: var(--fs-3);
  display: flex; flex-direction: column; gap: 3px;
}
.lista-plikow li { padding: 5px 9px; background: var(--paper); border: 1px solid var(--line-soft); }

.galeria {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
}
.galeria-pozycja { border: 1px solid var(--line); background: var(--white); display: flex; flex-direction: column; }
.galeria-pozycja.przenoszona { opacity: 0.4; border-color: var(--ink); }

.galeria-obraz { position: relative; background: var(--paper); border-bottom: 1px solid var(--line-soft); }
.galeria-obraz img { display: block; width: 100%; height: 168px; object-fit: contain; }

.galeria-uchwyt {
  position: absolute; top: 6px; left: 6px;
  width: 26px; height: 26px;
  display: grid; place-items: center;
  padding: 0;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--muted);
  cursor: grab;
}
.galeria-uchwyt:hover { color: var(--ink); border-color: var(--muted-2); }
.galeria-uchwyt:active { cursor: grabbing; }

/* Kafle są ciasne z rozmysłem: przy pięćdziesięciu zdjęciach każda zbędna
   linijka w kaflu to pięćdziesiąt linijek przewijania. */
.galeria-pola { padding: 9px 10px; display: flex; flex-direction: column; gap: 6px; }
.galeria-pola .pole label { font-size: var(--fs-2); margin-bottom: 2px; }
.galeria-pola .przelacznik { font-size: var(--fs-2); }
.galeria-stopka { display: flex; gap: 5px; flex-wrap: wrap; padding-top: 7px; border-top: 1px solid var(--line-soft); margin-top: 1px; }

/* Znacznik: przełączany stan zdjęcia w postaci małego przycisku z ikoną.
   Kropka i kwadracik w jednym rzędzie wyglądały jak dwie różne rzeczy, choć
   obie robią to samo: przestawiają jedno ustawienie kafla. Pole wyboru zostaje
   w drzewie i niesie stan, przykrywamy je tylko wizualnie, bo ukryte przez
   display: none wypada z kolejki klawisza Tab i z odczytu czytnika ekranu. */
.znacznik { position: relative; display: inline-flex; margin: 0; padding: 0; border: 0; background: none; cursor: pointer; }
.znacznik input {
  position: absolute;
  width: 1px; height: 1px;
  margin: 0;
  opacity: 0;
}
.znacznik > span,
.znacznik.znacznik-przycisk {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px 4px 7px;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--muted);
  font-family: var(--ui); font-size: var(--fs-1); font-weight: 500; line-height: 16px;
  white-space: nowrap;
}
.znacznik:hover > span,
.znacznik.znacznik-przycisk:hover { color: var(--ink); border-color: var(--muted-2); }
.znacznik input:focus-visible { outline: none; }
.znacznik input:focus-visible + span { outline: 2px solid var(--marka); outline-offset: -3px; }

/* Wybrane zdjęcie główne i zdjęcie idące do usunięcia widać na pierwszy rzut
   oka, bez czytania napisów: jedno jest wyróżnieniem, drugie ostrzeżeniem,
   więc każde dostaje własny kolor, a nie ten sam znak wciśnięcia. */
.znacznik-glowne input:checked + span {
  color: var(--marka); border-color: var(--marka); font-weight: 600;
}
.znacznik-glowne input:checked + span svg { fill: currentColor; }
.znacznik-usun input:checked + span {
  color: var(--red); border-color: var(--red); background: var(--err-bg); font-weight: 600;
}
/* Podpis rozwinięty: przycisk zostaje wciśnięty, żeby po zwinięciu sąsiada
   było widać, który kafel ma pole otwarte. */
.znacznik-przycisk[aria-expanded="true"] { color: var(--ink); border-color: var(--muted-2); background: var(--line-soft); }

/* Dane pliku pod „i”: nazwa, wymiary i waga są potrzebne raz na jakiś czas,
   a zajmowały linijkę w każdym kaflu. Panel rozwija się nad zdjęciem, więc
   nie przestawia sąsiadów w siatce. */
.galeria-info { position: absolute; top: 6px; right: 6px; z-index: 2; }
.galeria-info summary {
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--muted);
  font-family: var(--mono); font-size: var(--fs-4); font-weight: 700;
  cursor: pointer; list-style: none;
}
.galeria-info summary::-webkit-details-marker { display: none; }
.galeria-info summary:hover { color: var(--ink); border-color: var(--muted-2); }
.galeria-info[open] summary { color: var(--ink); border-color: var(--muted-2); }
.galeria-info-tresc {
  position: absolute; top: 30px; right: 0;
  width: 210px; padding: 7px 9px;
  border: 1px solid var(--line);
  background: var(--white);
  font-size: var(--fs-2); line-height: 1.5; color: var(--muted-2);
  font-family: var(--mono); word-break: break-all;
}

/* Zdjęcie bez opisu alternatywnego. Znak stoi na zdjęciu, bo lista błędów
   nad formularzem mówi „zdjęcie nr 37”, a oko i tak musi je odliczyć.
   Pojawia się tylko przy wdrożeniu z wymogiem dostępności. */
.galeria-brak { display: none; }
.galeria-pozycja.bez-opisu { border-color: var(--red); }
/* Ten sam znak w bibliotece mediów: kafel wygląda inaczej, ale pytanie jest
   to samo, więc odpowiedź ma wyglądać tak samo. */
.galeria-pozycja.bez-opisu .galeria-brak,
.media-kafel.bez-opisu .galeria-brak {
  position: absolute; bottom: 6px; left: 6px; z-index: 1;
  width: 24px; height: 24px;
  display: grid; place-items: center;
  background: var(--red); color: #fff;
  font-weight: 700; font-size: var(--fs-7); line-height: 1;
}

/* Pasek nad galerią: układ na stronie i zaznaczanie zbiorcze. */
.galeria-pasek {
  display: flex; flex-wrap: wrap; gap: 12px 20px;
  align-items: flex-end; justify-content: space-between;
  margin-bottom: 11px;
}
.galeria-uklad { border: 0; margin: 0; padding: 0; }
.galeria-uklad legend {
  padding: 0; margin-bottom: 5px; width: 100%;
  font-size: var(--fs-2); text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted-2); font-weight: 700;
}

/* Przełącznik segmentowy: dwie wykluczające się opcje sklejone w jeden pasek,
   z których jedna jest wciśnięta. Pole wyboru zostaje w drzewie, bo to ono
   niesie stan i idzie z formularzem, ale chowamy je przezroczystością zamiast
   przez display: none, bo element ukryty w ten sposób wypada z kolejki
   klawisza Tab i z odczytu czytnika ekranu. */
.segmenty { display: inline-flex; border: 1px solid var(--line); background: var(--white); }
.segment { position: relative; display: inline-flex; cursor: pointer; }
.segment + .segment { border-left: 1px solid var(--line); }
.segment input {
  position: absolute;
  width: 1px; height: 1px;
  margin: 0;
  opacity: 0;
}
.segment span {
  padding: 7px 18px;
  font-size: var(--fs-4); line-height: 18px; font-weight: 500;
  color: var(--muted);
  white-space: nowrap;
}
.segment:hover span { color: var(--ink); background: var(--line-soft); }
.segment input:checked + span { background: var(--marka); color: var(--white); font-weight: 600; }
/* Obwódka klawiatury siada na pudełku napisu, bo samo pole wyboru jest
   niewidoczne i obwódka rysowałaby się w powietrzu obok przełącznika. */
.segment input:focus-visible { outline: none; }
.segment input:focus-visible + span { outline: 2px solid var(--marka); outline-offset: -3px; }

/* Przycisk bez napisu, do czynności ruszanej raz na kilkadziesiąt wpisów.
   Nazwę niesie aria-label i title, więc czytnik ekranu i najechanie myszą
   dostają pełne zdanie, a pasek nie oddaje rzadkiej rzeczy tyle miejsca,
   ile zajmują ustawienia dotykane przy każdym wpisie. */
.przycisk-ikona {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--muted);
  cursor: pointer;
}
.przycisk-ikona:hover { color: var(--red); border-color: var(--muted-2); }
/* Wciśnięty znaczy „wszystko zaznaczone”, więc następne kliknięcie odznacza.
   Ptaszek wtedy znika i zostaje sam pusty kwadrat: ikona pokazuje, co przycisk
   zrobi, a nie w jakim jest stanie. */
.przycisk-ikona[aria-pressed="true"] { color: var(--red); border-color: var(--red); background: var(--err-bg); }
.przycisk-ikona[aria-pressed="true"] .ikona-ptaszek { display: none; }

/* Zaznaczenie do usunięcia widać na całym kafelku, a nie tylko przy kwadraciku:
   przy dziesięciu zdjęciach łatwo zaznaczyć nie to, co się chciało. */
.przelacznik-usun span { color: var(--red); }
.galeria-pozycja:has(.przelacznik-usun input:checked) { border-color: var(--red); background: var(--err-bg); }
.galeria-pozycja:has(.przelacznik-usun input:checked) .galeria-obraz img { opacity: 0.4; }

/* Wykaz plików: jeden plik to jeden wiersz. Nazwa jest jedyną rzeczą, którą
   redaktor zmienia na co dzień, więc dostaje całą wolną szerokość, a terminy
   dostępności chowają się pod zegarkiem. */
.pliki { list-style: none; margin: 0; padding: 0; }
.pliki-pozycja {
  position: relative;
  border: 1px solid var(--line);
  background: var(--white);
  margin-bottom: -1px;
}
.pliki-pozycja:last-child { margin-bottom: 0; }
.pliki-wiersz { display: flex; gap: 10px; align-items: center; padding: 7px 8px 7px 6px; }
.pliki-pozycja .galeria-uchwyt { position: static; flex-shrink: 0; border: 0; background: none; }
.pliki-pozycja.przenoszona { opacity: 0.4; border-color: var(--ink); }
.pliki-format {
  flex-shrink: 0;
  min-width: 46px;
  padding: 4px 8px;
  background: var(--ink);
  color: var(--white);
  font-size: var(--fs-1);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-align: center;
}
.pliki-nazwa {
  flex: 1; min-width: 0;
  border: 1px solid transparent;
  background: none;
  padding: 6px 8px;
  font-family: var(--ui);
  font-size: var(--fs-5);
  color: var(--ink);
}
.pliki-nazwa::placeholder { color: var(--muted); }
.pliki-nazwa:hover { border-color: var(--line); }
.pliki-nazwa:focus { border-color: var(--marka); outline: none; background: var(--white); }

.pliki-waga {
  flex-shrink: 0;
  font-size: var(--fs-1);
  color: var(--muted-2);
  font-variant-numeric: tabular-nums;
}

/* Zegarek i kosz jako ikony: przy dziesięciu plikach dwa napisy w każdym
   wierszu zamieniłyby wykaz w ścianę tekstu. */
.pliki-ikona {
  flex-shrink: 0;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border: 1px solid transparent;
  color: var(--muted-2);
  cursor: pointer;
}
.pliki-ikona input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pliki-ikona:hover { border-color: var(--line); color: var(--ink); background: var(--paper); }
.pliki-ikona:has(input:focus-visible) { outline: 2px solid var(--marka); outline-offset: 1px; }
.pliki-ikona:has(.pliki-przelacz:checked) { color: var(--ink); border-color: var(--line); background: var(--paper); }
.pliki-kasuj:hover { color: var(--red); }
.pliki-kasuj:has(input:checked) { color: var(--white); background: var(--red); border-color: var(--red); }
.pliki-pozycja:has(.pliki-kasuj input:checked) { border-color: var(--red); background: var(--err-bg); z-index: 1; }
.pliki-pozycja:has(.pliki-kasuj input:checked) .pliki-nazwa { text-decoration: line-through; color: var(--muted); }

.pliki-terminy { display: none; }
.pliki-pozycja:has(.pliki-przelacz:checked) .pliki-terminy {
  display: flex; gap: 18px; flex-wrap: wrap;
  padding: 10px 12px 12px 44px;
  border-top: 1px dashed var(--line);
  background: var(--paper);
}
.pliki-terminy .pole label { font-size: var(--fs-1); }
.pliki-terminy .pole input { width: 190px; }

/* ---------- strony informacyjne ---------- */

.strony-lista { list-style: none; margin: 0; padding: 0; }
.strony-pozycja {
  position: relative;
  display: flex; align-items: center; gap: 14px;
  padding: 12px 15px 12px 42px;
  border-bottom: 1px solid var(--line-soft);
}
.strony-pozycja:last-child { border-bottom: 0; }
/* Podświetlenie całego wiersza, tak jak w tabelach: podpowiedź, gdzie jestem,
   a nie zaznaczenie, więc kolor tła strony, nie mocniejszy. */
.strony-pozycja:hover { background: var(--paper); }
.strony-pozycja:hover .strony-tytul { color: var(--marka); }
.strony-pozycja.przenoszona { opacity: 0.4; background: var(--paper); }
.strony-pozycja .galeria-uchwyt { position: absolute; top: 50%; left: 9px; transform: translateY(-50%); }
.strony-tresc { flex: 1; min-width: 0; }
.strony-tytul { font-size: var(--fs-6); font-weight: 600; color: inherit; text-decoration: none; }
.strony-tytul:hover { color: var(--marka); text-decoration: underline; }
.strony-pozycja .meta { font-size: var(--fs-1); color: var(--muted); font-family: var(--mono); }
.strony-stan { display: flex; gap: 7px; align-items: center; flex-shrink: 0; }

/* Adres składany z części stałej i wpisywanej, żeby było widać, co powstanie. */
.pole-adres { display: flex; align-items: stretch; border: 1px solid var(--line); background: var(--white); }
.pole-adres span {
  display: flex; align-items: center;
  padding: 0 4px 0 12px;
  background: var(--paper);
  border-right: 1px solid var(--line);
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-3);
  white-space: nowrap;
}
.pole-adres input { border: 0 !important; font-family: var(--mono) !important; font-size: var(--fs-4) !important; }

.pasek-stanu-adres {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-3); font-weight: 600; text-decoration: none;
}
.pasek-stanu-adres:hover { text-decoration: underline; }

.akcje-wiersza { display: flex; gap: 6px; flex-wrap: wrap; }
.blokada-przejmij { display: inline-block; margin-left: 6px; vertical-align: middle; }

/* Tabela z pozycjami boksu liczbowego: pola wypełniają komórki. */
.tabela-pozycji td { padding: 5px 8px; }
.tabela-pozycji th { padding: 8px; }
/* Wygląd pola przychodzi z reguły ogólnej; tutaj zostaje tylko to, co wynika
   z ciasnoty komórki: pełna szerokość i mniejsze odstępy, takie same jak
   w innych polach stojących w tabeli. */
.tabela-pozycji input { width: 100%; padding: 6px 10px; font-size: var(--fs-4); }
.tabela-pozycji td:first-child input { font-family: var(--mono); font-weight: 700; }

/* Tabela kafelków ma więcej kolumn (ikona, kolor, tytuł, opis, odnośnik):
   selecty na pełną szerokość jak pola, a całość może się przewinąć w poziomie
   na wąskim ekranie, zamiast rozpychać stronę. */
.tabela-kafelkow select { width: 100%; padding: 6px 8px; font-size: var(--fs-4); }
.tabela-kafelkow .td-ptaszek { text-align: center; }
/* Ptaszek widoczności nie może dziedziczyć width:100% z reguły pól w tabeli. */
.tabela-kafelkow .td-ptaszek input[type="checkbox"] { width: auto; margin: 0; }
.gdy-b-kafelki { overflow-x: auto; }

/* Strzałki kolejności artykułów na liście kategorii: dwa mikroprzyciski ikonowe
   obok siebie, każdy to osobny formularz (bez JS). */
.kolejnosc-td { white-space: nowrap; }
.kolejnosc-strzalki { display: inline-flex; gap: 3px; }
.kolejnosc-strzalki form { margin: 0; display: inline; }
.strzalka-sort {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; cursor: pointer;
  border: 1px solid var(--line); border-radius: 6px;
  background: transparent; color: var(--ink-2);
}
.strzalka-sort:hover { border-color: var(--marka); color: var(--marka); background: var(--belka); }

/* ---------- liczniki, stronicowanie, filtr ---------- */

.liczniki { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; }
.licznik {
  display: flex; flex-direction: column; gap: 2px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--ink);
  background: var(--white);
}
.licznik-liczba { font-size: 26px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.licznik-opis { font-size: var(--fs-1); color: var(--muted); line-height: 1.4; }

/* Pasek przy krawędzi w kolorze znaczenia liczby: zielony przy rzeczach, które
   mają się dziać, pomarańczowy przy tych, które warto mieć na oku. Kolor jest
   dodatkiem do opisu, a nie jedynym nośnikiem, bo przy daltonizmie zielony
   od pomarańczowego bywa nie do odróżnienia. */
.licznik-dobry { border-left-color: var(--ok); }
.licznik-uwaga { border-left-color: #d9a441; }

.stronicowanie { display: flex; gap: 4px; flex-wrap: wrap; padding: 12px 15px; border-top: 1px solid var(--line-soft); }
.stronicowanie a,
.stronicowanie span {
  min-width: 32px;
  padding: 6px 9px;
  border: 1px solid var(--line);
  font-size: var(--fs-4);
  text-align: center;
  text-decoration: none;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stronicowanie a:hover { border-color: var(--muted-2); }
.stronicowanie .wybrana { background: var(--ink); border-color: var(--ink); color: var(--white); font-weight: 700; }
.stronicowanie-przerwa { border: 0; color: var(--muted-2); padding: 6px 2px; min-width: 0; }

.zakladki-filtr { display: inline-flex; gap: 10px; text-transform: none; letter-spacing: 0; font-weight: 400; }
.zakladki-filtr a { font-size: var(--fs-3); text-decoration: none; color: var(--muted); }
.zakladki-filtr a:hover { color: var(--ink); }
/* Wybrany filtr sam pogrubieniem, bez podkreślenia: podkreślenie w pasku
   odnośników czyta się jak drugi rodzaj zaznaczenia obok pogrubienia. */
.zakladki-filtr a.wybrany { color: var(--ink); font-weight: 700; }

/* ---------- hasło jednorazowe ---------- */

/* Pokazywane raz, więc musi rzucać się w oczy i dać się przeczytać
   przez telefon: krój o stałej szerokości i duże odstępy między znakami. */
.karta-haslo { border-color: var(--ok); border-left-width: 3px; }
.haslo-jednorazowe {
  margin: 0;
  padding: 12px 16px;
  background: var(--ok-bg);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.14em;
  user-select: all;
  word-break: break-all;
}

/* === SEKCJA ROZWIJANA ===
   Zwykłe details, bez skryptu: przy wykazie artykułów tekst nad listą jest
   dodatkiem, a pusty edytor na pół ekranu przykrywał ustawienia, po które się
   na ten ekran przyszło. */
.rozwijane { border: 1px solid var(--line); border-radius: 8px; background: var(--white); }
.rozwijane > summary {
  display: flex; align-items: center; gap: 9px;
  padding: 11px 14px; cursor: pointer;
  font-size: var(--fs-2); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.1em; color: var(--muted);
  list-style: none;
}
.rozwijane > summary::-webkit-details-marker { display: none; }
/* Strzałka rysowana u nas, bo trójkąt systemowy ma w każdej przeglądarce inny
   rozmiar i inny odstęp od napisu. */
.rozwijane > summary::before {
  content: ""; width: 8px; height: 8px; flex-shrink: 0;
  border-right: 2px solid var(--muted-2); border-bottom: 2px solid var(--muted-2);
  transform: rotate(-45deg); margin-right: 2px;
  transition: transform 0.15s;
}
.rozwijane[open] > summary::before { transform: rotate(45deg); margin-top: -4px; }
.rozwijane > summary:hover { color: var(--ink); }
.rozwijane > summary:focus-visible { outline: 2px solid var(--marka); outline-offset: -2px; }
.rozwijane .plakietka { text-transform: none; letter-spacing: 0; }
.rozwijane-tresc {
  display: flex; flex-direction: column; gap: 12px;
  padding: 0 14px 14px;
}

/* Details zamiast div, więc widoczność sekcji przełącza ta sama reguła. */
.wybor-typu:has(.typ-kafel-artykuly input:checked) details.gdy-tresc,
.wybor-typu:has(.typ-kafel-tekst input:checked)    details.gdy-tresc { display: block; }

/* Komórka, w której łamanie tylko szkodzi: imię i nazwisko rozbite na dwie
   linie rozciągało wiersz, choć obok stało pół ekranu wolnego miejsca. */
.bez-lamania { white-space: nowrap; font-size: var(--fs-3); color: var(--muted); }


/* === BIBLIOTEKA MEDIÓW ===
   Foldery po lewej, pliki po prawej. Układ znany z każdego menedżera plików,
   więc nikt nie musi się go uczyć, a przy wąskim ekranie kolumny składają się
   jedna pod drugą, bo lista folderów jest krótka i nie warto jej ściskać. */
.media-uklad { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 16px; align-items: start; }
@media (max-width: 900px) { .media-uklad { grid-template-columns: minmax(0, 1fr); } }

.media-folder-wiersz { display: flex; align-items: stretch; }
.media-folder {
  flex: 1;
  display: flex; align-items: center; gap: 8px;
  padding: 7px 9px;
  color: var(--ink); text-decoration: none;
  font-size: var(--fs-4); line-height: 18px;
  border-left: 3px solid transparent;
  min-width: 0;
}
.media-folder span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Liczba plików prawym marginesem i cieńszym krojem: to podpowiedź, a nie
   nazwa. Bez niej folder mówi tylko tyle, że ktoś kiedyś wymyślił jego nazwę. */
/* Licznik plików bierze ciemniejszą szarość: siedzi na tle podświetlonego
   folderu, a to najciemniejsze z jasnych teł panelu i jaśniejszy stopień
   nie mieścił się na nim w normie kontrastu. */
.media-folder b { font-size: var(--fs-2); font-weight: 600; color: var(--muted); }
.media-folder:hover { background: var(--line-soft); }
.media-folder.wybrany { border-left-color: var(--marka); background: var(--line-soft); font-weight: 600; }
.media-folder svg { flex-shrink: 0; color: var(--muted-2); }
.media-folder.wybrany svg { color: var(--marka); }

/* Zmiana nazwy i kasowanie pod trzema kropkami: folder zakłada się raz
   i potem tylko w niego wchodzi, więc dwa przyciski przy każdej nazwie
   robiłyby z listy folderów listę przycisków. */
.media-folder-menu { position: relative; }
.media-folder-menu summary {
  list-style: none; cursor: pointer;
  width: 28px; height: 32px;
  display: grid; place-items: center;
  color: var(--muted-2);
}
.media-folder-menu summary::-webkit-details-marker { display: none; }
.media-folder-menu summary:hover { color: var(--ink); }
.media-folder-menu-tresc {
  position: absolute; right: 0; top: 100%; z-index: 5;
  width: 234px;
  border: 1px solid var(--muted-2);
  background: var(--white);
}
.media-folder-nazwa { padding: 10px 10px 11px; }

/* Etykieta nad polem, drobna i wersalikami, jak wszędzie w panelu: bez niej
   pole z wpisaną nazwą wygląda jak napis, a nie jak coś do poprawienia. */
.media-folder-nazwa label,
.media-folder-nowy label {
  display: block; margin-bottom: 4px;
  font-size: var(--fs-2); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.1em; color: var(--muted);
}

/* Pole i przycisk zatwierdzenia sklejone w jedną całość, bez szczeliny:
   czyta się to jako jedną rzecz do zrobienia, a nie dwie obok siebie. */
.media-folder-nazwa-pole { display: flex; }
.media-folder-nazwa-pole input { flex: 1; min-width: 0; }
.media-folder-nazwa-pole .przycisk-ikona { margin-left: -1px; flex-shrink: 0; }
.media-folder-nazwa-pole .przycisk-ikona:hover { color: var(--marka); border-color: var(--muted-2); }

/* Przycisk ikonowy przyklejony do pola tekstowego bierze wysokość z pola.
   Pole liczy ją z odstępów i wysokości wiersza, więc dopisanie tej samej
   liczby przy przycisku rozjechałoby się przy pierwszej zmianie rozmiaru
   pisma albo odstępów. Stąd `height: auto` i rozciąganie, a nie równanie
   liczby do liczby. Filtry rodzaju plików tak samo, żeby cały pasek
   nad wykazem był jedną linią, a nie trzema wysokościami obok siebie. */
.media-folder-nazwa-pole .przycisk-ikona,
.media-szukanie .przycisk-ikona,
.media-pasek .segmenty {
  height: auto;
  align-self: stretch;
}
.media-pasek .segment-link { display: inline-flex; align-items: center; }

/* Pozycja menu na całą szerokość, jak w każdym rozwijanym menu. Czerwień
   dopiero przy najechaniu: kasowanie ma być widoczne w chwili, w której
   kursor nad nim stoi, a nie krzyczeć z otwartego menu. */
.media-menu-pozycja {
  width: 100%;
  display: flex; align-items: center; gap: 8px;
  padding: 9px 11px;
  border: 0; border-top: 1px solid var(--line);
  background: none;
  font-family: var(--ui); font-size: var(--fs-3); color: var(--muted);
  text-align: left; cursor: pointer;
}
.media-menu-pozycja:hover { background: var(--err-bg); color: var(--red); }
.media-menu-pozycja svg { flex-shrink: 0; }

.media-folder-nowy { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line-soft); }

.media-pasek { display: flex; flex-wrap: wrap; gap: 12px 20px; align-items: center; justify-content: space-between; }
.media-szukanie { display: flex; gap: 6px; align-items: center; flex: 1; min-width: 240px; }
.media-szukanie input[type="search"] { flex: 1; min-width: 0; }

/* Filtr rodzaju plików tym samym przełącznikiem co układ galerii, tylko
   z odnośników: wybór przeładowuje wykaz, więc to nawigacja, a nie pole
   formularza, i ma się zachowywać jak odnośnik, z „otwórz w nowej karcie”
   włącznie. */
.segment-link {
  display: inline-flex; align-items: center;
  padding: 7px 16px;
  color: var(--muted); text-decoration: none;
  font-size: var(--fs-4); line-height: 18px; font-weight: 500;
  white-space: nowrap;
}
.segment-link + .segment-link { border-left: 1px solid var(--line); }
.segment-link:hover { color: var(--ink); background: var(--line-soft); }
.segment-link.wybrany { background: var(--marka); color: var(--white); font-weight: 600; }

.media-wgrywarki { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; }

/* Pole ustawienia wstawione w belkę nagłówka karty. Drobniejsze niż pole
   w formularzu, bo belka ma zostać belką: gdyby wpuścić tam pole w pełnym
   rozmiarze, urosłaby o połowę i przestała być tylko podpisem sekcji. */
.belka-pole { display: inline-flex; align-items: center; gap: 8px; }
.belka-pole label { font-size: var(--fs-2); color: var(--muted); letter-spacing: 0.08em; }
.belka-pole select {
  padding: 4px 30px 4px 9px;
  font-size: var(--fs-3);
  text-transform: none; letter-spacing: 0;
  background-position: right 8px center;
  background-size: 12px;
  max-width: 190px;
}

.media-siatka {
  list-style: none; margin: 0 0 14px; padding: 0;
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
}
.media-kafel { border: 1px solid var(--line); background: var(--white); display: flex; flex-direction: column; }
.media-kafel.bez-opisu { border-color: var(--red); }

/* Podgląd na szarym tle i zdjęcie wpisane w nie w całości, bez kadrowania:
   w bibliotece szuka się konkretnego pliku, a przycięty herb wygląda jak
   inny herb. Stała wysokość, żeby kafle stały równo w siatce. */
.media-podglad {
  position: relative;
  height: 140px;
  background: var(--line-soft);
  border-bottom: 1px solid var(--line);
}
.media-podglad > a { display: grid; place-items: center; width: 100%; height: 100%; text-decoration: none; }
.media-podglad img { max-width: 100%; max-height: 140px; display: block; }
.media-dokument { flex-direction: column; gap: 4px; color: var(--muted); }
.media-dokument b { font-size: var(--fs-2); letter-spacing: 0.08em; }
.media-dokument:hover { color: var(--marka); }

.media-dane { padding: 9px 10px; display: flex; flex-direction: column; gap: 6px; flex: 1; }
.media-nazwa {
  margin: 0; font-size: var(--fs-3); font-weight: 600; line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.media-metryka { margin: 0; font-size: var(--fs-2); color: var(--muted-2); }
.media-dane .pole label { font-size: var(--fs-2); margin-bottom: 2px; }
.media-stopka {
  margin-top: auto; padding-top: 7px;
  border-top: 1px solid var(--line-soft);
  display: flex; gap: 6px; align-items: center;
}
.media-wybor-folderu { flex: 1; min-width: 0; font-size: var(--fs-2); padding: 4px 6px; }

/* Ostrzeżenie przy przycisku zapisu i dopiero po zaznaczeniu pliku: czyta się
   je w chwili, w której ma znaczenie, zamiast wisieć nad każdym wejściem
   do biblioteki i zawadzać. */
.media-ostrzezenie b { display: block; }
.media-ostrzezenie {
  display: flex; gap: 9px; align-items: flex-start;
  margin: 0 0 14px;
  padding: 10px 12px;
  border: 1px solid var(--err-ramka);
  background: var(--err-bg);
  color: var(--ink);
  font-size: var(--fs-3); line-height: 1.5;
}
.media-ostrzezenie svg { flex-shrink: 0; color: var(--red); margin-top: 1px; }
.media-przyciski { display: flex; gap: 8px; flex-wrap: wrap; }

/* Nazwa wpisu w wykazie: grubszym krojem niż reszta wiersza. Tytuł i kategoria
   stoją obok siebie jako odnośniki w tym samym kolorze, więc bez różnicy
   w grubości wiersz czyta się jak dwie równorzędne nazwy. */
/* Kolor jak reszta wiersza (ciemny), nie domyślny niebieski link: tytuł wpisu
   ma wyglądać wszędzie tak samo, w wykazie, na pulpicie i w wykazie boksów.
   Czerwień marki dopiero przy najechaniu, żeby zapowiedzieć klikalność. */
.wykaz-tytul a { font-weight: 600; color: inherit; text-decoration: none; }
.wykaz-tytul a:hover { color: var(--marka); text-decoration: underline; }

/* Kategoria w wykazie: ciszej niż tytuł. W wierszu są dwa odnośniki, a sięga
   się po tytuł; kategoria odpowiada tylko na pytanie „gdzie to leży”, więc
   schodzi o poziom niżej także kolorem, nie tylko grubością. Podkreślenie
   wraca przy najechaniu, bo inaczej nic nie zapowiada, że da się kliknąć. */
.wykaz-kategoria a { color: var(--muted); text-decoration: none; }
.wykaz-kategoria a:hover { color: var(--marka); text-decoration: underline; }

/* === DROBNE KLASY UKŁADOWE ===
   Powstały z powtórzonych stylów wpisanych w atrybuty szablonów. Sam atrybut
   `style` nie jest tu grzechem: szerokość kolumny tabeli jest cechą tej jednej
   tabeli i klasa na każdą z nich to dwadzieścia klas użytych raz. Grzechem jest
   ten sam zestaw właściwości powtórzony w kilku plikach, bo poprawka wymaga
   wtedy pamiętania o wszystkich. Poniżej tylko takie przypadki. */

/* Kolumna sekcji formularza: karty jedna pod drugą z równym odstępem. */
.kolumna-sekcji { display: flex; flex-direction: column; gap: 18px; }
.kolumna-kart { display: flex; flex-direction: column; gap: 14px; }

/* Stopka karty z przyciskiem zapisu, odcięta kreską od zawartości. */
.stopka-karty { padding: 12px 15px; border-top: 1px solid var(--line-soft); }

/* Akapit objaśniający w karcie: bez marginesu, bo odstęp daje karta. */
.akapit-karty { margin: 0; font-size: var(--fs-4); line-height: 1.65; }

/* Operacja w historii: plakietka i szczegół w jednym rzędzie.

   Szczegół pod plakietką rozpychał wiersz, więc tabela, w której raz na kilka
   wpisów ktoś wgrał plik, miała wiersze różnej wysokości i wyglądała
   na poszarpaną.

   Rząd jest elastyczny, a nie zwykłym tekstem, bo tylko wtedy da się kazać
   długiej nazwie urwać się wielokropkiem zamiast zepchnąć samą siebie
   do następnej linii. `min-width: 0` jest tu konieczne: bez niego element
   elastyczny nie kurczy się poniżej swojej zawartości i przycięcie nigdy
   nie zadziała. Pełna nazwa zostaje w podpowiedzi po najechaniu. */
.historia-operacja { display: flex; align-items: center; gap: 8px; min-width: 0; }
.historia-szczegol {
  flex: 1;
  min-width: 0;
  color: var(--muted);
  font-size: var(--fs-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- diagnostyka ---------- */

/**
 * Punkty stanu wdrożenia.
 *
 * Zamiast plakietek z napisem „OK” po lewej stoi kropka w kolorze stanu.
 * Napis niesie całą treść, a kolor jest dodatkiem, nie jedynym nośnikiem
 * informacji: to warunek dostępności, bo osoba nierozróżniająca zieleni
 * od czerwieni ma dostać ten sam komunikat co każdy inny.
 */
.lista-stanu { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.lista-stanu li {
  position: relative; padding-left: 20px;
  font-size: var(--fs-6); line-height: 1.55;
}
.lista-stanu li::before {
  content: ""; position: absolute; left: 0; top: 7px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--muted);
}
.lista-stanu .stan-ok::before { background: var(--ok); }
.lista-stanu .stan-uwaga::before { background: var(--warn); }
.lista-stanu .stan-blad::before { background: var(--red); }
.lista-stanu .stan-blad { font-weight: 600; }

/**
 * Wpisy dziennika awarii.
 *
 * Pismo o stałej szerokości i zachowane łamanie wierszy, bo w środku są
 * ścieżki plików i ślad wywołań, których nie wolno posklejać w jeden akapit.
 * Zawijanie zamiast poziomego paska: wpis czyta się w całości, a nie przesuwa
 * w bok przy każdej dłuższej ścieżce.
 */
.lista-awarii { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.lista-awarii pre {
  margin: 0; padding: 11px 13px;
  background: var(--paper); border: 1px solid var(--line-soft); border-left: 3px solid var(--red);
  font-family: var(--mono); font-size: var(--fs-3); line-height: 1.6;
  white-space: pre-wrap; word-break: break-word;
}

/* Podgląd raportu. Ten sam tekst, który idzie do pliku, więc bez zawijania:
   kolumny w zestawieniach mają się zgadzać ze sobą, a długich wierszy tu nie ma. */
.raport-diagnostyczny {
  margin: 0; padding: 14px 16px;
  background: var(--paper); border: 1px solid var(--line-soft);
  font-family: var(--mono); font-size: var(--fs-3); line-height: 1.55;
  max-height: 460px; overflow: auto;
}
