/* Nowoczesne efekty graficzne z wyłącznikami (właściciel, 28.10.2026: "Przygotuj z 50 jakiś nowych propozycji związanych
   z nowoczesnymi efektami graficznymi i je porządnie zaprogramuj, tak, aby w razie czego dało się je cofnąć. Pamiętaj, że
   żadne efekty nie mogą nam przesłaniać danych oraz list"). Spis efektów i ich nazwy: App\Efekty::LISTA.

   ZASADY TEGO PLIKU (pilnuje unit-efekty-wylaczniki):
   - każda reguła stoi pod html[data-efekty~="kod"] - kod z App\Efekty::LISTA; wyłączony efekt nie ma się czego uchwycić;
   - barwy tylko ze zmiennych (var(--toz-granat), var(--toz-zloto), color-mix z nimi, transparent, currentColor) - żadnych
     #rrggbb ani rgb() poza rysunkami w url(data:...) używanymi jako maska; ciemny wygląd przelicza wtedy efekt sam;
   - cały ruch w @media (prefers-reduced-motion: no-preference), raz, bez forwards/both na .card, .main, tr i td;
   - nic NAD danymi, listami, polami i napisami - tylko wygląd samego elementu albo ozdoba za treścią;
   - arkusz idzie tylko na ekran (media="screen" w layout.php) - na wydruku efektów nie ma;
   - telefon: mniej, bez przesuwania strony w bok, bez dvh.
   Każdy etap i część dopisuje się pod swoim znacznikiem niżej. */

/* === etap 1, część A === */

/* brzeg-tabeli (nr 1; właściciel 28.10.2026: efekty z wyłącznikami) - tabela szersza niż ekran ma przy brzegu, w którą
   stronę są jeszcze kolumny, cienką złotą kreskę: na telefonie pasek przewijania się chowa i nie widać, że w bok jest
   więcej. Kreska to cień rzucony NA ZEWNĄTRZ pojemnika (w odstęp karty) - bez maski i bez przygaszania skrajnych kolumn,
   nic nad danymi. Steruje nią położenie przewinięcia samej tabeli (oś przewijania, bez skryptu i bez nasłuchu): pojemnik
   bez nadmiaru ma oś nieczynną, więc mieszcząca się tabela nie dostaje nic. Animuje się wyłącznie box-shadow (.table-wrap
   nie ma własnego cienia ani animacji w app.css) - bez position, transform i opacity; kopia nagłówka i jej oś
   (naglowek-tabeli.js) zostają nietknięte. Przeglądarka bez osi przewijania i bez ruchu w systemie - tabela jak dziś.
   W @supports pełna oś z "self": przeglądarka, która zna scroll(), ale nie oś samego pojemnika, odrzuciłaby oś
   i z samym "animation ... both" stanęłaby na stałe na ostatniej klatce (kreska z lewej przy każdej tabeli).
   Barwa kreski jak przy zmienionym polu (pole-zmienione): złoto z domieszką barwy napisu, bez przezroczystości - kreska
   jest tu jedynym znakiem, że w bok są jeszcze kolumny, a czyste złoto ma na białej karcie ok. 2:1 (85% krycia - 1,8:1);
   z domieszką ponad 3:1 do karty i do tła strony, w ciemnym wyglądzie jaśnieje razem z napisem (przegląd całości,
   28.10.2026; liczy unit-efekty-e1a). Przeglądarka z osią przewijania zna color-mix(). */
@media (prefers-reduced-motion: no-preference) {
    @supports (animation-timeline: scroll(self inline)) {
        html[data-efekty~="brzeg-tabeli"] .table-wrap {
            animation: np-brzeg-tabeli linear both;
            /* Po skrócie "animation", który zeruje oś. */
            animation-timeline: scroll(self inline);
        }
    }
}
@keyframes np-brzeg-tabeli {
    0% { box-shadow: -3px 0 0 -1px transparent, 3px 0 0 -1px color-mix(in srgb, var(--toz-zloto) 70%, var(--toz-text)); }
    4%, 96% {
        box-shadow: -3px 0 0 -1px color-mix(in srgb, var(--toz-zloto) 70%, var(--toz-text)),
            3px 0 0 -1px color-mix(in srgb, var(--toz-zloto) 70%, var(--toz-text));
    }
    100% { box-shadow: -3px 0 0 -1px color-mix(in srgb, var(--toz-zloto) 70%, var(--toz-text)), 3px 0 0 -1px transparent; }
}
/* Przy okazji: gest gładzika dojeżdżający do końca tabeli nie cofa całej strony do poprzedniej. To nie ruch - zostaje
   także bez ruchu w systemie. */
html[data-efekty~="brzeg-tabeli"] .table-wrap { overscroll-behavior-x: contain; }

/* wiersz-klawiatury (nr 2; właściciel 28.10.2026) - wiersz, w którym stoi kursor klawiatury, wygląda jak wiersz pod
   myszą: kreska z lewej i jasne tło. Dziś obwódkę ma tylko mały przycisk na końcu wiersza i w szerokiej tabeli nie
   wiadomo, do którego wiersza należy. W :is() tylko to, co po kliknięciu myszą NIE dostaje :focus-visible (odnośnik,
   przycisk, rozwinięcie, pole zaznaczenia) - pola do pisania i listy wyboru dostają je także po kliknięciu, a raport
   kasowy ma je w wierszach .table: tam kursor widać w samym polu, wiersz się nie zapala. Kreska w barwie fokusu
   (w ciemnym wyglądzie --toz-granat zostaje ciemny, --toz-fokus jest jasny), tej samej grubości co przy zaznaczonym
   wierszu. Wiersz w trakcie poprawki ma własne kreski, a znaczniki wiersza zostają swoje - złote (powrót do wiersza,
   świeży wpis historii, wiersz z kotwicy na liście postów) i bursztynowy zmiany od innej osoby (na-zywo.js nie gasi go
   klawiszem Tab); tło mogą dostać. Wiersz z kotwicy wyłączony tylko na liście postów, jak w app.css: cele zbiórek,
   widoki list i rodzaje miejsc wracają po zapisie na #wiersz, który złotej kreski nie ma - bez kreski kursora byłby
   jedynym wierszem bez niej (przegląd części A, 28.10.2026). Ustępuje też złotej kresce wiersza, który się otwiera
   (klik-czeka, klasa np-tu-w-drodze pod html.w-drodze): Enter na odnośniku wiersza zostawia na nim :focus-visible, a ten
   sam wiersz otwarty myszą ma złotą kreskę - bez wyjątku kreska kursora przykrywała złotą i ten sam stan wyglądał inaczej
   z klawiatury (przegląd całości, 28.10.2026). Tło przez :where() - waga samej bramki, więc kolor stanu
   wiersza i jego wariant pod kursorem z app.css wygrywają. Bez ruchu z założenia; bez :has() - jak dziś. */
html[data-efekty~="wiersz-klawiatury"] .table tbody tr:not(.wiersz-edytowany):not(.wiersz-ostatni):not(.wpis-swiezy):not(.na-zywo-zmiana):not(.tabela-postow tbody tr:target):not(html.w-drodze .np-tu-w-drodze):has(:is(a, button, summary, input[type="checkbox"], input[type="radio"]):focus-visible) > td:first-child {
    box-shadow: inset 3px 0 0 var(--toz-fokus);
}
html[data-efekty~="wiersz-klawiatury"] :where(.table tbody tr:not(.wiersz-edytowany):has(:is(a, button, summary, input[type="checkbox"], input[type="radio"]):focus-visible)) {
    background-color: var(--toz-granat-jasny);
}

/* wiersz-w-zmianie (nr 3; właściciel 28.10.2026) - po otwarciu w wierszu listy zmiany plakietki (w-wierszu.js: przycisk
   dostaje aria-expanded="true", przy wyborze, Esc, Tab i kliknięciu obok "false") cały wiersz ma lekki odcień i złotą
   kreskę z lewej: widać, w którym wierszu zmienia się plakietkę, także gdy lista zasłania sąsiednie wiersze. Odcień
   w warstwie obrazka komórek (kolor stanu wiersza zostaje pod spodem; zaznaczony wiersz ma odcień w tej samej
   własności - przy obu naraz ten sam wygląd, bez sumowania), kreska w obrysie pierwszej komórki - nic nowego nad
   danymi. --toz-fokus, bo w ciemnym wyglądzie --toz-granat zostaje ciemnym granatem i 10% go nie widać. Komórki nie
   dostają animacji; w bloku ruchu tylko przejście kreski przy otwarciu (przy zamknięciu gaśnie od razu). */
html[data-efekty~="wiersz-w-zmianie"] .table tbody tr:has(button.w-wierszu[aria-expanded="true"]) > td {
    background-image: linear-gradient(color-mix(in srgb, var(--toz-fokus) 10%, transparent), color-mix(in srgb, var(--toz-fokus) 10%, transparent));
}
html[data-efekty~="wiersz-w-zmianie"] .table tbody tr:has(button.w-wierszu[aria-expanded="true"]) > td:first-child {
    box-shadow: inset 3px 0 0 var(--toz-zloto);
}
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="wiersz-w-zmianie"] .table tbody tr:has(button.w-wierszu[aria-expanded="true"]) > td:first-child {
        transition: box-shadow .15s;
    }
}

/* pasek-zbiorczy (nr 4; właściciel 28.10.2026) - pasek działań pod listą ma dziś zawsze tę samą jasnogranatową ramkę;
   gdy coś jest zaznaczone, ramka przechodzi w spadek z granatu w złoto i raz rozchodzi się wokół niej złota poświata -
   widać, że przyciski paska działają. Stan z zaczepów zaznaczanie.js: licznik z .zbiorcze-licznik-aktywny albo przycisk
   [data-wymaga-zaznaczenia] włączony PRZEZ SKRYPT - data-podpowiedz-wlasna dokłada dopiero pierwsze przeliczenie,
   a w HTML przyciski nie mają disabled; samo :enabled pasowałoby przy wczytaniu i pasek błyskałby przy każdym wejściu
   na listę. Tło paska (var(--toz-granat-jasny) z app.css) powtórzone w warstwie padding-box - skrót background zeruje
   warstwy, więc komplet. Granat ramki z --toz-fokus (w ciemnym wyglądzie jasny). Pasek się nie wysuwa, nie przykleja
   i nie chowa (p. 24); poświata 4 px w odstępie pod tabelą, nie na wiersze i pola paska; animacja raz, bez fill-mode -
   rusza, gdy zaznaczenie się pojawia. Bez :has() - jak dziś. */
html[data-efekty~="pasek-zbiorczy"] .zbiorcze:has(.zbiorcze-licznik-aktywny, [data-wymaga-zaznaczenia][data-podpowiedz-wlasna]:enabled) {
    border-color: transparent;
    background: linear-gradient(var(--toz-granat-jasny), var(--toz-granat-jasny)) padding-box,
        linear-gradient(90deg, var(--toz-fokus), var(--toz-zloto)) border-box;
}
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="pasek-zbiorczy"] .zbiorcze:has(.zbiorcze-licznik-aktywny, [data-wymaga-zaznaczenia][data-podpowiedz-wlasna]:enabled) {
        animation: np-pasek-zbiorczy .6s ease-out;
    }
}
@keyframes np-pasek-zbiorczy {
    0%, 100% { box-shadow: 0 0 0 0 transparent; }
    40% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--toz-zloto) 30%, transparent); }
}

/* === etap 1, część B === */

/* karty-glebia (nr 5; właściciel 28.10.2026: efekty z wyłącznikami) - karty i kafelki jak kartki leżące na tle: cień
   z trzech warstw, tuż przy krawędzi ostry, dalej szeroki i blady. Jedna zmienna --toz-cien, której używają .card,
   .galeria-kafelek, .spis-sekcji i .wzor pod myszą (html z atrybutem waży więcej niż :root z app.css). Warstwy stoją
   w osobnych zmiennych, żeby wariant telefonu był w jednym miejscu: do 640 px bez dalekiej warstwy (kafelki galerii
   mają tam 10 px odstępu). Cień leży poza krawędzią, w odstępach między kartami - nic na treści. */
html[data-efekty~="karty-glebia"] {
    --np-glebia: 0 1px 1px color-mix(in srgb, var(--toz-granat-ciemny) 6%, transparent),
        0 2px 6px color-mix(in srgb, var(--toz-granat-ciemny) 5%, transparent),
        0 10px 24px -8px color-mix(in srgb, var(--toz-granat-ciemny) 12%, transparent);
    --np-glebia-uniesiona: 0 1px 2px color-mix(in srgb, var(--toz-granat-ciemny) 8%, transparent),
        0 4px 10px color-mix(in srgb, var(--toz-granat-ciemny) 7%, transparent),
        0 14px 28px -10px color-mix(in srgb, var(--toz-granat-ciemny) 16%, transparent);
}
@media (max-width: 640px) {
    html[data-efekty~="karty-glebia"] {
        --np-glebia: 0 1px 1px color-mix(in srgb, var(--toz-granat-ciemny) 6%, transparent),
            0 2px 6px color-mix(in srgb, var(--toz-granat-ciemny) 5%, transparent);
        --np-glebia-uniesiona: 0 1px 2px color-mix(in srgb, var(--toz-granat-ciemny) 8%, transparent),
            0 4px 10px color-mix(in srgb, var(--toz-granat-ciemny) 7%, transparent);
    }
}
/* TYLKO w jasnym wyglądzie: w ciemnym --toz-granat-ciemny zostaje granatem, a ciemny.css ma własny głęboki, czarny
   cień - granat 6-12% na prawie czarnym tle by go osłabił (tam głębię daje krawedz-swiatla). Jasny wygląd to meta
   color-scheme "light" (wygląd jasny na stałe, bez ciemny.css) albo "light dark" przy jasnym systemie urządzenia
   (ciemny.css ma wtedy media prefers-color-scheme: dark i nie działa) - layout.php.
   Całość w @supports z color-mix() (przegląd części B, 28.10.2026): wartość z var() przeglądarka przyjmuje przy
   wczytaniu bez sprawdzania, a dopiero przy wyliczaniu odrzuca - wtedy box-shadow: var(--toz-cien) karty spada do
   "none". Telefon ze starszym Safari (iOS 15.4-16.1: :has() już jest, color-mix() jeszcze nie) zgubiłby dzisiejszy
   cień kart; z @supports zostaje przy nim. */
@supports (color: color-mix(in srgb, transparent 50%, transparent)) {
    html[data-efekty~="karty-glebia"]:has(meta[name="color-scheme"][content="light"]) { --toz-cien: var(--np-glebia); }
    @media (prefers-color-scheme: light) {
        html[data-efekty~="karty-glebia"]:has(meta[name="color-scheme"][content="light dark"]) { --toz-cien: var(--np-glebia); }
    }
    /* Kafelki plików, zdjęć, wzorów i galerii pod myszą „unoszą się” samym mocniejszym cieniem - bez przesuwania (nic
       pod kursorem nie ucieka). Waga wyższa niż .galeria-kafelek:hover i .wzor:hover z app.css, które mają własny cień.
       Tylko urządzenia z myszą (na dotyku :hover zostaje po dotknięciu) i tylko w jasnym wyglądzie, jak wyżej. */
    @media (hover: hover) {
        html[data-efekty~="karty-glebia"]:has(meta[name="color-scheme"][content="light"]) :is(.materialy > li, .zalaczniki > li, .wzor, .galeria-kafelek):hover {
            box-shadow: var(--np-glebia-uniesiona);
        }
    }
    @media (hover: hover) and (prefers-color-scheme: light) {
        html[data-efekty~="karty-glebia"]:has(meta[name="color-scheme"][content="light dark"]) :is(.materialy > li, .zalaczniki > li, .wzor, .galeria-kafelek):hover {
            box-shadow: var(--np-glebia-uniesiona);
        }
    }
}
/* Płynne uniesienie tylko na kafelkach plików i zdjęć - .galeria-kafelek i .wzor mają już w app.css przejście ramki
   i cienia (nowe by je zabrało). Nigdy na .card: przejście na karcie to ruch całej strony przy każdej zmianie cienia. */
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="karty-glebia"] :is(.materialy > li, .zalaczniki > li) { transition: box-shadow .15s ease-out; }
}

/* krawedz-swiatla (nr 6; właściciel 28.10.2026: efekty z wyłącznikami) - w ciemnym wyglądzie karty i kafelki mają
   jaśniejszą górną krawędź, jak brzeg szklanej płyty oświetlonej z góry: na ciemnym tle cień prawie nie działa.
   Sama górna ramka (ta sama grubość, 1 px), bez cieni: cienie kafelków pod myszą stoją w app.css jako barwy na sztywno,
   których arkusz efektów nie może powtórzyć. light-dark() wybiera po schemacie strony (ciemny.css ma color-scheme: dark,
   meta color-scheme w layout.php) - w jasnym daje dzisiejszą barwę ramki, czyli zero zmiany. Karta pytania przed
   usunięciem (.card-danger) ma własną czerwoną ramkę - bez linii. Kafelki pod myszą i przy fokusie mają swoją ramkę
   (var(--toz-fokus)) - też bez linii.
   W @supports z light-dark() (przegląd części B, 28.10.2026): deklaracji z var() w środku przeglądarka bez light-dark()
   NIE odrzuca przy wczytaniu, tylko przy wyliczaniu - a wtedy górna ramka bierze barwę napisu (ciemna kreska na każdej
   karcie w jasnym wyglądzie, np. iPhone z iOS 16 albo 17.0-17.4). Z @supports taka przeglądarka ma ramkę jak dziś. */
@supports (color: light-dark(transparent, transparent)) {
    html[data-efekty~="krawedz-swiatla"] .card:not(.card-danger),
    html[data-efekty~="krawedz-swiatla"] .galeria-kafelek:not(:hover):not(:focus-visible),
    html[data-efekty~="krawedz-swiatla"] .wzor:not(:hover):not(:focus-visible) {
        border-top-color: light-dark(var(--toz-border), color-mix(in srgb, var(--toz-text) 24%, var(--toz-border)));
    }
}

/* plakietki-obwodka (nr 7; właściciel 28.10.2026: efekty z wyłącznikami) - plakietka stanu nie zlewa się z wierszem
   pomalowanym tym samym stanem: ramka bierze odcień napisu plakietki (currentColor), więc każda z barw stanu ma swoją
   bez listy barw, a ciemny wygląd ma jasny brzeg sam z siebie. .stan ma już w app.css ramkę 1 px (przezroczystą albo
   bladą w kolorze stanu) - zmienia się tylko jej barwa, rozmiar plakietki zostaje. Bez pustej plakietki w wierszu
   (.stan-pusty, przerywana ramka) i bez pełnej czerwieni (.stan-alarm). */
html[data-efekty~="plakietki-obwodka"] .stan:not(.stan-pusty):not(.stan-alarm) {
    border-color: color-mix(in srgb, currentColor 35%, transparent);
}
/* .badge (konta, wzory) ramki nie ma - cienka obwódka do środka, też bez zmiany rozmiaru. Bez „Zostało” w Terminarzu
   (.zostalo): ma własną obwódkę i puls po terminie na tej samej własności. */
html[data-efekty~="plakietki-obwodka"] .badge:not(.zostalo) {
    box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 30%, transparent);
}

/* === etap 1, część C === */

/* Odnośniki w odcieniu złota (odnosniki-zlote; właściciel 28.10.2026: efekty z wyłącznikami, nr 8). Zmienia się tylko
   kreska odnośnika bez własnej klasy - podpowiedzi, komunikaty, opisy, Dziennik zdarzeń, instrukcje na /konto; przyciski,
   liczniki, zakładki i nazwy wzorów mają klasę i zostają. Linii nie ustawiamy: odnośnik bez podkreślenia zostaje bez
   niego. Kreska jest JEDYNYM znakiem odnośnika (barwa napisu ma do zwykłego tekstu ok. 1,6:1, WCAG 1.4.1), więc złoto
   pół na pół z barwą napisu: ok. 4:1 na bieli, co najmniej 3,5:1 na tłach komunikatów, ok. 9:1 w ciemnym wyglądzie
   (czyste złoto na bieli ok. 2:1 - za mało; liczy unit-efekty-e1c). Pod myszą i przy kursorze klawiatury kreska
   w barwie napisu. */
html[data-efekty~="odnosniki-zlote"] a:not([class]) {
    text-decoration-thickness: from-font;
    text-underline-offset: .22em;
    text-decoration-skip-ink: auto;
    text-decoration-color: color-mix(in srgb, var(--toz-zloto) 50%, currentColor);
}
html[data-efekty~="odnosniki-zlote"] a:not([class]):hover,
html[data-efekty~="odnosniki-zlote"] a:not([class]):focus-visible { text-decoration-color: currentColor; }

/* Paski przewijania w barwach systemu (paski-przewijania, nr 9; właściciel 28.10.2026): suwak w przygaszonym granacie
   na przezroczystym torze, jak pasek w bok pod tabelą. Sam html - własność dziedziczy się w dół, więc dochodzi do rozwijanych list filtrów, list
   zmiany w wierszu, pól opisu, panelu "Kolumny" i spisu części strony; .table-wrap ma własną barwę z app.css i zostaje.
   --toz-fokus, nie --toz-granat: w ciemnym wyglądzie granat zostaje ciemny (ok. 2:1 do tła), a --toz-fokus jest tam
   jasnym granatem. Suwak do tła ok. 3,6:1 w jasnym i ok. 5:1 w ciemnym (jak J204: co najmniej 3:1). Szerokość bez
   zmian - miejsce na pasek trzyma scrollbar-gutter z app.css, nic nie przeskakuje. Telefon: paski systemu bez zmian. */
html[data-efekty~="paski-przewijania"] {
    scrollbar-color: color-mix(in srgb, var(--toz-fokus) 75%, var(--toz-bg)) transparent;
}

/* Kłódka przy nazwie pola, którego nie można zmienić (klodka-pola, nr 10; właściciel 28.10.2026): pole zablokowane
   (disabled), bo brak do niego uprawnienia albo wartość ustala system, ma za nazwą małą szarą kłódkę - widać to, zanim ktoś kliknie. Karta
   otwarta w całości do podglądu kłódek nie dostaje: listy wyboru blokuje tam disabled ($blokListy), a _pasek-zapisu.php
   bez prawa zapisu nie rysuje przycisków type=submit - formularz z paskiem zapisu bez przycisku zapisu to podgląd.
   Formularz bez paska (karty administracji, np. rola na własnej karcie konta w .grid-form) - kłódka przy polu
   zablokowanym. readonly bez kłódki. Etykieta z gwiazdką ma zajęte ::after - stąd :not(.wymagane). Kłódka to maska
   barwiona kolorem nazwy pola (ciemny wygląd sam), pusty tekst zastępczy - czytnik nic nie czyta, blokadę podaje samo
   pole. Bez obsługi masek wyszedłby szary kwadrat - stąd @supports. */
@supports ((-webkit-mask-size: contain) or (mask-size: contain)) {
    html[data-efekty~="klodka-pola"] :is(form:not(:has(.pasek-zapisu)), form:has(.pasek-zapisu [type="submit"])) :is(.pole, .grid-form > div):has(> .form-control:disabled, > * > .form-control:disabled) > .label:not(.wymagane)::after {
        content: '';
        content: '' / '';
        display: inline-block;
        width: .85em;
        height: .85em;
        margin-left: .35em;
        vertical-align: -.06em;
        background-color: currentColor;
        opacity: .6;
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.6 7V5.2a3.4 3.4 0 0 1 6.8 0V7' fill='none' stroke='%23000' stroke-width='1.8'/%3E%3Cpath d='M3.5 7h9A1.5 1.5 0 0 1 14 8.5v5a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 13.5v-5A1.5 1.5 0 0 1 3.5 7zM8 9.6a1.2 1.2 0 0 0-.6 2.24V13h1.2v-1.16A1.2 1.2 0 0 0 8 9.6z' fill-rule='evenodd'/%3E%3C/svg%3E") center / contain no-repeat;
        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.6 7V5.2a3.4 3.4 0 0 1 6.8 0V7' fill='none' stroke='%23000' stroke-width='1.8'/%3E%3Cpath d='M3.5 7h9A1.5 1.5 0 0 1 14 8.5v5a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 13.5v-5A1.5 1.5 0 0 1 3.5 7zM8 9.6a1.2 1.2 0 0 0-.6 2.24V13h1.2v-1.16A1.2 1.2 0 0 0 8 9.6z' fill-rule='evenodd'/%3E%3C/svg%3E") center / contain no-repeat;
    }
}

/* Ruch części C: tylko kreska odnośnika przechodzi w barwę napisu. :where() - waga zero, więc odnośnik, który ma już
   własne przejście w app.css, je zachowuje (reguła z przejściem podmienia całą listę przejść). */
@media (prefers-reduced-motion: no-preference) {
    :where(html[data-efekty~="odnosniki-zlote"] a:not([class])) { transition: text-decoration-color .15s ease-out; }
}

/* === etap 2, część A === */

/* filtry-ustawione (nr 11; właściciel 28.10.2026: efekty z wyłącznikami) - pole filtra, które TERAZ zawęża listę, widać
   od razu: jasnogranatowe tło i ramka w barwie fokusu (jak dziś pole wielokrotnego wyboru z zaznaczeniem) oraz mała
   złota kropka za nazwą pola. Według atrybutów od serwera (value, selected, checked), a nie tego, co się właśnie pisze -
   wyróżnione jest to, co naprawdę działa na listę. „Ustawione” jak ustawiony() w na-telefonie.js: nie liczą się komórki
   z data-nie-liczy (wybór rodzaju daty, stany na start) i ze znacznikiem data-stany-na-start, pola wyłączone, ukryte,
   z data-nie-liczy i z data-pokaz-wszystkie-stany, a w liście wyboru pierwsza pozycja (= wszystkie). Pole z błędem
   (.form-control-blad, „ten wpis nie zawęża listy”) zostaje czerwone. Formularz pracy w siatce filtrów (import,
   data-bez-zwijania) - bez wyróżnień. Pole wielokrotnego wyboru ma tło z app.css (.wybor-wielu-aktywny) - tu dostaje
   tylko kropkę. Napis pola ze zmiennej -tekst: arkusz efektów nie przechodzi przez generator ciemnego wyglądu, a tam
   --toz-granat-ciemny zostaje ciemnym granatem na ciemnym tle pola (ok. 1,5:1). Samo background-color - obrazy tła pola
   (kreska fokusu, strzałka listy) zostają. Bez :has() - pole jak dziś. Rozbłysk przy pustym wyniku - skrypt efektów. */
html[data-efekty~="filtry-ustawione"] form.filters:not([data-bez-zwijania]) > div:not([data-nie-liczy]):not(:has([data-stany-na-start])) > input.form-control[value]:not([value=""]):not([type="hidden"]):not(:disabled):not(.form-control-blad):not([data-nie-liczy]):not([data-pokaz-wszystkie-stany]),
html[data-efekty~="filtry-ustawione"] form.filters:not([data-bez-zwijania]) > div:not([data-nie-liczy]):not(:has([data-stany-na-start])) > select.form-control:not(:disabled):not(.form-control-blad):not([data-nie-liczy]):not([data-pokaz-wszystkie-stany]):has(> option:not(:first-child)[selected]) {
    background-color: var(--toz-granat-jasny);
    border-color: var(--toz-fokus-ramka);
    color: var(--toz-granat-ciemny-tekst, var(--toz-granat-ciemny));
}
/* Kropka za nazwą pola - także przy polu wielokrotnego wyboru z zaznaczeniem od serwera. Prawy margines ujemny o całą
   szerokość kropki z odstępem: kropka nie zajmuje miejsca w wierszu, więc nazwa łamie się tak samo jak dziś (także na
   telefonie), a w najgorszym razie kropka wchodzi w odstęp siatki filtrów (8-16 px), nie na sąsiednie pole. Pusty tekst
   zastępczy - czytnik nic nie czyta, ustawienie podaje samo pole. Etykieta z gwiazdką ma zajęte ::after. */
html[data-efekty~="filtry-ustawione"] form.filters:not([data-bez-zwijania]) > div:not([data-nie-liczy]):not(:has([data-stany-na-start])):has(> input.form-control[value]:not([value=""]):not([type="hidden"]):not(:disabled):not(.form-control-blad):not([data-nie-liczy]):not([data-pokaz-wszystkie-stany])) > .label:not(.wymagane)::after,
html[data-efekty~="filtry-ustawione"] form.filters:not([data-bez-zwijania]) > div:not([data-nie-liczy]):not(:has([data-stany-na-start])):has(> select.form-control:not(:disabled):not(.form-control-blad):not([data-nie-liczy]):not([data-pokaz-wszystkie-stany]) > option:not(:first-child)[selected]) > .label:not(.wymagane)::after,
html[data-efekty~="filtry-ustawione"] form.filters:not([data-bez-zwijania]) > div:not([data-nie-liczy]):not(:has([data-stany-na-start])):has(> details.wybor-wielu input[type="checkbox"][checked]:not(:disabled):not([data-nie-liczy]):not([data-pokaz-wszystkie-stany])) > .label:not(.wymagane)::after {
    content: '';
    content: '' / '';
    display: inline-block;
    width: 6px;
    height: 6px;
    margin: 0 -10px 0 4px;
    border-radius: 50%;
    background-color: var(--toz-zloto);
    vertical-align: .15em;
}

/* staranne-pismo (nr 12; właściciel 28.10.2026: efekty z wyłącznikami) - komunikaty, podpowiedzi i opisy nie zostawiają
   jednego słowa w ostatniej linijce (pretty), a tytuły części kart, legendy i nazwy kolumn w dwóch linijkach łamią się
   na równe połowy (balance; .h4 ma je już w app.css). Zmienia się tylko miejsce łamania - balance nie zmienia liczby
   linijek ani szerokości kolumn, więc kopia nagłówka (naglowek-tabeli.js, ta sama klasa .table) mierzy to samo. pretty
   nigdy w komórkach tabel (:not(td *)) - przy 500 wierszach to koszt bez zysku. Sama własność text-wrap-style, nie skrót
   text-wrap: skrót ustawia też text-wrap-mode: wrap i z wagą bramki zdejmowałby white-space: nowrap z app.css (kolumny
   dat i kwot, plakietki) - nagłówek „Data” łamałby się inaczej niż dziś. Przeglądarka bez text-wrap-style (i Firefox bez
   pretty) łamie jak dziś. */
html[data-efekty~="staranne-pismo"] :is(.alert, .hint, p.muted, .card p, dd, .powtorka, .wzor-do-czego):not(td *) {
    text-wrap-style: pretty;
}
html[data-efekty~="staranne-pismo"] :is(.card-head h2, .h5, h3, legend, .table th) {
    text-wrap-style: balance;
}
/* Przy okazji cyfry równej szerokości tam, gdzie ich jeszcze nie ma: komórki tabel poza liczbami, datami i Lp. (te mają
   je w app.css), plakietki i wartości w opisach karty - liczby w kolumnie stoją równo pod sobą. */
html[data-efekty~="staranne-pismo"] :is(.table td:not(.liczba):not(.kol-data):not(.kol-lp):not(.kol-lp-lista), .badge, .stan, dd) {
    font-variant-numeric: tabular-nums;
}

/* tlo-cichnie (nr 13; właściciel 28.10.2026: efekty z wyłącznikami) - u góry strony poświata za kartami (.tlo-zorza,
   .tlo-swiatlo, .okazja-tlo) ma pełne barwy, a przez pierwsze ok. 900 px przewijania przygasa mniej więcej do połowy:
   w środku długiej listy albo formularza tło nie odciąga oka; po powrocie na górę barwy wracają. Zasłona w barwie tła
   strony w wolnym body::after (app.css i ciemny.css go nie używają): jako ostatnie dziecko body maluje się po warstwach
   tła z z-index -1, a pod całą treścią - nic nie wchodzi na karty, kliknięcia przechodzą (pointer-events: none).
   Przypięta do ekranu z wysokością dużego ekranu (lvh, bez dvh - jak inne warstwy), zmienia się samo jej krycie
   według położenia strony (oś przewijania, bez skryptu i bez nasłuchu) - przewijanie nic nie kosztuje. Na stronie
   z łuną po zapisie, sceną święta, „Witaj w TOZ” albo pieczęcią zasłony nie ma wcale (te same warunki co przy
   .tlo-swiatlo::before w app.css): po „Zapisz zmiany” długi formularz wraca w to samo miejsce, a łuna wychodziłaby pod
   zasłoną. Gwiazdki, świetliki i ozdoby okazji w przewiniętej stronie przygasają razem z tłem - to ozdoby, nie zdarzenia.
   Animacji .tlo-zorza (powolny dryf) efekt nie dotyka. Do 640 px bez zasłony; bez ruchu w systemie krycie 0 - tło jak
   dziś; przeglądarka bez osi przewijania - jak dziś. */
html[data-efekty~="tlo-cichnie"] body:not([data-zapis]):not(:has(.swieto)):not(:has([data-witaj])):not(:has([data-pieczec]))::after {
    content: '';
    position: fixed; inset: 0 0 auto; height: 100vh; height: 100lvh; z-index: -1; pointer-events: none;
    background: var(--toz-bg);
    opacity: 0;
}
@media (max-width: 640px) {
    html[data-efekty~="tlo-cichnie"] body:not([data-zapis]):not(:has(.swieto)):not(:has([data-witaj])):not(:has([data-pieczec]))::after {
        display: none;
    }
}
@media (prefers-reduced-motion: no-preference) and (min-width: 641px) {
    @supports (animation-timeline: scroll(root block)) and (animation-range: 0 900px) {
        html[data-efekty~="tlo-cichnie"] body:not([data-zapis]):not(:has(.swieto)):not(:has([data-witaj])):not(:has([data-pieczec]))::after {
            animation: np-tlo-cichnie linear both;
            /* Po skrócie "animation", który zeruje oś i zakres. */
            animation-timeline: scroll(root block);
            animation-range: 0 900px;
        }
    }
}
@keyframes np-tlo-cichnie {
    from { opacity: 0; }
    to { opacity: .5; }
}

/* === etap 2, część B === */

/* email-od-razu (nr 14; właściciel 28.10.2026: efekty z wyłącznikami) - adres e-mail z literówką („jan.kowalski@”,
   odstęp w środku) po wyjściu z pola dostaje czerwoną ramkę z czerwoną kreską u dołu, a nazwa pola czerwienieje - dziś
   błąd wychodzi dopiero po zapisie. :user-invalid łapie pole dopiero po działaniu człowieka (zmiana i wyjście z pola),
   :not(:focus) - w trakcie pisania pole nie czerwienieje, a poprawione gaśnie od razu. :not([required]), bo
   :user-invalid łapie też brak wartości: puste pole obowiązkowe (logowanie, przypomnienie hasła, adres do wysyłek
   w Zarządzie, konta) czerwieniałoby po samym przejściu przez nie - te zostają jak dziś; puste pole nieobowiązkowe
   nie jest błędem. Pole z błędem z serwera (.form-control-blad) ma już czerwoną ramkę i napis pod sobą - bez dublowania.
   Ramka jak przy błędzie z serwera (var(--toz-blad)); kreska i nazwa pola w odpowiedniku -tekst, bo w ciemnym wyglądzie
   --toz-blad zostaje ciemną czerwienią (ok. 2:1 do tła pola) - kreska niesie sens, więc co najmniej 3:1 (liczy
   unit-efekty-e2b). var(--np-cien-zmienione): złota kreska zmienionego pola (pole-zmienione, etap 3) zostaje - ta
   reguła waży więcej niż .form-control.np-zmienione i bez niej by ją zgasiła. Formularze z novalidate wysyłają się
   dalej bez blokady - o zapisie rozstrzyga serwer (filter_var); rozjazdy reguły przeglądarki z serwerem wypisuje test.
   Nazwa pola: .pole i wiersz .grid-form (karta oddziału) z .label, panel szybkiego zgłoszenia z napisem w <span>.
   Bez dymków, bez napisów nad polem, bez ruchu. Przeglądarka bez :user-invalid albo :has() odrzuca regułę - jak dziś. */
html[data-efekty~="email-od-razu"] input.form-control[type="email"]:not([required]):not(.form-control-blad):user-invalid:not(:focus) {
    border-color: var(--toz-blad);
    box-shadow: inset 0 -2px 0 var(--toz-blad-tekst, var(--toz-blad)), var(--np-cien-zmienione, 0 0 transparent);
}
html[data-efekty~="email-od-razu"] :is(.pole, .grid-form > div):has(> input.form-control[type="email"]:not([required]):not(.form-control-blad):user-invalid:not(:focus)) > .label,
html[data-efekty~="email-od-razu"] .panel-pole:has(> input.form-control[type="email"]:not([required]):not(.form-control-blad):user-invalid:not(:focus)) > span:first-child {
    color: var(--toz-blad-tekst, var(--toz-blad));
}

/* wybor-karta (nr 15; właściciel 28.10.2026: efekty z wyłącznikami) - karta wyboru z opisem (label.choice: sposób
   logowania dwuetapowego, wybory na karcie oddziału, w ustawieniach i na ekranie efektów, karty pism i faktur) ma dziś
   po zaznaczeniu tylko ptaszek w małym polu i tę samą szarą ramkę. Zaznaczona: ramka w barwie fokusu, tło w spadku
   z płyty w jasny granat i złota kreska 3 px przy lewym brzegu - w wewnętrznym marginesie (12 px), pole, napis i opis
   zostają na miejscu. Wszystko to wygląd samej karty (ramka i tło), nic nad treścią; bez znaków i napisów, więc ekran
   logowania dwuetapowego nic nie zdradza. --toz-fokus-ramka zamiast --toz-granat: w ciemnym wyglądzie granat zostaje
   ciemny, ramka fokusu jest tam jasna. Zaznaczona (także wyłączona przy podglądzie) pod myszą się nie zmienia - nie ma
   wariantu :hover. Pole jednego wyboru: odznaczona karta traci wygląd od razu (bez przejścia). Rozmiary warstw tła
   jawnie, żeby kreska mogła rosnąć (niżej). Bez :has() - karta jak dziś. */
html[data-efekty~="wybor-karta"] .choice:has(input:checked) {
    border-color: var(--toz-fokus-ramka);
    background: linear-gradient(var(--toz-zloto), var(--toz-zloto)) 0 0 / 3px 100% no-repeat,
        linear-gradient(180deg, var(--toz-plyta), var(--toz-granat-jasny)) 0 0 / 100% 100% no-repeat;
}
/* Niezaznaczona i niewyłączona karta pod myszą ma ciemniejszą ramkę - widać, że się ją klika. Tylko z myszą (na dotyku
   :hover zostaje po dotknięciu). W @supports z color-mix(): deklarację z var() w środku przeglądarka bez color-mix()
   odrzuca dopiero przy wyliczaniu i ramka wzięłaby barwę napisu (przegląd etapu 1, 28.10.2026). */
@supports (color: color-mix(in srgb, transparent 50%, transparent)) {
    @media (hover: hover) {
        html[data-efekty~="wybor-karta"] .choice:not(:has(input:checked)):not(:has(input:disabled)):hover {
            border-color: color-mix(in srgb, var(--toz-fokus-ramka) 45%, var(--toz-border));
        }
    }
}
/* Po kliknięciu (klasa np-wybor-klik z efekty-nowoczesne.js - tylko po zmianie przez człowieka, nie przy wczytaniu
   strony z polem zaznaczonym z serwera) złota kreska rośnie od góry do dołu w 0,2 s. Animacja raz, bez fill-mode:
   po niej zostaje wygląd z reguły wyżej. Karta wyboru nie jest .card, wierszem ani komórką i nie ma animacji w app.css. */
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="wybor-karta"] .choice:has(input.np-wybor-klik:checked) {
        animation: np-wybor-karta .2s ease-out;
    }
}
@keyframes np-wybor-karta {
    from { background-size: 3px 0%, 100% 100%; }
}

/* pasek-zapisu-krawedz (nr 16; właściciel 28.10.2026: efekty z wyłącznikami) - pasek z „Zapisz” trzyma się dołu ekranu
   w środku długiego formularza i wygląda tak samo jak na jego końcu, więc nie widać, że pola ciągną się pod nim. Gdy
   jest przyklejony, jego górna krawędź jest złota (spadek z barwy fokusu w złoto); po przewinięciu do końca formularza
   pasek staje na swoim miejscu i wraca zwykła szara kreska - widać, że to koniec. Sam arkusz: zapytanie o stan
   przyklejenia (scroll-state, stuck: bottom) - bez skryptu i bez nasłuchu przewijania. container-type: scroll-state nie
   zakłada żadnego ograniczenia rozmiaru ani układu - szerokość (ujemne marginesy) i przyklejenie paska bez zmian.
   ::before paska jest wolny (app.css i ciemny.css go nie używają - pilnuje unit-efekty-e2b) i jako pseudo-element
   samego pojemnika pyta o jego stan. Pasek jest sticky, czyli pozycjonowany - ::before liczy się od niego. Kreska
   2 px w miejscu obramowania (1 px ramki i 1 px wewnętrznego marginesu 14 px), bez cienia rzucanego w górę na pola,
   nie łapie kliknięć; kropka niezapisanych zmian stoi przy przycisku, z dala od niej. --toz-fokus, bo w ciemnym
   wyglądzie --toz-granat zostaje ciemny. Do 640 px, na dotyku do 1024 px i na niskim ekranie pasek jest static -
   warunek nigdy nie zachodzi. Przeglądarka bez scroll-state (dziś Safari i Firefox) - pasek jak dziś.
   ::before powstaje dopiero przy przyklejeniu, a nowy pseudo-element nie ma stanu początkowego - @starting-style daje
   mu start z opacity 0, z którego przejście w bloku ruchu rozjaśnia kreskę w 0,2 s; bez ruchu w systemie kreska stoi
   od razu (stąd @starting-style poza blokiem ruchu). Odklejenie gasi kreskę od razu. */
@supports (container-type: scroll-state) {
    html[data-efekty~="pasek-zapisu-krawedz"] .pasek-zapisu {
        container-type: scroll-state;
    }
    @container scroll-state(stuck: bottom) {
        html[data-efekty~="pasek-zapisu-krawedz"] .pasek-zapisu::before {
            content: '';
            position: absolute;
            left: 0;
            right: 0;
            top: -1px;
            height: 2px;
            pointer-events: none;
            background: linear-gradient(90deg, var(--toz-fokus), var(--toz-zloto));
        }
        @starting-style {
            html[data-efekty~="pasek-zapisu-krawedz"] .pasek-zapisu::before {
                opacity: 0;
            }
        }
    }
}
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="pasek-zapisu-krawedz"] .pasek-zapisu::before {
        transition: opacity .2s;
    }
}

/* === etap 2, część C === */

/* zdjecie-na-liscie (nr 17; właściciel 28.10.2026: efekty z wyłącznikami) - na karcie podopiecznego, w części „Zdjęcia
   i filmy”, kafelek zdjęcia wybranego przyciskiem „Pokaż na liście” ma złotą obwódkę: od razu widać, które zdjęcie stoi
   przy imieniu na liście i w galerii. Stan daje znacznik „na liście” (span.badge-active w formularzu .wybor-na-liste
   w opisie kafelka - _sekcja-zdjecia.php i _material.php), więc po wybraniu innego zdjęcia strona wraca z serwera
   z obwódką przy nowym, a przy przenoszeniu kafelka myszą (przestaw-pliki.js przestawia ten sam element) obwódka idzie
   z nim. Ramka kafelka w złocie, pierścień i poświata w cieniu NA ZEWNĄTRZ (w odstępie siatki), obrys miniatury
   w odstępie wokół zdjęcia (outline-offset) - nic na zdjęciu, nazwie ani przyciskach. Interwencje i faktury nie mają
   zdjęcia na liście, więc selektor nic tam nie łapie; przeglądarka bez :has() zostaje przy samym znaczniku „na liście”.
   Waga wyższa niż uniesienie kafelka pod myszą z karty-glebia (ul, li i span w selektorze): wybrane zdjęcie pod myszą
   nie zmienia barw (pilnuje unit-efekty-e2c). Bez ruchu. */
html[data-efekty~="zdjecie-na-liscie"] ul.materialy > li:has(.zalacznik-opis .wybor-na-liste span.badge-active) {
    border-color: var(--toz-zloto);
}
html[data-efekty~="zdjecie-na-liscie"] ul.materialy > li:has(.zalacznik-opis .wybor-na-liste span.badge-active) .material-podglad img {
    outline: 2px solid var(--toz-zloto);
    outline-offset: 2px;
}
/* Cień pod @supports z color-mix(): bez niego deklaracja odpadłaby dopiero przy wyliczaniu i zabrała kafelkowi cień spod
   myszy z karty-glebia. Poświata do 12 px w bok - mieści się w odstępie siatki (14 px), nie sięga sąsiednich kafelków. */
@supports (color: color-mix(in srgb, transparent 50%, transparent)) {
    html[data-efekty~="zdjecie-na-liscie"] ul.materialy > li:has(.zalacznik-opis .wybor-na-liste span.badge-active) {
        box-shadow: 0 0 0 1px var(--toz-zloto), 0 4px 12px color-mix(in srgb, var(--toz-zloto) 25%, transparent);
    }
}

/* pieczec-zatwierdzenia (nr 18; właściciel 28.10.2026) - pasek „zatwierdzony” (_zatwierdzenie.php, wypisywany tylko przy
   zatwierdzonym raporcie 1,5%, inspektorskim, kasowym i uchwale) ma w prawym wolnym polu złotą okrągłą pieczęć z łapką,
   lekko przekrzywioną - jak pieczęć zamkniętej sprawy (App\Pieczec, layout.php): pierścień, kropki, łapa; bez napisu.
   Rysunek to maska w kolorze złota (ciemny wygląd sam), przygaszona do 40% - znak, nie drugi stan: zielona kreska stanu
   z lewej zostaje. Pieczęć POD napisami: ::after z z-index -1 w pasku z isolation (nad tłem paska, pod treścią), a pasek
   dostaje 88 px odstępu z prawej, więc zdania i przycisk „Zdejmij zatwierdzenie” do niej nie dochodzą; overflow: hidden -
   ani pieczęć, ani jej „stuknięcie” nie wychodzą poza pasek (w pasku nie ma rozwijanych list ani dymków - same zdania,
   kółko osoby i przycisk; obrys fokusu przycisku mieści się w odstępie paska). ::after paska jest wolny (app.css
   i ciemny.css go nie używają). Do 640 px bez pieczęci i bez odstępu (na telefonie zdania potrzebują całej szerokości);
   bez masek w przeglądarce - też nic (zostałby złoty kwadrat). */
@media (min-width: 641px) {
    @supports ((-webkit-mask-size: contain) or (mask-size: contain)) {
        html[data-efekty~="pieczec-zatwierdzenia"] .pasek-zatwierdzenia {
            position: relative;
            isolation: isolate;
            overflow: hidden;
            padding-right: 88px;
        }
        html[data-efekty~="pieczec-zatwierdzenia"] .pasek-zatwierdzenia::after {
            content: '';
            content: '' / '';
            position: absolute;
            top: 50%;
            right: 14px;
            z-index: -1;
            width: 64px;
            height: 64px;
            margin-top: -32px;
            rotate: -8deg;
            background-color: var(--toz-zloto);
            opacity: .4;
            pointer-events: none;
            -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cg fill='none' stroke='%23000'%3E%3Ccircle cx='32' cy='32' r='29.5' stroke-width='2.6'/%3E%3Ccircle cx='32' cy='32' r='18.5' stroke-width='1.2'/%3E%3Ccircle cx='32' cy='32' r='24' stroke-width='2.2' stroke-linecap='round' stroke-dasharray='.01 6.273'/%3E%3C/g%3E%3Cg transform='translate(20 20) scale(.5)'%3E%3Cellipse cx='9.5' cy='20' rx='4.4' ry='6' transform='rotate(-22 9.5 20)'/%3E%3Cellipse cx='18.4' cy='11' rx='4.6' ry='6.6' transform='rotate(-8 18.4 11)'/%3E%3Cellipse cx='29.6' cy='11' rx='4.6' ry='6.6' transform='rotate(8 29.6 11)'/%3E%3Cellipse cx='38.5' cy='20' rx='4.4' ry='6' transform='rotate(22 38.5 20)'/%3E%3Cpath d='M24 22.5c-6.9 0-12.8 6.3-12.8 12.2 0 3.9 2.9 5.9 6.3 5.9 2.6 0 4.2-1.2 6.5-1.2s3.9 1.2 6.5 1.2c3.4 0 6.3-2 6.3-5.9 0-5.9-5.9-12.2-12.8-12.2z'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cg fill='none' stroke='%23000'%3E%3Ccircle cx='32' cy='32' r='29.5' stroke-width='2.6'/%3E%3Ccircle cx='32' cy='32' r='18.5' stroke-width='1.2'/%3E%3Ccircle cx='32' cy='32' r='24' stroke-width='2.2' stroke-linecap='round' stroke-dasharray='.01 6.273'/%3E%3C/g%3E%3Cg transform='translate(20 20) scale(.5)'%3E%3Cellipse cx='9.5' cy='20' rx='4.4' ry='6' transform='rotate(-22 9.5 20)'/%3E%3Cellipse cx='18.4' cy='11' rx='4.6' ry='6.6' transform='rotate(-8 18.4 11)'/%3E%3Cellipse cx='29.6' cy='11' rx='4.6' ry='6.6' transform='rotate(8 29.6 11)'/%3E%3Cellipse cx='38.5' cy='20' rx='4.4' ry='6' transform='rotate(22 38.5 20)'/%3E%3Cpath d='M24 22.5c-6.9 0-12.8 6.3-12.8 12.2 0 3.9 2.9 5.9 6.3 5.9 2.6 0 4.2-1.2 6.5-1.2s3.9 1.2 6.5 1.2c3.4 0 6.3-2 6.3-5.9 0-5.9-5.9-12.2-12.8-12.2z'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
        }
    }
}
/* Przy wejściu na stronę pieczęć raz „stuka” na miejsce: z większej i mocniej przekrzywionej do spoczynku. Bez fill-mode -
   stan końcowy to styl spoczynkowy wyżej (obrót -8deg, 40%), więc po animacji nic się nie zmienia. Animuje się sam
   pseudoelement paska, nigdy karta ani pasek; przez cały czas pod napisami i w granicach paska. */
@media (prefers-reduced-motion: no-preference) and (min-width: 641px) {
    html[data-efekty~="pieczec-zatwierdzenia"] .pasek-zatwierdzenia::after {
        animation: np-pieczec-stuk .45s cubic-bezier(.3, .7, .4, 1);
    }
}
@keyframes np-pieczec-stuk {
    from { scale: 1.6; rotate: -28deg; opacity: 0; }
    60% { scale: .94; }
}

/* zdjecia-ciemne (nr 19; właściciel 28.10.2026) - w ciemnym wyglądzie zdjęcia w galerii do adopcji i miniatury materiałów
   na kartach (img[data-kafelek] - _material.php przy interwencji i podopiecznym, skany przy fakturze) są lekko przygaszone,
   jak kafelki mapy (ciemny.css), żeby nie świeciły w oczy; pod myszą albo przy kursorze klawiatury w kafelku wracają do
   pełnej jasności, a otwarty podgląd (podglad-plikow.js, osobny obrazek) pokazuje zdjęcie w pełnych barwach. Ciemny
   wygląd z meta color-scheme (layout.php): "dark" - na stałe, "light dark" - gdy ciemny jest system urządzenia; "light"
   - nic. Przygasa sam obrazek filtrem, nie przezroczystością (pod zdjęciem w galerii leży złota łapa) - nic na zdjęciu.
   Filtr tworzy obrazkowi własną warstwę, dlatego bez list i bez miniatur 40 px przy imieniu (.miniatura-podopiecznego).
   blur(0) przed brightness(): mgiełka zdjęć (zdjecia-mgielka.js, img.zdjecie-wylania, @keyframes z blur(4px) w app.css)
   ma wtedy tę samą listę filtrów i przechodzi płynnie z rozmycia w przygaszenie - bez tego przeskakiwałaby w połowie. */
html[data-efekty~="zdjecia-ciemne"]:has(meta[name="color-scheme"][content="dark"]) :is(.galeria-zdjecie img, img[data-kafelek]) {
    filter: blur(0) brightness(.88);
}
html[data-efekty~="zdjecia-ciemne"]:has(meta[name="color-scheme"][content="dark"]) :is(.materialy > li, .zalaczniki > li, .galeria-adopcji > li):is(:hover, :focus-within) :is(.galeria-zdjecie img, img[data-kafelek]) {
    filter: none;
}
@media (prefers-color-scheme: dark) {
    html[data-efekty~="zdjecia-ciemne"]:has(meta[name="color-scheme"][content="light dark"]) :is(.galeria-zdjecie img, img[data-kafelek]) {
        filter: blur(0) brightness(.88);
    }
    html[data-efekty~="zdjecia-ciemne"]:has(meta[name="color-scheme"][content="light dark"]) :is(.materialy > li, .zalaczniki > li, .galeria-adopcji > li):is(:hover, :focus-within) :is(.galeria-zdjecie img, img[data-kafelek]) {
        filter: none;
    }
}
/* Płynny powrót jasności tylko w bloku ruchu i tylko w ciemnym wyglądzie. Zdjęcie galerii ma w app.css przejście
   powiększenia pod myszą (transform .3s) - reguła z przejściem podmienia całą listę, więc stoi tu razem z nim
   (unit-efekty-e2c porównuje je z app.css). */
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="zdjecia-ciemne"]:has(meta[name="color-scheme"][content="dark"]) img[data-kafelek] {
        transition: filter .15s ease-out;
    }
    html[data-efekty~="zdjecia-ciemne"]:has(meta[name="color-scheme"][content="dark"]) .galeria-zdjecie img {
        transition: transform .3s ease-out, filter .15s ease-out;
    }
}
@media (prefers-reduced-motion: no-preference) and (prefers-color-scheme: dark) {
    html[data-efekty~="zdjecia-ciemne"]:has(meta[name="color-scheme"][content="light dark"]) img[data-kafelek] {
        transition: filter .15s ease-out;
    }
    html[data-efekty~="zdjecia-ciemne"]:has(meta[name="color-scheme"][content="light dark"]) .galeria-zdjecie img {
        transition: transform .3s ease-out, filter .15s ease-out;
    }
}

/* dotyk-wcisniecie (nr 20; właściciel 28.10.2026) - na telefonie i tablecie dotknięty kafelek galerii, nazwa wzoru
   (cały kafelek wzoru), zakładka, pozycja menu i nazwa grupy menu, kapsułka „Wróć” i liczba-odnośnik w tabeli ciemnieją
   w chwili dotknięcia o ton i dostają granatową obwódkę - widać, że stuknięcie trafiło, zanim zacznie się wczytywać
   następna strona. Przyciski .btn pominięte - już się wciskają (app.css). Otwarte (.aktywna) bez zmian.
   Ton to przygaszony granat wylany cieniem do środka (inset): leży nad tłem elementu, pod napisem - działa tak samo na
   jednolitym tle, na tle z gradientem („Wróć”) i na tle, które już jest jasnym granatem (liczba-odnośnik, zakładka pod
   palcem); kafelek wzoru dostaje ten sam odcień w tle (niżej, dlaczego); w ciemnym wyglądzie --toz-fokus jest jasny,
   więc element jaśnieje o ton. Obwódka: ramka, gdzie element ją ma (zakładka, „Wróć”, wzór, kafelek galerii), a gdzie
   nie ma - cienka kreska w tym samym cieniu, bez zmiany rozmiaru.
   Kafelek galerii ma u góry zdjęcie (overflow hidden) - ton dostaje jego opis, nie zdjęcie. Ramka kafelka galerii i wzoru
   waży więcej niż górna linia światła z krawedz-swiatla - wciśnięty ma obwódkę dookoła, także u góry.
   Tylko dotyk bez myszy (hover: none, pointer: coarse) i tylko w bloku ruchu: barwa wchodzi po 70 ms, a przy przewijaniu
   palcem przeglądarka zdejmuje :active wcześniej - nic nie mruga. Bez ruchu w systemie nie ma zwłoki, więc nie ma
   i efektu (barwa mrugałaby przy każdym przewinięciu). Safari na iPhonie zapala :active dopiero, gdy strona słucha
   dotknięcia - pusty nasłuch dokłada efekty-nowoczesne.js (ten sam kod). Komputer bez zmian. Pod @supports z color-mix():
   bez niego cień kafelka spadłby przy dotknięciu do „none”. */
@media (prefers-reduced-motion: no-preference) and (hover: none) and (pointer: coarse) {
    @supports (color: color-mix(in srgb, transparent 50%, transparent)) {
        html[data-efekty~="dotyk-wcisniecie"] .zakladka:not(.aktywna):active,
        html[data-efekty~="dotyk-wcisniecie"] .breadcrumb a:active {
            border-color: var(--toz-fokus);
            box-shadow: inset 0 0 0 999px color-mix(in srgb, var(--toz-fokus) 12%, transparent);
            transition: border-color .1s ease 70ms, box-shadow .1s ease 70ms;
        }
        /* Kafelek wzoru (przegląd części C, 28.10.2026): ton w tle, nie w cieniu. Pobranie wzoru zostawia stronę, a na
           dotyku kafelek zostaje wtedy „pod myszą” - z cieniem zewnętrznym (.wzor:hover w app.css, karty-glebia). Cienia
           zewnętrznego przeglądarka nie zamienia płynnie na wewnętrzny: ton wchodziłby od razu, bez zwłoki 70 ms, i mrugał
           przy przewijaniu palcem zaczętym na tej samej nazwie. Tło kafelka jest jednolite (var(--toz-plyta)), więc
           domieszka w tle daje ten sam odcień, a cień zostaje, jaki był. Osobna reguła także dlatego, że przeglądarka bez
           :has() odrzuca całą listę selektorów - zakładki i „Wróć” zostają wtedy przy efekcie. */
        html[data-efekty~="dotyk-wcisniecie"] .wzor:has(a.wzor-nazwa:active) {
            border-color: var(--toz-fokus);
            background-color: color-mix(in srgb, var(--toz-fokus) 12%, var(--toz-plyta));
            transition: border-color .1s ease 70ms, background-color .1s ease 70ms;
        }
        html[data-efekty~="dotyk-wcisniecie"] .nav a:not(.aktywna):active,
        html[data-efekty~="dotyk-wcisniecie"] .nav-grupa:not(.aktywna) > summary:active,
        html[data-efekty~="dotyk-wcisniecie"] a.licznik:active {
            box-shadow: inset 0 0 0 1px var(--toz-fokus), inset 0 0 0 999px color-mix(in srgb, var(--toz-fokus) 12%, transparent);
            transition: box-shadow .1s ease 70ms;
        }
        html[data-efekty~="dotyk-wcisniecie"] .galeria-adopcji > li > .galeria-kafelek:active {
            border-color: var(--toz-fokus);
            transition: border-color .1s ease 70ms;
        }
        html[data-efekty~="dotyk-wcisniecie"] .galeria-adopcji > li > .galeria-kafelek:active .galeria-opis {
            box-shadow: inset 0 0 0 999px color-mix(in srgb, var(--toz-fokus) 12%, transparent);
            transition: box-shadow .1s ease 70ms;
        }
    }
}

/* === etap 3, część A === */

/* wymagane-ptaszek (nr 21; właściciel 28.10.2026: efekty z wyłącznikami) - czerwona gwiazdka pola obowiązkowego
   (.wymagane::after w app.css, " *") zamienia się w granatowy ptaszek, gdy pole ma wartość: klasę np-wypelnione daje
   efekty-nowoczesne.js (pole do napisu jak oznaczWymagane() w blad-w-polu.js; pole z błędem od serwera zostaje
   z gwiazdką, dopóki ktoś go nie zmieni). Ptaszek stoi w tym samym pseudoelemencie co gwiazdka, z tą samą spacją przed
   sobą - jeden znak w miejscu jednego znaku. inline-block, bo przekształcenie przy wskoku nie działa na elemencie
   w linii; white-space: pre, bo w inline-block spacja na początku by zniknęła. Część formularza z kompletem
   (fieldset.sekcja.np-komplet) ma ten sam ptaszek za tytułem: ::after tytułu jest wolny (::before to kreska z app.css),
   a tytuł, który sam ma gwiazdkę („Kogo dotyczy”, „Powód”), pokazuje swój. Pusty tekst zastępczy - czytnik ptaszka nie
   czyta, „wymagane” podaje mu aria-required pola. Barwa ze zmiennej -tekst: arkusz efektów nie przechodzi przez
   generator ciemnego wyglądu, a --toz-granat zostaje tam ciemny. Całość w @supports ze składnią content z „/” -
   przeglądarka bez niej zostaje przy czerwonej gwiazdce (bez @supports dostałaby granatową gwiazdkę). */
@supports (content: "" / "") {
    html[data-efekty~="wymagane-ptaszek"] .wymagane.np-wypelnione::after,
    html[data-efekty~="wymagane-ptaszek"] fieldset.sekcja.np-komplet > legend:not(.wymagane)::after {
        content: " ✓" / "";
        display: inline-block;
        white-space: pre;
        color: var(--toz-granat-tekst, var(--toz-granat));
        font-weight: 700;
    }
}
/* Przy zmianie ręką (klasa -teraz na 0,3 s ze skryptu, tylko bez ograniczenia ruchu) ptaszek raz wskakuje z 40% wielkości.
   Animuje się sam pseudoelement napisu, nigdy pole - pola mają w app.css swoje animacje (drgnięcie błędu, błysk pola
   poprawionego). Bez fill-mode: po wskoku zostaje wygląd z reguły wyżej. */
@media (prefers-reduced-motion: no-preference) {
    @supports (content: "" / "") {
        html[data-efekty~="wymagane-ptaszek"] .wymagane.np-wypelnione.np-wypelnione-teraz::after,
        html[data-efekty~="wymagane-ptaszek"] fieldset.sekcja.np-komplet.np-komplet-teraz > legend:not(.wymagane)::after {
            animation: np-ptaszek .2s ease-out;
        }
    }
}
@keyframes np-ptaszek {
    from { transform: scale(.4); }
}

/* pole-zmienione (nr 22; właściciel 28.10.2026) - pole karty już zapisanej, w którym zmieniono wartość od otwarcia
   strony (klasa np-zmienione z efekty-nowoczesne.js; nowy wpis bez kresek), ma po lewej, wewnątrz ramki, kreskę 3 px:
   przed „Zapisz zmiany” widać, co zostało poprawione. Cień do środka w lewym wewnętrznym marginesie pola (12 px) - tekst
   zaczyna się dalej, kwoty stoją po drugiej stronie; pierścień fokusu to outline (app.css), a kreska pod polem przy
   pisaniu to warstwa tła - nic się nie gryzie. Kreska w zmiennej --np-cien-zmienione: email-od-razu (etap 2) i
   kontrolki-marki (etap 4) dokładają ją do swojego cienia w jednej deklaracji. BEZ animation na polu - reguła z animacją
   podmieniłaby animation-name pola (błysk pola poprawionego skryptem, drgnięcie pola z błędem); kreska i tak wchodzi
   płynnie przy pisaniu (przejście box-shadow pola w fokusie z app.css), w liście wyboru od razu.
   Barwa: kreska niesie sens („zmienione”), więc co najmniej 3:1 do tła pola - czyste złoto ma na bieli ok. 2:1. Złoto
   z domieszką barwy napisu (70/30): w jasnym ok. 3,3:1, w ciemnym jaśnieje razem z napisem (liczy unit-efekty-e3a).
   Domieszka pod @supports z color-mix() - bez niego zmienna byłaby nieważna przy wyliczaniu i zgasiłaby też cień
   email-od-razu, który ją dokłada; wtedy zostaje czyste złoto. */
html[data-efekty~="pole-zmienione"] .form-control.np-zmienione {
    --np-cien-zmienione: inset 3px 0 0 var(--toz-zloto);
    box-shadow: var(--np-cien-zmienione);
}
@supports (color: color-mix(in srgb, transparent 50%, transparent)) {
    html[data-efekty~="pole-zmienione"] .form-control.np-zmienione {
        --np-cien-zmienione: inset 3px 0 0 color-mix(in srgb, var(--toz-zloto) 70%, var(--toz-text));
    }
}

/* blad-poprawiany (nr 23; właściciel 28.10.2026) - po odrzuconym zapisie pole z błędem (.form-control-blad,
   aria-invalid z field_describe()), które ktoś zaczął poprawiać (klasa np-blad-poprawiany ze skryptu: wartość inna niż
   odrzucona), zmienia czerwoną ramkę na złotą („czeka na zapis”), a czerwonawe tło na zwykłe tło pola; komunikat pod
   nim (p.pole-blad, np-pole-blad-poprawiany) szarzeje, ale zostaje do przeczytania. Zmienia się tylko barwa ramki, tła
   i napisu - nic nie dochodzi; drgnięcie przy wczytaniu (toz-drgnienie) zostaje, bo animacji nie ruszamy. Samo
   background-color, nie skrót: skrót zdjąłby strzałkę listy wyboru i kreskę pod polem z app.css. Tło płyty, nie tło
   uwagi - pole nie myli się z „powtórką” (złota ramka i tło uwagi). Ramka to granica pola, więc jak kreska wyżej: złoto
   z domieszką barwy napisu (co najmniej 3:1; bez color-mix() czyste złoto). W fokusie app.css daje polu z błędem
   czerwony obrys - złota ramka w czerwonym obrysie mówiłaby dwie rzeczy naraz, więc obrys też złoty (pod @supports:
   wartość z var() w color-mix() odpadłaby dopiero przy wyliczaniu i obrys wziąłby barwę napisu). Błąd grupy
   przełączników (bez ramki) - tylko przygaszony komunikat. */
html[data-efekty~="blad-poprawiany"] .form-control-blad.np-blad-poprawiany {
    border-color: var(--toz-zloto);
    background-color: var(--toz-plyta);
}
html[data-efekty~="blad-poprawiany"] .pole-blad.np-pole-blad-poprawiany {
    color: var(--toz-muted);
}
@supports (color: color-mix(in srgb, transparent 50%, transparent)) {
    html[data-efekty~="blad-poprawiany"] .form-control-blad.np-blad-poprawiany {
        border-color: color-mix(in srgb, var(--toz-zloto) 70%, var(--toz-text));
    }
    html[data-efekty~="blad-poprawiany"] .form-control-blad.np-blad-poprawiany:focus {
        outline-color: color-mix(in srgb, var(--toz-zloto) 45%, transparent);
    }
}
/* Przejście z czerwieni w złoto w 0,3 s. Reguła z przejściem podmienia całą listę przejść pola, więc to, czego efekt nie
   przejmuje, stoi tu powtórzone z app.css (unit-efekty-e3a porównuje): przejście cienia z „Łagodnych przejść kolorów”
   (bez niego kreska zmienionego pola w poprawianej liście wyboru wskakiwałaby bez przejścia; przegląd części A,
   28.10.2026), a w polu do pisania w fokusie - lista z „Miejsce pisania świeci”. Powrót do odrzuconej wartości -
   czerwień wraca w tempie app.css. */
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="blad-poprawiany"] .form-control-blad.np-blad-poprawiany {
        transition: border-color .3s ease-out, background-color .3s ease-out, color .3s ease-out, box-shadow .12s ease;
    }
    html[data-efekty~="blad-poprawiany"] .form-control-blad.np-blad-poprawiany:where(input:not([type="file"]):not([type="checkbox"]):not([type="radio"]), textarea):focus {
        transition: border-color .3s ease-out, background-color .3s ease-out, color .3s ease-out, box-shadow .12s ease,
            background-size .3s cubic-bezier(.2, .8, .2, 1), outline-color .25s ease-out, outline-offset .25s ease-out;
    }
    html[data-efekty~="blad-poprawiany"] .pole-blad.np-pole-blad-poprawiany {
        transition: color .3s ease-out;
    }
}

/* opis-miejsce (nr 24; właściciel 28.10.2026) - w długim polu opisu z limitem znaków od zapełnienia 80% w wierszu nazwy
   pola, po prawej, stoi „Zostało 312 znaków” z kółkiem napełnianym złotem (span.np-opis-miejsce z efekty-nowoczesne.js;
   ukryty atrybutem hidden poniżej 80%). Etykieta (.label.np-z-miejscem) od wczytania ma zarezerwowane miejsce z prawej
   i jest punktem odniesienia liczby - liczba stoi nad polem, w wierszu nazwy, nie w polu i nie na tekście, a jej pojawienie
   się niczego nie przesuwa. Wysokość wiersza liczby = wysokość wiersza nazwy (line-height 1,5 nazwy przeliczone na
   mniejsze pismo), więc stoi w pierwszej linijce nazwy. Barwa przygaszona; przy ostatnich 50 znakach barwa ostrzeżenia
   (nie czerwień - to nie błąd). Liczba nie łapie kliknięć (klik w nazwę dalej stawia kursor w polu). Bez ruchu. */
html[data-efekty~="opis-miejsce"] .label.np-z-miejscem {
    position: relative;
    padding-right: 11em;
}
html[data-efekty~="opis-miejsce"] .np-opis-miejsce {
    position: absolute;
    top: 0;
    right: 0;
    display: inline-flex;
    align-items: center;
    gap: .35em;
    font-size: .84em;
    line-height: 1.7857;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--toz-muted);
    pointer-events: none;
}
html[data-efekty~="opis-miejsce"] .np-opis-miejsce.np-opis-malo {
    color: var(--toz-uwaga-tekst, var(--toz-uwaga));
    font-weight: 600;
}
/* Kółko: stożek złota do ułamka zapełnienia (--np-zapelnienie, 0-1, ustawia skrypt na samej liczbie), reszta toru w bladej
   barwie fokusu (--toz-granat w ciemnym wyglądzie zostaje ciemny, tor by zniknął). Tylko ozdoba - pusty tekst zastępczy.
   Pod @supports z conic-gradient() i color-mix(): bez nich zostaje sama liczba. */
@supports (background-image: conic-gradient(transparent 0deg, transparent 0deg)) and (color: color-mix(in srgb, transparent 50%, transparent)) {
    html[data-efekty~="opis-miejsce"] .np-opis-miejsce::before {
        content: '';
        content: '' / '';
        flex: none;
        width: .95em;
        height: .95em;
        border-radius: 50%;
        background-image: conic-gradient(var(--toz-zloto) calc(var(--np-zapelnienie, 0) * 1turn), color-mix(in srgb, var(--toz-fokus) 30%, transparent) 0deg);
    }
}
/* Wąski ekran: tylko liczba z kółkiem - słowa „Zostało” i „znaków” znikają z oczu, ale zostają dla czytnika (jak .sr-only),
   a rezerwa w etykiecie maleje do miejsca na cztery cyfry z kółkiem. */
@media (max-width: 520px) {
    html[data-efekty~="opis-miejsce"] .label.np-z-miejscem {
        padding-right: 4em;
    }
    html[data-efekty~="opis-miejsce"] .np-opis-slowo {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
    }
}

/* === etap 3, część B === */

/* kolumna-pod-kursorem (nr 25; właściciel 28.10.2026: efekty z wyłącznikami) - w liście (tabela w .table-wrap-ewidencja)
   komórka pod myszą zapala w nagłówku nazwę swojej kolumny: wyraźnie głębszy granat tła, ciemniejszy napis i granatowa
   kreska 3 px nad złotą kreską, którą każdy nagłówek ma już dziś (sama grubsza złota prawie by nie odróżniła kolumny).
   Wiersz pod myszą ma kreskę z lewej (app.css), więc razem widać wiersz i kolumnę - jak w arkuszu. Kolumny w danych się
   nie maluje (kolor wiersza to tylko jego stan). Klasę np-kolumna-pod-kursorem stawia skrypt efektów na th o numerze
   kolumny w prawdziwym nagłówku i w jego kopii (.naglowek-kopia z naglowek-tabeli.js - ta sama klasa tabeli) i tylko
   tam, więc selektor nie musi wymieniać list. Reguła podmienia komplet z app.css („Nagłówek tabeli”: spadek tła i cień
   ze złotą kreską) - background-image i box-shadow, nie skrót background (kolor tła th zostaje pod spodem, spadek jest
   kryjący). Napis w odpowiedniku -tekst (w ciemnym wyglądzie --toz-granat-ciemny zostaje ciemny), odnośnik sortowania
   bierze ten sam: aktywny ma własny granat, który na głębszym tle w ciemnym wyglądzie miałby poniżej 4,5:1 (liczy
   unit-efekty-e3b); strzałki sortowania bez własnych reguł. Obwódka fokusu w kopii (.kopia-fokus) to outline - widać ją
   razem z tym. Pod @supports z color-mix(): bez niego deklaracje odpadłyby dopiero przy wyliczaniu i nagłówek straciłby
   dzisiejszy spadek i złotą kreskę. */
@supports (color: color-mix(in srgb, transparent 50%, transparent)) {
    html[data-efekty~="kolumna-pod-kursorem"] .table thead th.np-kolumna-pod-kursorem {
        background-image: linear-gradient(180deg, color-mix(in srgb, var(--toz-fokus) 14%, var(--toz-plyta)),
            color-mix(in srgb, var(--toz-fokus) 26%, var(--toz-plyta)));
        box-shadow: inset 0 -2px 0 var(--toz-zloto), inset 0 -5px 0 var(--toz-fokus),
            0 2px 3px color-mix(in srgb, var(--toz-granat-ciemny) 6%, transparent);
        color: var(--toz-granat-ciemny-tekst, var(--toz-granat-ciemny));
    }
    html[data-efekty~="kolumna-pod-kursorem"] .table thead th.np-kolumna-pod-kursorem .sort {
        color: inherit;
    }
}

/* filtruj-czeka (nr 26; właściciel 28.10.2026) - w polu filtra wpisano coś nowego, a lista nie jest jeszcze
   przefiltrowana (pole czeka na Enter albo „Filtruj”): przycisk „Filtruj” stoi w złotym pierścieniu, póki filtry
   różnią się od tych, z którymi przyszła lista; po cofnięciu zmian i po wysłaniu formularza pierścień gaśnie. Klasę
   np-filtry-zmienione na formularzu stawia skrypt efektów (pola wysyłane same - od razu po zmianie, po zamknięciu listy,
   przełącznik „pokaż wszystkie” - się nie liczą). Sam pierścień stały, bez animacji: wchodzi przez przejście cienia .btn
   z app.css, a raz pulsuje skryptem (Element.animate) - reguła animation tu miałaby wyższą wagę niż błysk pod myszą
   (toz-blysk) i fala kliknięcia (toz-fala) z app.css i zabierałaby je akurat wtedy, gdy człowiek klika „Filtruj”.
   Pierścień 3 px wokół samego przycisku, w odstępie paska akcji (8-16 px) - nie wchodzi na „Wyczyść” ani na pola. Waga
   wyższa niż cień pod myszą i wciśnięty z app.css - pierścień zostaje. Pod @supports z color-mix(): bez niego przycisk
   straciłby przy wyliczaniu dzisiejszy cień. */
@supports (color: color-mix(in srgb, transparent 50%, transparent)) {
    html[data-efekty~="filtruj-czeka"] form.filters.np-filtry-zmienione .filters-action .btn-primary[type="submit"]:not(:disabled) {
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--toz-zloto) 65%, transparent),
            0 1px 2px color-mix(in srgb, var(--toz-granat-ciemny) 22%, transparent);
    }
}

/* historia-dni (nr 27; właściciel 28.10.2026) - w historii zmian na kartach, w dzienniku zdarzeń i w „Ostatnich
   zdarzeniach” konta pierwszy wpis z każdego kolejnego dnia (lista idzie od najnowszego) ma u góry cienką złotą kreskę,
   a jego data jest pogrubiona: długa historia układa się w dni. To granica dnia, nie pas co drugi wiersz - klasę
   np-nowy-dzien stawia skrypt efektów po porównaniu daty z wierszem wyżej. Kreska to obramowanie w miejscu zwykłej linii
   między wierszami (przy border-collapse szersze wygrywa) - nic na tekście, wiersz bez tła; wysokość wiersza rośnie
   o piksel, szerokość bez zmian. Nieruchome (komórki bez animacji - świeży wpis ma swoją). Deklaracja z color-mix()
   w przeglądarce bez niego odpada przy wyliczaniu do braku kreski - linia jak dziś. */
html[data-efekty~="historia-dni"] .table tbody tr.np-nowy-dzien > td {
    border-top: 2px solid color-mix(in srgb, var(--toz-zloto) 65%, transparent);
}
html[data-efekty~="historia-dni"] .table tbody tr.np-nowy-dzien > td.kol-data {
    font-weight: 600;
}

/* historia-bylo-jest (nr 28; właściciel 28.10.2026) - w kolumnie „Szczegóły” historii zmian dawna wartość jest szara,
   strzałka w ciemniejszym odcieniu złota, a nowa wartość granatowa i pogrubiona: od razu widać, NA CO zmieniono.
   Skrypt efektów dzieli linię z dokładnie jedną strzałką na span.np-bylo, span.np-strzalka i span.np-jest - te same znaki
   w tej samej kolejności, zmienia się tylko barwa i grubość liter. Nowa wartość w odpowiedniku -tekst (arkusz efektów nie
   idzie przez generator ciemnego wyglądu, a --toz-granat-ciemny jest tam tłem). Strzałka niesie sens „zmieniono na”,
   a czyste złoto ma do bieli ok. 2:1 - stąd pół na pół z barwą napisu (co najmniej 3:1, liczy unit-efekty-e3b);
   przeglądarka bez color-mix() daje jej po prostu barwę napisu. Bez ruchu. */
html[data-efekty~="historia-bylo-jest"] .tabela-historii .np-bylo {
    color: var(--toz-muted);
}
html[data-efekty~="historia-bylo-jest"] .tabela-historii .np-strzalka {
    color: color-mix(in srgb, var(--toz-zloto) 55%, currentColor);
    font-weight: 700;
}
html[data-efekty~="historia-bylo-jest"] .tabela-historii .np-jest {
    color: var(--toz-granat-ciemny-tekst, var(--toz-granat-ciemny));
    font-weight: 600;
}

/* Ruch części B: tylko nazwa kolumny zapala się w 0,12 s (gaśnie od razu). th nie ma w app.css przejść ani animacji. */
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="kolumna-pod-kursorem"] .table thead th.np-kolumna-pod-kursorem {
        transition: box-shadow .12s ease-out, color .12s ease-out;
    }
}

/* === etap 3, część C === */

/* na-gore-ustepuje (nr 29; właściciel 28.10.2026: efekty z wyłącznikami) - okrągły przycisk „Na górę” (na-gore.js) stoi
   na stałe w prawym dolnym rogu, więc na końcu listy zasłaniał „Następna”, przyciski działań na zaznaczonych, „Pozycji
   na stronie” albo „Kolumny”. Gdy któryś z nich wchodzi w pas przy dole ekranu (obserwator widoczności w skrypcie
   efektów, bez nasłuchu przewijania), przycisk dostaje klasę np-na-gore-ustepuje i gaśnie: nie widać go, nie łapie
   kliknięć, a kursor klawiatury go omija. Przycisk, na którym kursor klawiatury już stoi, zostaje - nie znika spod ręki.
   Otwarty panel „Kolumny” chowa przycisk już w app.css (T28) - zgodnie. Samo krycie i widoczność: rozmiar i miejsce
   bez zmian, nic się nie przesuwa. */
html[data-efekty~="na-gore-ustepuje"] .na-gore.np-na-gore-ustepuje:not(:focus-visible) {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}
/* Od 1600 px z myszą --toz-margines (clamp(16px, 2.5vw, 40px) w app.css) ma pełne 40 px: przycisk 32 px staje pośrodku
   tego wolnego pasa obok kart (4 px od brzegu okna i 4 px od karty), a nie nad ostatnią kolumną wierszy. 32 px przy
   myszy wystarcza (WCAG 2.5.8 wymaga 24); na dotyku zostaje 46 px. Strzałka mniejsza do pary. Między 1280 a 1600 px pas
   jest węższy niż przycisk - tam przycisk stoi jak dziś (w środku listy może wisieć nad prawą kolumną) i tylko ustępuje
   przyciskom pod listą. */
@media (min-width: 1600px) and (hover: hover) and (pointer: fine) {
    html[data-efekty~="na-gore-ustepuje"] .na-gore {
        width: 32px;
        height: 32px;
        right: calc((var(--toz-margines) - 32px) / 2);
    }
    html[data-efekty~="na-gore-ustepuje"] .na-gore::before {
        width: 9px;
        height: 9px;
    }
}
/* Gaśnie w 0,2 s; widoczność przechodzi razem z kryciem (przy gaśnięciu znika na końcu, przy powrocie od razu). .na-gore
   nie ma przejścia w app.css, a jego animacji wejścia (toz-zjaw) ta reguła nie dotyka. */
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="na-gore-ustepuje"] .na-gore {
        transition: opacity .2s ease-out, visibility .2s;
    }
}

/* okno-kiwa (nr 30; właściciel 28.10.2026: efekty z wyłącznikami) - po kliknięciu w szybę obok okna pytania skrypt
   efektów daje oknu na 0,5 s klasę np-okno-czeka: przycisk z kursorem (zwykle „Nie”, pytanie.js stawia go na wyjściu)
   dostaje złoty pierścień 4 px - widać, że trzeba odpowiedzieć tutaj. Pierścień wchodzi i schodzi przez przejście cienia,
   które .btn ma w app.css (w bloku ruchu); bez ruchu w systemie stoi 0,5 s. Mieści się w odstępie między przyciskami
   (8 px) i w marginesie okna (20 px) - nic na napisach. :focus, nie :focus-visible: kursor stawia na przycisku skrypt
   (pytanie.js przy otwarciu, skrypt efektów po kliknięciu w szybę), a po myszy przeglądarka nie zapala :focus-visible.
   BEZ animation: otwarte okno ma animację wejścia toz-okno (app.css) - reguła z animation podmieniłaby ją, a po zdjęciu
   klasy odtworzyła wejście okna od nowa; kiwnięcie robi Element.animate w skrypcie. W @supports z color-mix(): reguła
   podmienia cień przycisku z app.css i bez color-mix() spadłaby przy wyliczaniu do „none”. */
@supports (color: color-mix(in srgb, transparent 50%, transparent)) {
    html[data-efekty~="okno-kiwa"] .okno-pytania.np-okno-czeka .btn:focus {
        box-shadow: 0 0 0 4px color-mix(in srgb, var(--toz-zloto) 75%, transparent);
    }
}

/* === etap 4, część A === */

/* szukane-slowa (nr 31; właściciel 28.10.2026: efekty z wyłącznikami) - słowa z pól szukania filtrów (pole „Szukaj”
   i inne pola szukania listy, w wartości, z którą przyszła lista) są w widocznych komórkach wyników podświetlone jak
   zakreślaczem: jasnozłote tło i cienka złota kreska pod literami - widać, dlaczego wiersz trafił do wyników. Wpisany
   fragment w liście podpowiedzi adresu i w wyszukiwarce miejsc nad mapą ma samo jasnozłote tło. Zakresy zbiera skrypt
   efektów (zbiory np-szukane i np-podpowiedz); strona się nie zmienia - bez nowych znaczników w tekście, przeglądarka
   maluje podświetlenie POD literami, jak zaznaczenie tekstu: litery zostają w swoim kolorze i miejscu (bez color - barwa
   napisu się nie zmienia), kolor wiersza (stan) zostaje pod spodem, zaznaczenie myszą przykrywa podświetlenie. Kreska
   osobnymi własnościami (skrót z grubością starsze przeglądarki odrzucają w całości). Przeglądarka bez podświetleń
   nazwanych (Firefox 128 ESR, Safari przed 17.2) - nic; bez color-mix() - sama kreska. Bez ruchu.
   Zakreślacz w wynikach w jasnym wyglądzie (przegląd całości, 28.10.2026): nie samo złoto 40%, tylko złoto 45% w barwie
   karty (--toz-plyta), kryjące w 90% - na białej karcie wygląda tak samo, ale na tłach stanów wiersza (zwłaszcza pod myszą)
   samo złoto przyciemniało tło i napis przygaszony pod zakreśleniem schodził do ok. 4:1, czyli czytał się gorzej niż bez
   niego. Jasne złoto rozjaśnia tło pod słowem - najsłabszy napis ma co najmniej 4,5:1 na każdym tle stanu wiersza
   (liczy unit-efekty-e4a). Barwy napisu nie zmienia (czerwień błędu w komórce zostaje czerwienią). */
html[data-efekty~="szukane-slowa"] ::highlight(np-szukane) {
    background-color: color-mix(in srgb, color-mix(in srgb, var(--toz-zloto) 45%, var(--toz-plyta)) 90%, transparent);
    text-decoration-line: underline;
    text-decoration-color: var(--toz-zloto);
    text-decoration-thickness: 2px;
    text-underline-offset: 2px;
}
html[data-efekty~="szukane-slowa"] ::highlight(np-podpowiedz) {
    background-color: color-mix(in srgb, var(--toz-zloto) 40%, transparent);
}
/* W ciemnym wyglądzie zakreślacz w wynikach słabszy (przegląd części A, 28.10.2026): 40% złota pod jasnymi literami
   to średni brąz - odnośnik w komórce (--toz-granat-ciemny-tekst) miał na nim ok. 3,5-4:1, napis przygaszony (--toz-muted)
   ok. 2,5-2,8:1, czyli szukane słowo czytało się gorzej niż bez podświetlenia (ponad 5,8:1). Jasne złoto z jasnego wyglądu
   w barwie ciemnej karty byłoby tu brązem, więc w ciemnym zostaje samo złoto, słabsze: 12% trzyma oba ponad
   4,5:1 także na tłach stanów wiersza (liczy unit-efekty-e4a), a słowo i tak widać po złotej kresce (na ciemnym tle ponad
   5:1). Ciemny wygląd z meta color-scheme (layout.php), jak zdjecia-ciemne: "dark" - na stałe, "light dark" - gdy ciemny
   jest system urządzenia (wtedy działa ciemny.css). Podpowiedzi zostają przy 40%: nazwa pozycji ma pełną barwę napisu. */
html[data-efekty~="szukane-slowa"]:has(meta[name="color-scheme"][content="dark"]) ::highlight(np-szukane) {
    background-color: color-mix(in srgb, var(--toz-zloto) 12%, transparent);
}
@media (prefers-color-scheme: dark) {
    html[data-efekty~="szukane-slowa"]:has(meta[name="color-scheme"][content="light dark"]) ::highlight(np-szukane) {
        background-color: color-mix(in srgb, var(--toz-zloto) 12%, transparent);
    }
}

/* zaznaczenie-rozlewa (nr 32; właściciel 28.10.2026) - jasny granat zaznaczonego wiersza (warstwa obrazka komórek
   z app.css) nie zapala się od razu w całym wierszu, tylko rozlewa się od pola zaznaczenia w prawo; „zaznacz wszystkie”
   zalewa widoczne wiersze falą z góry na dół. Ruch robi skrypt efektów (Element.animate na rozmiarze tej warstwy, raz,
   bez stanu, który zostaje): reguła animation na komórkach podmieniłaby animację powrotu do wiersza i świeżego wpisu
   (toz-wiersz-ostatni z app.css), a po zdjęciu klasy złoty błysk odtworzyłby się drugi raz. Tu tylko stały zaczep bez
   ruchu: warstwa odcienia bez powtarzania. Ma rozmiar całej komórki (auto), więc wygląd się nie zmienia - a skrypt może
   ją rozciągać od lewej. Ten sam odcień co dziś, odznaczenie gaśnie od razu; kreska pola z lewej (cień) bez zmian. */
html[data-efekty~="zaznaczenie-rozlewa"] .table tbody tr:has(> td.kol-zaznacz input:checked) > td {
    background-repeat: no-repeat;
}

/* kolumna-rozblysk (nr 33; właściciel 28.10.2026) - celowo bez reguł w arkuszu: rozbłysk dodanej, pokazanej albo
   przeniesionej kolumny robi skrypt efektów (Element.animate na tle komórek i cieniu nagłówka, bez fill - po 1,4 s
   wraca barwa spod spodu). Reguła animation na komórkach podmieniłaby animację powrotu do wiersza i świeżego wpisu
   z app.css (toz-wiersz-ostatni), a po zdjęciu klasy złoty błysk 2,4 s odtworzyłby się drugi raz. */

/* === etap 4, część B === */

/* legenda-wskazuje (nr 34; właściciel 28.10.2026: efekty z wyłącznikami) - po najechaniu myszą na pozycję legendy reszta
   rysunku przygasa, a wskazana seria, rodzaj zdarzenia albo rodzaj pinezki zostaje w pełnej barwie: na wykresie z kilkoma
   seriami trudno wzrokiem wyłowić jedną. Nic nie dochodzi - zmienia się samo krycie tego, co już jest; legenda, osie,
   podpisy i tabela dla czytnika bez zmian, wartości dalej widać. Na wykresie klasę np-poza-wskazaniem dostają ze skryptu
   efektów całe grupy innych serii (słupek z ozdobami, linia z poświatą i kropkami), a w słupku z części - same części innych
   serii. Wykres z chmurką p. 25 (svg.wykres-wybrany, ruchome.js - już przygasza słupki do 45%) i wykres, który jeszcze nie
   wyrósł (wykres-czeka), nie przygasają drugi raz. */
html[data-efekty~="legenda-wskazuje"] .wykres-svg:not(.wykres-wybrany):not(.wykres-czeka) .np-poza-wskazaniem {
    opacity: .28;
}
/* Kalendarz Terminarza i mapa spraw: wskazany rodzaj stoi w atrybucie KONTENERA (data-np-wskazane), nie w klasie na każdym
   zdarzeniu i każdej pinezce - przy setkach pinezek skrypt zmienia jeden atrybut, a pinezki rysowane od nowa po
   przesunięciu mapy przygasają same. Rodzaje kalendarza jak App\Zarzad\Kalendarz::TYPY, „po terminie” osobno (pilnuje
   unit-efekty-e4b); pinezki jak w legendzie nad mapą (interwencje/mapa.php, mapa-zgloszen.js). */
html[data-efekty~="legenda-wskazuje"] .kalendarz[data-np-wskazane="panstwowe"] .kalendarz-dni .zdarzenie:not(.zdarzenie-panstwowe),
html[data-efekty~="legenda-wskazuje"] .kalendarz[data-np-wskazane="swieto"] .kalendarz-dni .zdarzenie:not(.zdarzenie-swieto),
html[data-efekty~="legenda-wskazuje"] .kalendarz[data-np-wskazane="urodziny"] .kalendarz-dni .zdarzenie:not(.zdarzenie-urodziny),
html[data-efekty~="legenda-wskazuje"] .kalendarz[data-np-wskazane="raport"] .kalendarz-dni .zdarzenie:not(.zdarzenie-raport),
html[data-efekty~="legenda-wskazuje"] .kalendarz[data-np-wskazane="umowa"] .kalendarz-dni .zdarzenie:not(.zdarzenie-umowa),
html[data-efekty~="legenda-wskazuje"] .kalendarz[data-np-wskazane="wpis"] .kalendarz-dni .zdarzenie:not(.zdarzenie-wpis),
html[data-efekty~="legenda-wskazuje"] .kalendarz[data-np-wskazane="stale"] .kalendarz-dni .zdarzenie:not(.zdarzenie-stale),
html[data-efekty~="legenda-wskazuje"] .kalendarz[data-np-wskazane="po"] .kalendarz-dni .zdarzenie:not(.zdarzenie-po),
html[data-efekty~="legenda-wskazuje"] .mapa-zgloszen[data-np-wskazane="w-toku"] .mapa-plotno .pin.pin-przygaszony,
html[data-efekty~="legenda-wskazuje"] .mapa-zgloszen[data-np-wskazane="w-toku"] .mapa-plotno .pin.pin-niebezpieczne,
html[data-efekty~="legenda-wskazuje"] .mapa-zgloszen[data-np-wskazane="przygaszony"] .mapa-plotno .pin:not(.pin-przygaszony),
html[data-efekty~="legenda-wskazuje"] .mapa-zgloszen[data-np-wskazane="niebezpieczne"] .mapa-plotno .pin:not(.pin-niebezpieczne),
html[data-efekty~="legenda-wskazuje"] .mapa-zgloszen[data-np-wskazane="grupa"] .mapa-plotno .pin:not(.pin-grupa) {
    opacity: .3;
}

/* kafelek-swiatlo (nr 35; właściciel 28.10.2026) - obwódka kafelka zdjęcia, pliku i wzoru świeci złotem w miejscu najbliższym
   kursora, a dalej przechodzi w granat i w zwykłą ramkę - jak szkło łapiące światło. Światło TYLKO w obramowaniu 1 px:
   ramka przezroczysta, a pod nią dwie warstwy tła - płyta kafelka w padding-box (zdjęcie, nazwa, przyciski i plakietki
   leżą na niej jak dotąd) i plama światła w border-box, widoczna wyłącznie w pasku ramki. Bez nakładki i bez ::after nad
   zdjęciem. Położenie światła (--np-swiatlo-x/-y) i klasę np-swiatlo-na stawia skrypt efektów - tylko z myszą, bez
   ograniczenia ruchu w systemie, nie w trakcie przeciągania pliku ani przestawiania kafelków; na telefonie zostaje
   dzisiejsza ramka. Zmienne zarejestrowane bez dziedziczenia - zmiana położenia nie przelicza potomków kafelka. Płyta, bo
   każdy z tych kafelków ma tło var(--toz-plyta) (załącznik faktury - bez własnego, na płycie karty). --toz-fokus zamiast
   granatu: w ciemnym wyglądzie granat zostaje ciemny i środek światła by zniknął. Waga wyższa niż ramka pod myszą z app.css
   (.galeria-kafelek:hover, .wzor:hover) - cień spod myszy zostaje, bo efekt go nie dotyka; niższa niż złota ramka zdjęcia
   „na liście” (zdjecie-na-liscie) - wybrane zdjęcie nie zmienia barw pod kursorem. */
@property --np-swiatlo-x {
    syntax: '<length-percentage>';
    inherits: false;
    initial-value: 50%;
}
@property --np-swiatlo-y {
    syntax: '<length-percentage>';
    inherits: false;
    initial-value: 50%;
}
html[data-efekty~="kafelek-swiatlo"] :is(.galeria-kafelek, .materialy > li, .zalaczniki > li, .wzory > .wzor).np-swiatlo-na {
    border-color: transparent;
    background: linear-gradient(var(--toz-plyta), var(--toz-plyta)) padding-box,
        radial-gradient(160px circle at var(--np-swiatlo-x, 50%) var(--np-swiatlo-y, 50%), var(--toz-zloto), var(--toz-fokus) 45%, var(--toz-border) 80%) border-box;
}

/* kwoty-grosze (nr 36; właściciel 28.10.2026) - w sumach liczonych przez system pełne złote stoją wyraźnie, a „,56 zł” jest
   mniejsze i przygaszone: wzrok od razu trafia na wielkość kwoty. Skrypt efektów dzieli napis sumy na dwa span (te same znaki
   w tej samej kolejności) i tylko drugi, span.np-grosze, ma tu wygląd. Zwykłe kwoty w wierszach list bez zmian.
   Barwa: domieszka barwy przygaszonego napisu do barwy sumy, nie przezroczystość - grosze to drobny napis, więc potrzebują
   4,5:1 do tła, a „Razem z pozycji” faktury stoi już przygaszonym napisem (70% barwy z przezroczystym dawało tam ok. 3,2:1;
   liczy unit-efekty-e4b). Suma ujemna (kwota-ujemna) zostaje czerwona, bo baza to currentColor. Grubość 500 tylko tam, gdzie
   suma jest pogrubiona (strong, pole wyliczone) - przy zwykłym napisie 500 byłoby grubsze od złotych. Bez ruchu. */
html[data-efekty~="kwoty-grosze"] .np-grosze {
    font-size: .78em;
    color: color-mix(in srgb, currentColor 65%, var(--toz-muted));
}
html[data-efekty~="kwoty-grosze"] :is(strong, b, .wyliczone) > .np-grosze {
    font-weight: 500;
}

/* karta-stan-kreska (nr 37; właściciel 28.10.2026) - na zapisanej karcie interwencji kreska pod tytułem (dziś granat w złoto)
   bierze barwę stanu „Stan u nas” - tę samą co plakietka przy tytule (p. 37, ruchome.js) i wiersz na liście. Barwę ramki
   plakietki czyta skrypt efektów (w ciemnym wyglądzie już ta z ciemny.css) i stawia na .card-head zmienną --np-stan-barwa
   z klasą np-stan; stan szary i biały zostają przy kresce marki. Zmienia się sam obrazek kreski: background-size,
   background-position i background-repeat z app.css (1 px u dołu nagłówka) zostają, więc i rysowanie kreski od lewej przy
   wejściu (toz-linia, animacja background-size) - bez skrótu background, który zerowałby warstwy. Nic na treści, karta się
   nie rusza. Zmienna zarejestrowana jako barwa, więc przy wyborze innego stanu kreska przechodzi płynnie (w bloku ruchu).
   Pod @supports z color-mix(): reguła podmienia kreskę z app.css i bez niego spadłaby przy wyliczaniu do „none”. */
@property --np-stan-barwa {
    syntax: '<color>';
    inherits: false;
    initial-value: transparent;
}
@supports (color: color-mix(in srgb, transparent 50%, transparent)) {
    html[data-efekty~="karta-stan-kreska"] .card-head.np-stan {
        background-image: linear-gradient(90deg, var(--np-stan-barwa), color-mix(in srgb, var(--np-stan-barwa) 45%, transparent) 60%, transparent);
    }
}

/* Ruch części B: przygasanie w 0,15 s - grupy serii wykresu (części słupka mają już przejście krycia w app.css) i zdarzenia
   kalendarza (ani jedne, ani drugie nie mają przejść w app.css); pinezki mapy bez przejścia (mapy bez ruchu). Kreska karty
   przechodzi w nową barwę w 0,3 s (.card-head nie ma przejść w app.css). */
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="legenda-wskazuje"] .wykres-svg :is(.wykres-stos, .wykres-linia-grupa) {
        transition: opacity .15s ease-out;
    }
    html[data-efekty~="legenda-wskazuje"] .kalendarz .kalendarz-dni .zdarzenie {
        transition: opacity .15s ease-out;
    }
    html[data-efekty~="karta-stan-kreska"] .card-head.np-stan {
        transition: --np-stan-barwa .3s ease-out;
    }
}

/* === etap 4, część C === */

/* blad-w-czesci (nr 38; właściciel 28.10.2026: efekty z wyłącznikami) - po odrzuconym zapisie długiej karty kreska przy
   tytule części formularza („KWOTY”, „ADRES”...), w której jest pole z błędem (aria-invalid z field_describe() albo ze
   skryptu, który sprawdza w trakcie pisania - raport kasowy, pozycje faktury), robi się czerwona: od razu widać, dokąd
   przewinąć. Pole, które człowiek już poprawia (np-blad-poprawiany z blad-poprawiany, etap 3), błędem części nie jest -
   gdy wszystkie pola części są poprawiane albo poprawione, kreska wraca do granatu i złota. Zmienia się tylko barwa
   istniejącej kreski (app.css: „Tytuł sekcji formularza dostaje tę samą kreskę co tytuł strony”): rozmiar, wzrost przy
   wejściu (toz-rosnij) i złota poświata części, w której się pisze (.sekcja:focus-within), zostają; w poświacie kreska też
   jest czerwona (waga bramki wyższa niż .sekcja:focus-within) - błąd ważniejszy. Czerwień w odpowiedniku -tekst:
   w ciemnym wyglądzie --toz-blad zostaje ciemną czerwienią (ok. 2:1 do tła), a kreska niesie sens. Część bez tytułu
   (fieldset z data-spis-sekcja) - tylko kropka w spisie niżej; na telefonie spisu nie ma - zostaje sama kreska. Bez
   ruchu; przeglądarka bez :has() - kreska jak dziś. */
html[data-efekty~="blad-w-czesci"] .sekcja:has([aria-invalid="true"]:not(.np-blad-poprawiany)) > legend::before {
    background: var(--toz-blad-tekst, var(--toz-blad));
}
/* Kropka w spisie części z prawej (ruchome.js, p. 36; od 1440 px): przycisk części z polem z błędem dostaje ze skryptu
   efektów klasę np-spis-z-bledem, a za jego nazwą stoi mała czerwona kropka - na tle samego spisu, w linii z nazwą
   (zawija się razem z nią), nic nad polami. ::after przycisku spisu jest wolny (app.css i ciemny.css go nie używają).
   Pusty tekst zastępczy - czytnik ekranu kropki nie czyta, błąd podaje samo pole. Barwa jak kreska wyżej. */
html[data-efekty~="blad-w-czesci"] .spis-sekcji button.np-spis-z-bledem::after {
    content: '';
    content: '' / '';
    display: inline-block;
    width: 7px;
    height: 7px;
    margin-left: 6px;
    border-radius: 50%;
    background: var(--toz-blad-tekst, var(--toz-blad));
    vertical-align: .1em;
}

/* kontrolki-marki (nr 39; właściciel 28.10.2026) - to, co przeglądarka rysuje po swojemu, dostaje wygląd systemu.
   Przycisk „Wybierz pliki” w polu pliku (12 pól .form-control: faktury, odczyt, interwencje, podopieczni, wzory, umowy,
   papier oddziału, import) wygląda jak zwykły przycisk systemu: zaokrąglony, w spadku z płyty w jasny granat, granatowy
   napis (odpowiednik -tekst - w ciemnym wyglądzie --toz-granat-ciemny zostaje ciemny). Przycisk 32 px w polu 42 px: pole
   pliku dostaje 4 px wewnętrznego marginesu u góry, u dołu i z lewej (zamiast 9 i 12 px) - wysokość pola bez zmian,
   nazwa pliku 12 px za przyciskiem, na swoim miejscu. Pod @supports selector(): przeglądarka bez ::file-selector-button
   zostaje przy dzisiejszym polu (bez mniejszego marginesu wokół przycisku systemu). */
@supports selector(::file-selector-button) {
    html[data-efekty~="kontrolki-marki"] input.form-control[type="file"] {
        padding-top: 4px;
        padding-bottom: 4px;
        padding-left: 4px;
    }
    html[data-efekty~="kontrolki-marki"] input.form-control[type="file"]::file-selector-button {
        min-height: 32px;
        margin: 0 12px 0 0;
        padding: 0 14px;
        border: 1px solid var(--toz-border);
        border-radius: 8px;
        background: linear-gradient(180deg, var(--toz-plyta), var(--toz-granat-jasny));
        color: var(--toz-granat-tekst, var(--toz-granat-ciemny));
        font-family: inherit;
        font-size: .875rem;
        font-weight: 600;
        line-height: 1.2;
        cursor: pointer;
    }
    /* Pole wyłączone (podgląd karty bez prawa zapisu) - przycisk przygaszony, bez łapki kursora i bez zmiany pod myszą. */
    html[data-efekty~="kontrolki-marki"] input.form-control[type="file"]:disabled::file-selector-button {
        color: var(--toz-muted);
        cursor: default;
    }
    /* Ramka przycisku z domieszką granatu jak .btn (#cdd6ee) i ciemniejsza pod myszą - z barwy ramki fokusu, która
       w ciemnym wyglądzie jest jasna (--toz-granat zostaje tam ciemny i ramka by zniknęła). Pod @supports z color-mix():
       bez niego ramka wzięłaby przy wyliczaniu barwę napisu. Pod myszą tylko z myszą (na dotyku :hover zostaje po
       dotknięciu). */
    @supports (color: color-mix(in srgb, transparent 50%, transparent)) {
        html[data-efekty~="kontrolki-marki"] input.form-control[type="file"]::file-selector-button {
            border-color: color-mix(in srgb, var(--toz-fokus-ramka) 25%, var(--toz-border));
        }
        @media (hover: hover) {
            html[data-efekty~="kontrolki-marki"] input.form-control[type="file"]:not(:disabled)::file-selector-button:hover {
                background: linear-gradient(180deg, var(--toz-granat-jasny), color-mix(in srgb, var(--toz-fokus) 14%, var(--toz-granat-jasny)));
                border-color: color-mix(in srgb, var(--toz-fokus-ramka) 55%, var(--toz-border));
            }
        }
    }
}
/* Po wybraniu pliku (klasa np-ma-pliki ze skryptu efektów: zmiana pola, także przeciągnięciem - przeciagnij-pliki.js
   wysyła wtedy change) pole ma granatową ramkę ze złotą kreską u dołu - widać, że plik czeka na zapis. Kreska to cień
   do środka w miejscu dolnej ramki (pole pliku nie ma kreski pisania z app.css ani kreski zmienionego pola), nazwa pliku
   nad nią. Pole z błędem od serwera zostaje czerwone (albo złote z blad-poprawiany). Bez ruchu. */
html[data-efekty~="kontrolki-marki"] input.form-control[type="file"].np-ma-pliki:not(.form-control-blad) {
    border-color: var(--toz-fokus-ramka);
    box-shadow: inset 0 -2px 0 var(--toz-zloto);
}
/* Znaczek kalendarza w polu daty, zegar w polu godziny i krzyżyk „wyczyść” w polu szukania (#q i szukanie nad mapą) -
   granatowe (--toz-fokus: w ciemnym wyglądzie jasny granat). Rysunek to maska barwiona zmienną, wielkość i miejsce
   znaczka zostają systemowe. Pseudoelementy -webkit- zna Chrome, Edge i Safari; Firefox i iPhone (własny wybór daty) -
   bez zmian; gdzie maska na znaczku nie działa, zostaje znaczek systemowy. Reguła app.css chowająca krzyżyk w pustym polu
   (:placeholder-shown, display: none) zostaje - tu nie ma display. Bez obsługi masek wyszedłby granatowy kwadrat - stąd
   @supports. */
@supports ((-webkit-mask-size: contain) or (mask-size: contain)) {
    html[data-efekty~="kontrolki-marki"] input.form-control[type="date"]::-webkit-calendar-picker-indicator,
    html[data-efekty~="kontrolki-marki"] input.form-control[type="datetime-local"]::-webkit-calendar-picker-indicator {
        background: var(--toz-fokus);
        cursor: pointer;
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.6 1.2v2.4M11.4 1.2v2.4' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round'/%3E%3Crect x='1.8' y='2.8' width='12.4' height='11.6' rx='2' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M2 6.3h12' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M4.4 8.6h1.8v1.8H4.4zM7.1 8.6h1.8v1.8H7.1zM9.8 8.6h1.8v1.8H9.8zM4.4 11.2h1.8V13H4.4zM7.1 11.2h1.8V13H7.1z'/%3E%3C/svg%3E") center / contain no-repeat;
        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.6 1.2v2.4M11.4 1.2v2.4' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round'/%3E%3Crect x='1.8' y='2.8' width='12.4' height='11.6' rx='2' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M2 6.3h12' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M4.4 8.6h1.8v1.8H4.4zM7.1 8.6h1.8v1.8H7.1zM9.8 8.6h1.8v1.8H9.8zM4.4 11.2h1.8V13H4.4zM7.1 11.2h1.8V13H7.1z'/%3E%3C/svg%3E") center / contain no-repeat;
    }
    html[data-efekty~="kontrolki-marki"] input.form-control[type="time"]::-webkit-calendar-picker-indicator {
        background: var(--toz-fokus);
        cursor: pointer;
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6.3' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M8 4.3V8l2.6 1.7' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6.3' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M8 4.3V8l2.6 1.7' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
    }
    html[data-efekty~="kontrolki-marki"] input[type="search"]::-webkit-search-cancel-button {
        -webkit-appearance: none;
        appearance: none;
        width: 14px;
        height: 14px;
        margin-left: 6px;
        background: var(--toz-fokus);
        cursor: pointer;
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1zm2.9 4.1a.75.75 0 0 1 0 1.06L9.06 8l1.84 1.84a.75.75 0 1 1-1.06 1.06L8 9.06l-1.84 1.84a.75.75 0 1 1-1.06-1.06L6.94 8 5.1 6.16A.75.75 0 1 1 6.16 5.1L8 6.94l1.84-1.84a.75.75 0 0 1 1.06 0z' fill-rule='evenodd'/%3E%3C/svg%3E") center / contain no-repeat;
        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1zm2.9 4.1a.75.75 0 0 1 0 1.06L9.06 8l1.84 1.84a.75.75 0 1 1-1.06 1.06L8 9.06l-1.84 1.84a.75.75 0 1 1-1.06-1.06L6.94 8 5.1 6.16A.75.75 0 1 1 6.16 5.1L8 6.94l1.84-1.84a.75.75 0 0 1 1.06 0z' fill-rule='evenodd'/%3E%3C/svg%3E") center / contain no-repeat;
    }
}
/* Pola wypełnione przez przeglądarkę z pamięci (zapamiętany e-mail na logowaniu, adres na kartach członków i kont) mają
   jasnogranatowe tło zamiast żółtego czy błękitnego przeglądarki - najbardziej widać to w ciemnym wyglądzie. Tła pola
   z pamięci nie da się podmienić wprost (przeglądarka trzyma je na sztywno), więc kryje je cień do środka na całe pole,
   a barwę napisu daje -webkit-text-fill-color; cień leży pod napisem. DWIE osobne reguły: przeglądarka, która nie zna
   jednej z nazw (:-webkit-autofill albo :autofill), odrzuciłaby całą listę. Waga (input.form-control i pseudoklasa) wyższa
   niż .form-control.np-zmienione z pole-zmienione (etap 3) - tło nie znika w zmienionym polu, a złota kreska zostaje
   przez var(--np-cien-zmienione). Na ekranie logowania tylko barwy - nic nie zdradza. Bez ruchu. */
html[data-efekty~="kontrolki-marki"] input.form-control:-webkit-autofill {
    box-shadow: var(--np-cien-zmienione, 0 0 transparent), inset 0 0 0 100px var(--toz-granat-jasny);
    -webkit-text-fill-color: var(--toz-text);
    caret-color: var(--toz-text);
}
html[data-efekty~="kontrolki-marki"] input.form-control:autofill {
    box-shadow: var(--np-cien-zmienione, 0 0 transparent), inset 0 0 0 100px var(--toz-granat-jasny);
    -webkit-text-fill-color: var(--toz-text);
    caret-color: var(--toz-text);
}
/* Kreska pod polem przy pisaniu (app.css „Miejsce pisania świeci”, od 641 px) to warstwa tła - cień na całe pole ją
   kryje. W polu z pamięci wraca jako cień do środka na początku listy (nad kryjącym), w barwie fokusu, bez rysowania
   od lewej. Tylko tam, gdzie app.css ją rysuje. */
@media (min-width: 641px) {
    html[data-efekty~="kontrolki-marki"] input.form-control:-webkit-autofill:focus {
        box-shadow: inset 0 -2px 0 var(--toz-fokus), var(--np-cien-zmienione, 0 0 transparent), inset 0 0 0 100px var(--toz-granat-jasny);
    }
    html[data-efekty~="kontrolki-marki"] input.form-control:autofill:focus {
        box-shadow: inset 0 -2px 0 var(--toz-fokus), var(--np-cien-zmienione, 0 0 transparent), inset 0 0 0 100px var(--toz-granat-jasny);
    }
}

/* cien-przewijania (nr 40; właściciel 28.10.2026) - listy przewijane w środku mają przy górnej albo dolnej krawędzi
   delikatny cień, gdy w tę stronę jest jeszcze coś do przewinięcia: rozwinięta lista „wybór wielu” w filtrach, lista
   zmiany stanu w wierszu (w-wierszu.js) i podpowiedzi adresu oraz szukania na mapie (ul.mapa-wyniki). Na początku listy
   nie ma cienia u góry, na końcu u dołu - nie trzeba zgadywać, czy to już wszystko (na Macu i telefonie pasek
   przewijania jest zwykle niewidoczny); lista, która się mieści, wygląda jak dziś. Klasyczne cienie przewijania z warstw
   TŁA listy (bez skryptu, bez osi przewijania, działają w każdej przeglądarce): dwie zasłony w barwie płyty jadą z treścią
   (local) i na początku albo końcu listy przykrywają cień, a dwa cienie 12 px stoją przy krawędziach (scroll). Wszystko to
   tło - maluje się pod pozycjami i napisami; pozycja pod myszą ma własne pełne tło i przykrywa cień. Tło listy powtórzone
   tą samą zmienną var(--toz-plyta) (app.css: biel albo płyta; w ciemnym .wybor-wielu-lista ma #1b1e25, płyta #1a1e28).
   Cień zewnętrzny list i ich wejście (toz-rozwin, toz-w-wierszu-lista) zostają z app.css nietknięte - ten efekt nie
   dotyka ani animacji, ani box-shadow. Bez pól opisu (textarea ma w tle kreskę pisania i własne animacje) i bez spisu
   części (leży na tle strony, nie na płycie). Barwa cienia przez light-dark(): w ciemnym --toz-granat-ciemny zostaje
   granatem i na ciemnej płycie byłby niewidoczny, więc tam jasna poświata z barwy napisu. Pod @supports z light-dark():
   deklaracja z var() odpadłaby dopiero przy wyliczaniu i lista zostałaby bez tła (napisy na treści pod nią). Wysoki
   kontrast systemu (forced-colors) - bez efektu: zasłona w barwie płyty mogłaby wtedy leżeć pod napisem w barwie tła.
   Telefon - tak (listy przewija się palcem); bez ruchu - to nie ruch. */
@media (forced-colors: none) {
    @supports (color: light-dark(transparent, transparent)) and (color: color-mix(in srgb, transparent 50%, transparent)) {
        html[data-efekty~="cien-przewijania"] {
            --np-cien-przewijania: light-dark(color-mix(in srgb, var(--toz-granat-ciemny) 22%, transparent), color-mix(in srgb, var(--toz-text) 16%, transparent));
        }
        html[data-efekty~="cien-przewijania"] .wybor-wielu-lista {
            background: linear-gradient(var(--toz-plyta) 30%, transparent) center top / 100% 40px no-repeat local,
                linear-gradient(transparent, var(--toz-plyta) 70%) center bottom / 100% 40px no-repeat local,
                radial-gradient(farthest-side at 50% 0, var(--np-cien-przewijania), transparent) center top / 100% 12px no-repeat scroll,
                radial-gradient(farthest-side at 50% 100%, var(--np-cien-przewijania), transparent) center bottom / 100% 12px no-repeat scroll,
                var(--toz-plyta);
        }
        html[data-efekty~="cien-przewijania"] .w-wierszu-lista {
            background: linear-gradient(var(--toz-plyta) 30%, transparent) center top / 100% 40px no-repeat local,
                linear-gradient(transparent, var(--toz-plyta) 70%) center bottom / 100% 40px no-repeat local,
                radial-gradient(farthest-side at 50% 0, var(--np-cien-przewijania), transparent) center top / 100% 12px no-repeat scroll,
                radial-gradient(farthest-side at 50% 100%, var(--np-cien-przewijania), transparent) center bottom / 100% 12px no-repeat scroll,
                var(--toz-plyta);
        }
        html[data-efekty~="cien-przewijania"] ul.mapa-wyniki {
            background: linear-gradient(var(--toz-plyta) 30%, transparent) center top / 100% 40px no-repeat local,
                linear-gradient(transparent, var(--toz-plyta) 70%) center bottom / 100% 40px no-repeat local,
                radial-gradient(farthest-side at 50% 0, var(--np-cien-przewijania), transparent) center top / 100% 12px no-repeat scroll,
                radial-gradient(farthest-side at 50% 100%, var(--np-cien-przewijania), transparent) center bottom / 100% 12px no-repeat scroll,
                var(--toz-plyta);
        }
    }
}

/* Ruch części C: tylko przycisk w polu pliku płynnie zmienia ramkę i napis pod myszą (0,15 s); spadek tła zmienia się od
   razu (spadku przeglądarka nie przechodzi płynnie). Pseudoelement nie ma w app.css przejść ani animacji. */
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="kontrolki-marki"] input.form-control[type="file"]::file-selector-button {
        transition: border-color .15s ease-out, color .15s ease-out;
    }
}

/* === etap 5, część A === */

/* lista-w-miejscu (nr 41; właściciel 28.10.2026: efekty z wyłącznikami) - przy filtrowaniu, sortowaniu, zmianie widoku
   i przejściu na inną stronę TEJ SAMEJ listy karta z tytułem i filtrami stoi w miejscu, a przenika się sama tabela;
   po „Następna” albo wyższym numerze strony nowa tabela wjeżdża lekko z prawej, po „Poprzednia” z lewej. Dotąd cała
   strona gasła i wjeżdżała od dołu (@view-transition w app.css), razem z filtrami, których przed chwilą się użyło.
   Przejście robi przeglądarka; nazwy dostają elementy TYLKO na czas przejścia: klasę przejscie-ta-lista na <html>
   i data-przejscie-lista na jedynej karcie z tabelą listy stawia przejscie-wiersza.js (pageswap na liście, którą się
   opuszcza, pagereveal na tej samej liście po wczytaniu), a po końcu przejścia (najwyżej 1 s) je zdejmuje. Nazwa na
   karcie na stałe zrobiłaby z niej osobną warstwę i rozwijana lista filtra chowałaby się pod następną kartą.
   Przesuwa się obraz tabeli w warstwie przejścia, nie sama karta ani wiersze - nagłówek tabeli mierzy położenie już po
   przejściu; obraz jest przycięty do okna, więc strona nie ucieka w bok także na telefonie (tam 16 px zamiast 28 px).
   Reszta strony (tło, belka, pozostałe karty) przy tym przejściu stoi - bez ruchu strony z app.css. Pseudoelementy
   przejścia pod bramką i pod klasą: bez niej (lista -> karta, menu, zakładki) przejścia z app.css bez zmian. Wszystko
   w bloku ruchu - bez ruchu w systemie i w przeglądarce bez przejść między stronami lista zmienia się jak dziś. */
@media (prefers-reduced-motion: no-preference) {
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista .karta-filtrow { view-transition-name: np-filtry; }
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista [data-przejscie-lista] { view-transition-name: np-lista; }
    /* Strona bez ruchu: nowa stoi od razu na swoim miejscu, stara tylko gaśnie pod nią (bez wjazdu od dołu z app.css). */
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista::view-transition-old(root) { animation: np-lista-gasnie .12s ease-out both; }
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista::view-transition-new(root) { animation: none; }
    /* Filtry stoją: nowy obraz od razu na swoim miejscu, stary nie przenika. */
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista::view-transition-group(np-filtry),
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista::view-transition-new(np-filtry) { animation: none; }
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista::view-transition-old(np-filtry) { display: none; }
    /* Tabela: stara gaśnie, nowa się pojawia (0,2 s); przy innej stronie listy nowa wjeżdża z kierunku kroku (0,22 s).
       Warstwa tabeli stoi od razu w nowym miejscu, bez wędrówki grupy przejścia (przegląd części A, 28.10.2026): stare
       położenie przeglądarka bierze z ekranu sprzed kliknięcia, a „Następna” i numery stron stoją pod tabelą - po
       przewinięciu długiej listy tabela jechałaby z góry ekranu w dół, przez kartę filtrów (warstwa tabeli leży nad
       nią). Bez wędrówki obie warstwy tabeli stoją pod kartą filtrów, a stara gaśnie w miejscu nowej. */
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista::view-transition-group(np-lista) { animation: none; }
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista::view-transition-old(np-lista) { animation: np-lista-gasnie .2s ease-out both; }
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista::view-transition-new(np-lista) { animation: np-lista-wchodzi .2s ease-out both; }
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista.przejscie-strona-dalej::view-transition-new(np-lista) {
        animation: np-lista-z-prawej .22s cubic-bezier(.2, .8, .2, 1) both;
    }
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista.przejscie-strona-wstecz::view-transition-new(np-lista) {
        animation: np-lista-z-lewej .22s cubic-bezier(.2, .8, .2, 1) both;
    }
}
@media (prefers-reduced-motion: no-preference) and (max-width: 640px) {
    html[data-efekty~="lista-w-miejscu"].przejscie-ta-lista::view-transition-new(np-lista) { --np-lista-krok: 16px; }
}
@keyframes np-lista-gasnie { to { opacity: 0; } }
@keyframes np-lista-wchodzi { from { opacity: 0; } }
@keyframes np-lista-z-prawej { from { opacity: 0; translate: var(--np-lista-krok, 28px) 0; } }
@keyframes np-lista-z-lewej { from { opacity: 0; translate: calc(var(--np-lista-krok, 28px) * -1) 0; } }

/* klik-czeka (nr 42; właściciel 28.10.2026) - kliknięty albo dotknięty wiersz listy, kafelek galerii, pozycja menu, numer
   strony, nagłówek sortowania, zakładka i „Wróć” (klasa np-tu-w-drodze ze skryptu efektów) mają jasnozłote tło, aż
   przyjdzie następna strona, a wiersz także złotą kreskę z lewej, jak wiersz, do którego się wraca. Tylko pod html.w-drodze
   (efekty.js zapala je po 0,16 s czekania) - szybkie przejście niczego nie zapala. Bez ruchu: samo tło (falę wiersza robi
   skrypt przez Element.animate - reguła animation na komórkach podmieniłaby błysk powrotu do wiersza i świeżego wpisu).
   Komórki: background-color, nie background-image - odcień zaznaczenia (app.css) i światło wiersza w zmianie leżą
   w warstwie obrazka, więc zostają widoczne nad złotem, a reguły nie biją się o tę samą własność; złoto przezroczyste,
   więc i kolor stanu wiersza (tło tr) prześwituje. Kreska w obrysie pierwszej komórki - waga wyższa niż kreska wiersza pod
   myszą z app.css. Kafelek galerii: tło jego opisu (zdjęcie zostaje, jak jest). Numer strony i „Wróć” mają w app.css
   kryjący spadek w warstwie obrazka - tło pod nim byłoby niewidoczne, więc tu złoto stoi w tej warstwie zamiast spadku
   (waga wyższa niż spadek przycisku pod myszą - kliknięty przycisk zwykle zostaje pod kursorem). Wszystko to tło pod
   napisami - nic nie rośnie i nic nie leci nad treścią. Pod @supports z color-mix(): bez niego deklaracje odpadłyby przy
   wyliczaniu, a przycisk straciłby swój spadek.
   Barwa złota (przegląd całości, 28.10.2026): nie samo złoto 22%, tylko złoto 30% w barwie karty (--toz-plyta), w połowie
   przezroczyste. Samo złoto przyciemniało w jasnym wyglądzie tło stanu wiersza, a w ciemnym rozjaśniało ciemne - napis
   przygaszony (druga linijka komórki, gmina, oddział w galerii) schodził do ok. 4,3:1 w jasnym i 3,7:1 w ciemnym. Barwa
   karty działa w obie strony sama (w jasnym rozjaśnia, w ciemnym przyciemnia): na każdym tle stanu wiersza, także pod
   myszą, napis przygaszony ma co najmniej 4,5:1 (liczy unit-efekty-e5a), a na białej karcie złoto wygląda jak ok. 15%. */
html[data-efekty~="klik-czeka"].w-drodze .table tbody tr.np-tu-w-drodze > td:first-child {
    box-shadow: inset 4px 0 0 var(--toz-zloto);
}
@supports (color: color-mix(in srgb, transparent 50%, transparent)) {
    html[data-efekty~="klik-czeka"].w-drodze .table tbody tr.np-tu-w-drodze > td,
    html[data-efekty~="klik-czeka"].w-drodze :is(.nav a.nav-link, th a.sort, a.zakladka).np-tu-w-drodze,
    html[data-efekty~="klik-czeka"].w-drodze a.galeria-kafelek.np-tu-w-drodze .galeria-opis {
        background-color: color-mix(in srgb, color-mix(in srgb, var(--toz-zloto) 30%, var(--toz-plyta)) 50%, transparent);
    }
    html[data-efekty~="klik-czeka"].w-drodze .breadcrumb a.np-tu-w-drodze,
    html[data-efekty~="klik-czeka"].w-drodze .pager a.btn.np-tu-w-drodze:not(.btn-primary):not(.btn-danger):not(.btn-link):not(.btn-strona-aktywna) {
        background-image: linear-gradient(color-mix(in srgb, color-mix(in srgb, var(--toz-zloto) 30%, var(--toz-plyta)) 50%, transparent), color-mix(in srgb, color-mix(in srgb, var(--toz-zloto) 30%, var(--toz-plyta)) 50%, transparent));
    }
}

/* okno-z-przycisku (nr 43; właściciel 28.10.2026) - okno pytania (pytanie.js) z klasą np-z-przycisku (skrypt efektów: było
   otwarte przyciskiem albo odnośnikiem, wektor od środka okna do środka przycisku skrócony do 35% w --np-z-x/--np-z-y)
   wychodzi od strony tego przycisku i w 0,22 s staje na środku, lekko rosnąc. Zastępuje wejście z dołu (toz-okno, app.css -
   bez zmian) tylko przy tej klasie; klasa schodzi przy zamknięciu, a okno bez [open] nie ma animacji, więc nic się nie
   odtwarza. Animacja raz, bez fill-mode: po niej okno stoi tam, gdzie zawsze. To samo okno i ta sama szyba za nim; ruch
   własnościami translate i scale - kiwnięcie z okno-kiwa (Element.animate na scale) go nie przerywa. Do 640 px (telefon)
   i bez ruchu w systemie - jak dotąd. */
@media (prefers-reduced-motion: no-preference) and (min-width: 641px) {
    html[data-efekty~="okno-z-przycisku"] .okno-pytania.np-z-przycisku[open] {
        animation: np-okno-z-przycisku .22s cubic-bezier(.2, .8, .2, 1);
    }
}
@keyframes np-okno-z-przycisku {
    from { opacity: 0; translate: var(--np-z-x, 0px) var(--np-z-y, 0px); scale: .85; }
}

/* spis-znacznik (nr 44; właściciel 28.10.2026) - w spisie części długiej karty (ruchome.js, p. 36; od 1440 px) złota kreska
   bieżącej części nie przeskakuje, tylko w 0,28 s zjeżdża albo podjeżdża do nowej i dopasowuje długość do wysokości nazwy.
   Położenie i wysokość przycisku z klasą spis-biezaca mierzy skrypt efektów (--np-spis-y, --np-spis-h na liście, klasa
   np-spis-znacznik). Znacznik to ::before listy (app.css i ciemny.css go nie używają) na szarej linii spisu z lewej
   (ramka 2 px listy) - nie na nazwach części i nie na formularzu, nie łapie kliknięć; złota krawędź bieżącego przycisku
   ustępuje mu miejsca. Punkt odniesienia to sam spis (position: fixed w app.css), a nie lista: przyciski liczą położenie
   od spisu (offsetTop), z którego ruchome.js trzyma bieżącą pozycję w widoku długiego spisu - lista z position: relative
   przesunęłaby ten rachunek o wewnętrzny margines spisu (8 px) i dolna pozycja chowałaby się pod krawędzią. Spis nie ma
   lewego wewnętrznego marginesu, a lista - marginesu (pilnuje unit-efekty-e5a), więc linia stoi przy left: 0; przewija się
   razem z treścią spisu. Ruch przez translate - bez przeliczania układu. Wszystko w bloku ruchu: bez ruchu w systemie
   złota krawędź przycisku przeskakuje jak dziś. Telefon - spisu nie ma. Pod @supports z własnością translate (przegląd
   części A, 28.10.2026): przeglądarka bez niej postawiłaby znacznik na górze spisu, a złota krawędź bieżącej części
   by zniknęła - tam zostaje krawędź przycisku jak dziś. */
@media (prefers-reduced-motion: no-preference) {
    @supports (translate: 0 1px) {
        html[data-efekty~="spis-znacznik"] .spis-sekcji ol.np-spis-znacznik::before {
            content: '';
            content: '' / '';
            position: absolute;
            left: 0;
            top: 0;
            width: 2px;
            height: var(--np-spis-h, 0px);
            translate: 0 var(--np-spis-y, 0px);
            border-radius: 2px;
            background: var(--toz-zloto);
            pointer-events: none;
            transition: translate .28s cubic-bezier(.2, .8, .2, 1), height .28s cubic-bezier(.2, .8, .2, 1);
        }
        html[data-efekty~="spis-znacznik"] .spis-sekcji ol.np-spis-znacznik button.spis-biezaca {
            border-left-color: transparent;
        }
    }
}

/* === etap 5, część B === */

/* kolko-ja (nr 45; właściciel 28.10.2026: efekty z wyłącznikami) - wszędzie, gdzie przy wpisie stoi kółko z inicjałami
   (historia zmian na kartach, dziennik zdarzeń, pliki, „zrobione przez” w Terminarzu, pasek zatwierdzenia raportu),
   kółko osoby zalogowanej ma cienki złoty pierścień z odstępem - własne zmiany widać jednym rzutem oka. Klasę
   kolko-osoby-ja (na końcu class) stawia serwer: App\Auth\PodpisKonta::kolko() porównuje konto kółka z zalogowanym,
   bez zapytań; konto usunięte i kółko z samej nazwy - bez klasy. Sama klasa niczego nie zmienia (app.css jej nie zna).
   Pierścień to cień NA ZEWNĄTRZ kółka: 2 px odstępu w barwie płyty i 1,5 px złota, razem 3,5 px - mieści się w odstępie
   przed nazwiskiem (.osoba-z-kolkiem, gap .4em); cień nie zajmuje miejsca, więc wysokość linijki, litery i nazwisko bez
   zmian. Zastępuje dzisiejszą bladą obwódkę do środka (inset 1px z app.css) - w złotym pierścieniu jest zbędna. Złoto
   na bieli to ok. 2:1, ale pierścień niczego sam nie mówi: kto to, mówi nazwisko obok. Bez ruchu; na wydruku kółek nie
   ma (app.css), a arkusz efektów idzie tylko na ekran. */
html[data-efekty~="kolko-ja"] .kolko-osoby-ja {
    box-shadow: 0 0 0 2px var(--toz-plyta), 0 0 0 3.5px var(--toz-zloto);
}
/* Z lewej pierścień nie ma swojego miejsca: kółko w zdaniu stoi tuż za napisem - „podpięty ... (” w poprzednich
   arkuszach oddziału nawet bez spacji, a spacja przy małym piśmie ma ok. 3-3,5 px. Kółko rysuje się po napisie przed
   nim, więc cień leżałby NA nawiasie (płyta go wymazuje, złoto zamalowuje) - przegląd e5b 28.10.2026: nic nad
   napisami. W zdaniu kółko dostaje z lewej margines równy pierścieniowi, więc pierścień zaczyna się tam, gdzie dziś
   brzeg kółka. W komórce tabeli (kółko na początku, 8 px odstępu komórki) bez marginesu - nazwiska w kolumnie stoją
   równo jak dotąd. */
html[data-efekty~="kolko-ja"] :not(td) > .osoba-z-kolkiem > .kolko-osoby-ja {
    margin-inline-start: 3.5px;
}

/* galeria-gatunek (nr 46; właściciel 28.10.2026) - kafelek galerii do adopcji bez zdjęcia (i zanim zdjęcie dojdzie)
   pokazuje w złocie zarys siedzącego psa albo kota - według gatunku z karty - zamiast tej samej łapy przy wszystkich;
   przy innych gatunkach zostaje łapa. data-gatunek na ramce zdjęcia stawia galeria.php (DoAdopcji::sylwetkaGatunku():
   początek słowa nazwy gatunku ze słownika oddziału, bez wielkości liter); sam atrybut niczego nie zmienia. Podmieniona
   jest wyłącznie maska ozdoby z app.css (.galeria-zdjecie::before) - barwa (var(--toz-zloto)), przezroczystość .55,
   ramka inset 30% oraz położenie i wielkość maski (center / contain, z jej skrótu) zostają, więc sylwetka stoi dokładnie
   tam, gdzie łapa: pod zdjęciem (img z position: relative leży nad ::before), widać ją tylko w pustej ramce; imię i opis
   nietknięte. Sylwetki w kwadratowym viewBox jak łapa: pies z profilu (pysk, ucho, łapy przednie i tylne, ogon w górę),
   kot od przodu (uszy, ogon owinięty z boku, szpara między łapami). Telefon - ta sama jedna nieruchoma ozdoba; bez ruchu;
   na wydruku ::before znika jak dziś. */
html[data-efekty~="galeria-gatunek"] .galeria-zdjecie[data-gatunek="pies"]::before {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath d='M7 12.4C7 11 7.9 10.2 9.4 10.2L12.8 10.1C13.5 6.9 16.1 4.8 19.6 4.8C22.6 4.8 24.6 6.3 25.6 8.6C27 11.6 27.3 15 26.2 17.8C25.6 19.2 24.2 19.3 23.8 17.8C25.4 21 27.6 23.6 30 25.6C35 27 39.4 30.4 41 35C42.6 33.4 43.6 31.4 44 29.4C44.3 28.2 45.7 28.4 45.6 29.8C45.3 33.2 43.8 36.2 41.8 38.2C41.4 41.2 39.8 43.4 37.4 44.4L21.6 44.4C20.2 44.4 20.2 42.3 21.6 42.3L24.6 42.3C25.4 40.4 25.6 39.2 25 38C23 36.8 20.4 36.8 18.6 37.6L18.6 44.4L10.6 44.4C9.2 44.4 9.2 42.3 10.6 42.3L14 42.3L14 28.6C14 25.4 12.8 23.4 12.8 21.2C12.8 19.6 13.4 18.6 13.8 17.6C12.4 16.9 11.1 16.6 9.9 16.4C8.1 16.1 7 14.5 7 12.4Z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath d='M7 12.4C7 11 7.9 10.2 9.4 10.2L12.8 10.1C13.5 6.9 16.1 4.8 19.6 4.8C22.6 4.8 24.6 6.3 25.6 8.6C27 11.6 27.3 15 26.2 17.8C25.6 19.2 24.2 19.3 23.8 17.8C25.4 21 27.6 23.6 30 25.6C35 27 39.4 30.4 41 35C42.6 33.4 43.6 31.4 44 29.4C44.3 28.2 45.7 28.4 45.6 29.8C45.3 33.2 43.8 36.2 41.8 38.2C41.4 41.2 39.8 43.4 37.4 44.4L21.6 44.4C20.2 44.4 20.2 42.3 21.6 42.3L24.6 42.3C25.4 40.4 25.6 39.2 25 38C23 36.8 20.4 36.8 18.6 37.6L18.6 44.4L10.6 44.4C9.2 44.4 9.2 42.3 10.6 42.3L14 42.3L14 28.6C14 25.4 12.8 23.4 12.8 21.2C12.8 19.6 13.4 18.6 13.8 17.6C12.4 16.9 11.1 16.6 9.9 16.4C8.1 16.1 7 14.5 7 12.4Z'/%3E%3C/svg%3E");
}
html[data-efekty~="galeria-gatunek"] .galeria-zdjecie[data-gatunek="kot"]::before {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath fill-rule='evenodd' d='M14.6 3.6L19.8 8Q22 7.3 24.2 8L29.4 3.6L29.8 11.6Q30.6 17 26.6 19.6C31.2 22.2 34.2 30 34.2 37C34.2 41.6 32.2 44.2 28.2 44.2L15.8 44.2C11.8 44.2 9.8 41.6 9.8 37C9.8 30 12.8 22.2 17.4 19.6Q13.4 17 14.2 11.6ZM21.6 44.2L22 34.5L22.4 44.2Z'/%3E%3Cpath d='M31 43.2C38.6 44.2 43.6 40.6 43.6 34C43.6 30.8 41.8 29.2 40 30.2C38.8 30.9 39.3 32.2 40 33.2C40.9 35.8 38 40 31 40.3Z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath fill-rule='evenodd' d='M14.6 3.6L19.8 8Q22 7.3 24.2 8L29.4 3.6L29.8 11.6Q30.6 17 26.6 19.6C31.2 22.2 34.2 30 34.2 37C34.2 41.6 32.2 44.2 28.2 44.2L15.8 44.2C11.8 44.2 9.8 41.6 9.8 37C9.8 30 12.8 22.2 17.4 19.6Q13.4 17 14.2 11.6ZM21.6 44.2L22 34.5L22.4 44.2Z'/%3E%3Cpath d='M31 43.2C38.6 44.2 43.6 40.6 43.6 34C43.6 30.8 41.8 29.2 40 30.2C38.8 30.9 39.3 32.2 40 33.2C40.9 35.8 38 40 31 40.3Z'/%3E%3C/svg%3E");
}

/* galeria-glebia (nr 47; właściciel 28.10.2026) - w galerii do adopcji przy przewijaniu strony zdjęcie w każdym kafelku
   przesuwa się w swojej ramce trochę wolniej niż strona - kafelki wyglądają jak okienka, za którymi siedzi zwierzak.
   Ramka, imię i opis stoją jak dziś. Sam arkusz, sterowany przewijaniem - bez nasłuchu w skrypcie.
   Oś NAZWANA na li galerii, nie view() na samym zdjęciu: ramka .galeria-zdjecie i kafelek .galeria-kafelek mają
   overflow: hidden, czyli są pojemnikami przewijania - view() na img liczyłby widoczność w nieruchomej ramce i zdjęcie
   nigdy by nie drgnęło. li nie ma overflow (ani nikt nad nim aż do strony: html i body mają overflow-x: clip), więc jego
   oś liczy się względem okna, a nazwę widzą potomkowie. Nazwa osi inna niż zmienna --np-glebia z karty-glebia: osie mają
   własne nazwy, ale ten sam napis myliłby przy szukaniu.
   Zdjęcie jest o 12% wyższe od ramki i jedzie od -10% do -2% własnej wysokości, czyli od -11,2% do -2,24% wysokości
   ramki (dół od 100,8% do 109,8%): przez cały czas zakrywa ramkę od góry do dołu, bez pustego paska, a poza ramkę nie
   wychodzi (overflow: hidden) - nie wchodzi na imię, opis ani sąsiednie kafelki. object-fit: cover przycina przy tym
   ok. 11% więcej - z boków oraz z góry i z dołu. Rusza się translate, osobne od transform: przybliżenie pod myszą z app.css
   (transform: scale(1.04)) działa dalej, a przejście zdjęcia w tytuł karty (przejscie-wiersza.js) nazywa ramkę, nie
   obrazek - leci ramka, z tym, co w niej widać. To animacja samego obrazka, nie .card/tr/td - fill both wolno.
   Zdjęcie wczytujące się (zdjecie-czeka; zdjecie-polysk z połyskiem toz-szkielet w kółko w app.css) stoi ze swoim
   ruchem - reguła z animation o wyższej wadze zabrałaby połysk, a powtórzyć go tu nie wolno; głębia dochodzi razem
   z mgiełką, gdy rysunek się pokazuje (wcześniej stoi poza ramką, więc zmiany wysokości nie widać). Mgiełka
   (img.zdjecie-wylania, toz-zdjecie-wylania z app.css, klasę zdejmuje zdjecia-mgielka.js po 0,45 s): osobna reguła
   z obiema animacjami i tymi samymi :not() - inaczej przegrałaby wagą z ogólną; wartości mgiełki co do znaku z app.css
   (unit-efekty-e5b porównuje). Po zdjęciu klasy głębia trwa dalej (animacja o tej samej nazwie nie zaczyna się od
   nowa), a i tak jej postęp to położenie strony.
   Telefon (do 640 px) - bez głębi; bez ruchu w systemie albo w przeglądarce bez osi widoczności - zdjęcia stoją jak
   dziś. W @supports pełne warunki: sama oś widoczności i nazwana oś na przodku. */
@media (prefers-reduced-motion: no-preference) and (min-width: 641px) {
    @supports (animation-timeline: view()) and (view-timeline: --np-galeria-glebia block) {
        html[data-efekty~="galeria-glebia"] .galeria-adopcji > li {
            view-timeline: --np-galeria-glebia block;
        }
        html[data-efekty~="galeria-glebia"] .galeria-zdjecie img:not(.zdjecie-polysk):not(.zdjecie-czeka) {
            height: 112%;
            animation: np-galeria-glebia linear both;
            /* Po skrócie "animation", który zeruje oś i zakres. */
            animation-timeline: --np-galeria-glebia;
            animation-range: cover;
        }
        html[data-efekty~="galeria-glebia"] .galeria-zdjecie img.zdjecie-wylania:not(.zdjecie-polysk):not(.zdjecie-czeka) {
            animation: toz-zdjecie-wylania .3s ease-out, np-galeria-glebia linear both;
            animation-timeline: auto, --np-galeria-glebia;
            animation-range: normal, cover;
        }
    }
}
@keyframes np-galeria-glebia {
    from { translate: 0 -10%; }
    to { translate: 0 -2%; }
}

/* === etap 5, część C === */

/* lista-wyboru (nr 48; właściciel 28.10.2026: efekty z wyłącznikami) - zwykła lista wyboru w formularzu („Sposób
   odebrania”, rodzaj, oddział) po kliknięciu otwiera listę w wyglądzie systemu zamiast szarej listy przeglądarki: białą
   kartę z zaokrągleniem i cieniem jak lista „wybór wielu” w filtrach, pozycja pod myszą w jasnym granacie, przy wybranej
   granatowy ptaszek (ptaszek przeglądarki w barwie pozycji). To ta sama lista, którą przeglądarka pokazuje dziś po
   kliknięciu - zamyka ją wybór, Esc albo kliknięcie obok; nic nie otwiera się samo, a zamyka się od razu (bez wygaszania),
   więc nad formularzem stoi nie dłużej niż dziś. Tylko w przeglądarce z budową listy w stylu strony (appearance:
   base-select - dziś najnowszy Chrome i Edge), tylko z myszą i od 641 px; telefon i dotyk zostają przy liście systemowej
   (wygodniejszej palcem), inne przeglądarki - jak dziś. Wyłącznik przywraca listę systemową.
   Bez list wysyłanych od razu (data-wyslij-po-zmianie: „Pozycji na stronie”, „Kolejność”): lista-ewidencji.js (F05)
   zakłada dawny model klawiatury (strzałka zmienia wartość w polu, wysyłka po Enter albo po wyjściu z pola), a tu wybiera
   się w otwartej liście - filtr mógłby nie przefiltrować się do drugiego Entera. Bez listy jednostki obok liczby
   (.pole-z-jednostka - „Wiek przy przyjęciu”, width: auto w app.css - szerokość tylko od treści): w nowej budowie
   przeglądarka może liczyć szerokość od wybranej pozycji, więc pole rosłoby i malało przy każdym wyborze; pozostałe listy
   mają szerokość z formularza (100%, kolumna siatki, flex). Bez list
   wielokrotnych i z size (nie mają rozwijania).
   Bez list w rozwinięciu z „Anuluj” (details z [data-zwin] - „Dodaj wzór”, pole „Dla kogo”; przegląd części C,
   28.10.2026): lista w stylu strony leży w samej stronie, więc Escape, którym człowiek zamyka otwartą listę, dochodzi
   do nasłuchów strony (lista przeglądarki zabiera klawisz dla siebie). zwin.js czyta Escape w takim rozwinięciu jak
   „Anuluj” - zwinąłby je i wyczyścił formularz: wybrany plik i wpisany opis. Tam zostaje lista systemowa.
   Budowa pola zmienia się z budową listy, więc wysokość i odstępy trzymają .form-control (42 px w formularzach, mniej
   w zwartych filtrach i panelach - z app.css, ta reguła ich nie rusza): napis i strzałka w jednym rzędzie (flex, środek),
   napis w jednej linijce, a długi napis nie wypycha strzałki poza pole (overflow: hidden - lista leży w warstwie
   wierzchniej, nie przycina się); szerokość własna pola jak dziś, od najdłuższej pozycji, nie od wybranej
   (field-sizing: fixed) - kolumna z listą w wierszach raportu kasowego nie zmienia szerokości przy wyborze. Strzałka z tła (app.css, w ciemnym ciemny.css) znika - zostaje jedna, rysowana przez
   przeglądarkę na swoim miejscu (::picker-icon), ta sama co w polu „wybór wielu” (maska z rysunkiem z app.css, barwa
   przygaszonego napisu, 12 px od prawej) i odwraca się, gdy lista jest otwarta. Ramka, tło, błąd, wyróżnienie filtra
   i kreska zmienionego pola - z app.css i innych efektów, bez zmian. Barwy listy ze zmiennych (ciemny wygląd sam); pole
   wyłączone się nie otwiera, a pozycja wyłączona pod myszą się nie zapala. Listy z grupami, długie (do 18rem, dalej
   przewijane w środku, jak „wybór wielu”) i podmieniane przez skrypty (szukajka.js, podpowiedzi-oddzialu.js,
   slowniki-oddzialu.js) - to dalej zwykłe <option>. Kolory w color-mix() bez osobnego @supports: każda przeglądarka
   z base-select zna color-mix(). */
@supports (appearance: base-select) {
    @media (pointer: fine) and (min-width: 641px) {
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select),
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select)::picker(select) {
            appearance: base-select;
        }
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select) {
            display: flex;
            align-items: center;
            gap: 10px;
            padding-right: 12px;
            background-image: none;
            white-space: nowrap;
            overflow: hidden;
            field-sizing: fixed;
        }
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select)::picker-icon {
            content: '';
            content: '' / '';
            flex: none;
            width: 12px;
            height: 8px;
            margin-left: auto;
            color: var(--toz-muted);
            background-color: currentColor;
            -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
        }
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select):open::picker-icon {
            rotate: 180deg;
        }
        /* Karta listy jak .wybor-wielu-lista z app.css: 4 px od pola, 6 px wewnętrznego marginesu, zaokrąglenie 10 px, cień
           w dół. Pozycje łamią się w linijki (pole wyżej jest w jednej) i lista nie wychodzi poza ekran w bok. Wysokość do
           18rem, ale nigdy wyższa niż okno razem z odstępami 2 x 4 px (przegląd całości, 28.10.2026): przy powiększeniu
           strony 200% na niskim oknie (poniżej ok. 296 px CSS) 18rem nie mieściło się w oknie i ostatnie pozycje leżały
           pod jego krawędzią - przeglądarka przesuwa listę do środka okna (wtedy zachodzi na samo pole), ale nie skraca jej.
           100vh to tu wysokość okna (tylko komputer z myszą, bez paska adresu telefonu). */
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select)::picker(select) {
            box-sizing: border-box;
            margin-block: 4px;
            padding: 6px;
            max-block-size: min(18rem, 100vh - 8px);
            max-inline-size: calc(100vw - 16px);
            border: 1px solid var(--toz-border);
            border-radius: 10px;
            background: var(--toz-plyta);
            color: var(--toz-text);
            white-space: normal;
            box-shadow: 0 12px 28px color-mix(in srgb, var(--toz-granat-ciemny) 22%, transparent);
        }
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select) option {
            border-radius: 6px;
            padding: 6px 8px;
        }
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select) option:not(:disabled):hover,
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select) option:focus-visible {
            background: var(--toz-granat-jasny);
        }
        /* Wybrana pozycja i jej ptaszek w granacie z odpowiednika -tekst: w ciemnym wyglądzie --toz-granat-ciemny zostaje
           ciemny (arkusz efektów nie idzie przez generator ciemnego wyglądu). */
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select) option:checked {
            font-weight: 600;
            color: var(--toz-granat-tekst, var(--toz-granat-ciemny));
        }
        /* Same wartości startowe otwartej listy (4 px wyżej, przezroczysta) - bez przejścia z bloku ruchu nic nie robią,
           więc stoją poza nim. */
        @starting-style {
            html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select)::picker(select):popover-open {
                opacity: 0;
                translate: 0 -4px;
            }
        }
    }
    /* Lista wchodzi miękko w 0,12 s; przejście tylko na otwartej, więc zamknięcie jest natychmiastowe. Warunki złączone
       w jednym zapytaniu z ograniczeniem ruchu na początku (strażnik bloku ruchu). */
    @media (prefers-reduced-motion: no-preference) and (pointer: fine) and (min-width: 641px) {
        html[data-efekty~="lista-wyboru"] select.form-control:not([multiple]):not([size]):not([data-wyslij-po-zmianie]):not(.pole-z-jednostka > select):not(details:has([data-zwin]) select)::picker(select):popover-open {
            transition: opacity .12s, translate .12s;
        }
    }
}

/* pola-wyboru-marki (nr 49; właściciel 28.10.2026: efekty z wyłącznikami) - pola zaznaczania (kwadraciki) i pola jednego
   wyboru (kółka) w całym systemie w barwach systemu, zamiast pola przeglądarki pokolorowanego tylko accent-color z app.css:
   kliknięty kwadracik zalewa się granatem od dołu (warstwa tła rośnie od dolnej krawędzi), a w środku wyłania się ptaszek
   w barwie karty (w jasnym biały, w ciemnym ciemny na jasnym granacie - w obu kontrast z zapasem); kółko dostaje granatową
   kropkę rosnącą ze środka; „część zaznaczonych” (indeterminate, np. nagłówek listy i jego kopia z naglowek-tabeli.js)
   to pozioma kreska na granacie. Zmienia się wygląd samego pola, w jego miejscu: nic nie wychodzi poza kwadracik.
   Granat z --toz-fokus (w ciemnym jasny - --toz-granat zostaje tam ciemny), ramka pustego pola --toz-pole-ramka (ok. 3,3:1
   jak ramka pól tekstowych).
   Ptaszek i kropka na ::before pola (przy appearance: none rysują je Chrome, Safari i Firefox), ptaszek wycięty clip-path.
   BEZ maski na samym polu: maska przycina całe malowanie elementu do jego ramki, także obrys fokusu stojący na zewnątrz -
   zaznaczone pole z kursorem klawiatury straciłoby widoczny fokus (WCAG 2.4.7; J191, F20, J202). Obrys :focus-visible
   z app.css zostaje nietknięty - ten efekt nie ustawia outline, overflow ani clip-path na polu.
   Bez ukrytych pól przełącznika tak/nie (.przelacznik-tak-nie - widać tam tylko etykiety). Rozmiar i odstęp w :where() -
   waga zero: dzisiejsze rozmiary i odstępy z app.css (16-20 px w „wybór wielu”, 22 px w kolumnie zaznaczania na dotyku,
   margin-top w .choice i .uprawnienie) wygrywają; gdzie app.css nic nie mówi - 16 px bez marginesu przeglądarki (pola
   stoją w rzędach z odstępem - gap - więc nic się nie skleja). Pole wyłączone przygaszone (ramka i wypełnienie
   w przygaszonym napisie) i bez zmiany pod myszą; zaznaczone też się pod myszą nie zmienia. Pola są dalej zwykłymi
   polami - klik, klawiatura, czytnik i skrypty bez zmian. Setki pól na liście po 500 wierszy: appearance, warstwa tła
   i clip-path na ::before to tanie malowanie, bez filtrów i cieni.
   W @supports: appearance: none, scale (bez niego kropka kółka stałaby zawsze) i color-mix() (ramka pola wyłączonego). */
@supports (appearance: none) and (scale: 0) and (color: color-mix(in srgb, transparent 50%, transparent)) {
    :where(html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input), html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input)) {
        width: 16px;
        height: 16px;
        margin: 0;
    }
    html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input) {
        -webkit-appearance: none;
        appearance: none;
        display: inline-grid;
        place-content: center;
        box-sizing: border-box;
        border: 1.5px solid var(--toz-pole-ramka);
        border-radius: 4px;
        background: var(--toz-plyta) linear-gradient(var(--toz-fokus), var(--toz-fokus)) 0 100% / 100% 0% no-repeat;
    }
    html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input) {
        -webkit-appearance: none;
        appearance: none;
        display: inline-grid;
        place-content: center;
        box-sizing: border-box;
        border: 1.5px solid var(--toz-pole-ramka);
        border-radius: 50%;
        background: var(--toz-plyta);
    }
    html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input)::before {
        content: '';
        width: .62em;
        height: .62em;
        background: var(--toz-plyta);
        clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0, 43% 62%);
        scale: 0;
    }
    html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input)::before {
        content: '';
        width: .5em;
        height: .5em;
        border-radius: 50%;
        background: var(--toz-fokus);
        scale: 0;
    }
    html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input):checked,
    html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input):indeterminate {
        border-color: var(--toz-fokus);
        background-size: 100% 100%;
    }
    html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input):checked {
        border-color: var(--toz-fokus);
    }
    html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input):checked::before,
    html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input):indeterminate::before,
    html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input):checked::before {
        scale: 1;
    }
    /* „Część zaznaczonych” - kreska zamiast ptaszka (także gdy pole jest przy tym zaznaczone, jak w przeglądarce). */
    html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input):indeterminate::before {
        clip-path: inset(38% 0 round 1px);
    }
    /* Pole wyłączone: ramka blada (jak pole przeglądarki), zaznaczone - wypełnienie i kropka w przygaszonym napisie. */
    html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input):disabled,
    html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input):disabled {
        border-color: color-mix(in srgb, var(--toz-pole-ramka) 55%, var(--toz-plyta));
    }
    html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input):disabled:is(:checked, :indeterminate) {
        border-color: var(--toz-muted);
        background-image: linear-gradient(var(--toz-muted), var(--toz-muted));
    }
    html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input):disabled:checked {
        border-color: var(--toz-muted);
    }
    html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input):disabled::before {
        background: var(--toz-muted);
    }
    /* Puste, włączone pole pod myszą - ramka w granacie: widać, że się je klika (tylko z myszą; zaznaczone i wyłączone
       pod myszą się nie zmieniają). */
    @media (hover: hover) {
        html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input):not(:disabled):not(:checked):not(:indeterminate):hover,
        html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input):not(:disabled):not(:checked):hover {
            border-color: var(--toz-fokus);
        }
    }
    /* Wysoki kontrast systemu: barwy i tła wymienia system, więc wypełnienie i ptaszek mogłyby zniknąć - wraca pole
       przeglądarki. */
    @media (forced-colors: active) {
        html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input),
        html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input) {
            -webkit-appearance: auto;
            appearance: auto;
        }
        html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input)::before,
        html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input)::before {
            display: none;
        }
    }
}
/* Zalanie i ptaszek w 0,15 s - przejście rusza przy zmianie stanu (klik, klawisz, „zaznacz wszystkie”), nie przy wczytaniu:
   pola zaznaczone od serwera stoją bez ruchu. BEZ animation: pole w przełączniku „wskakuje” animacją z app.css
   (toz-wskok) - reguła z animation zabrałaby ją. Pola nie mają w app.css przejść. */
@media (prefers-reduced-motion: no-preference) {
    @supports (appearance: none) and (scale: 0) and (color: color-mix(in srgb, transparent 50%, transparent)) {
        html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input),
        html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input) {
            transition: background-size .15s ease-out, border-color .15s ease-out;
        }
        html[data-efekty~="pola-wyboru-marki"] input[type="checkbox"]:not(.przelacznik-tak-nie input)::before,
        html[data-efekty~="pola-wyboru-marki"] input[type="radio"]:not(.przelacznik-tak-nie input)::before {
            transition: scale .15s ease-out;
        }
    }
}

/* szklo-na-tle (nr 50; właściciel 28.10.2026: efekty z wyłącznikami) - nieotwarte zakładki kategorii pism (Treści pism,
   sciganie/lista.php) i górna kapsułka „Wróć do listy” (odnosnik_powrotu() w helpers.php, miejsce 'gora') stają się
   matowym szkłem: prześwituje przez nie rozmyta poświata i wzór tła strony. Otwarta zakładka zostaje pełna i biała jak
   część karty - od razu widać, która jest „z przodu” (jej złota kreska, .zakladka-znak, p. 33, zostaje). Pod myszą i przy
   kursorze klawiatury pełne tło z app.css, jak dziś. Kapsułki ze środka i z dołu karty (breadcrumb-srodek,
   breadcrumb-dol) stoją na płycie karty - rozmycie nic tam nie daje, więc bez zmian.
   Szkło to tło samych zakładek i górnej kapsułki: obie leżą na tle strony, nad poświatą, nie nad kartą ani tabelą
   (zakładki stoją przed kartą, a szablony wołają górne odnosnik_powrotu() przed pierwszą kartą - pilnuje unit-efekty-e5c),
   więc pod szkłem jest tylko ozdobne tło, a napisy i liczby leżą na wierzchu. Krycie płyty dobrane tak, żeby napis miał
   co najmniej 4,5:1 w najmocniejszym miejscu każdej poświaty (także łuny po zapisie i nocnych barw ciemnego wyglądu) po
   rozmyciu i nasyceniu - liczy unit-efekty-e5c: zakładki - płyta 58%; kapsułka - spadek z jasnego granatu w płytę
   z odrobiną złota, 70% krycia (czyste złoto 20% przy krawędzi kapsułki dawało w ciemnym wyglądzie ok. 3,5:1 dla
   jasnogranatowego napisu, bo złoto rozjaśnia ciemną płytę). Ramka kapsułki i zakładek - z app.css.
   Elementy są małe i nieprzyklejone (nie jak pasek zapisu z G15), bez rozwijanych list. Od 641 px - na telefonie rząd
   zakładek przewija się w bok, szkło nic by nie dało. Wysoki kontrast systemu - bez szkła. Bez ruchu. Ekran logowania
   nie ma ani zakładek, ani kapsułki. W @supports z backdrop-filter (także z przedrostkiem - Safari) i color-mix() -
   bez nich deklaracja z var() odpadłaby dopiero przy wyliczaniu, a zakładka zostałaby bez tła.
   Kliknięta zakładka i „Wróć” w czasie czekania na stronę (klik-czeka: klasa np-tu-w-drodze pod html.w-drodze) - bez
   szkła, żeby złote tło klik-czeka zostało także po zjechaniu myszą z klikniętego elementu (szkło waży więcej i stoi
   dalej w pliku, więc bez wyjątku przykrywało złoto; przegląd całości, 28.10.2026). Wyjątek z html.w-drodze, nie sama
   klasa: przez pierwsze 0,16 s, zanim zapali się w-drodze, zakładka zostaje szkłem, zamiast mignąć kryjącym tłem z app.css. */
@media (min-width: 641px) and (forced-colors: none) {
    @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) and (color: color-mix(in srgb, transparent 50%, transparent)) {
        html[data-efekty~="szklo-na-tle"] .zakladki > .zakladka:not(.aktywna):not(:hover):not(:focus-visible):not(html.w-drodze .np-tu-w-drodze) {
            background: color-mix(in srgb, var(--toz-plyta) 58%, transparent);
            -webkit-backdrop-filter: blur(10px) saturate(1.4);
            backdrop-filter: blur(10px) saturate(1.4);
        }
        html[data-efekty~="szklo-na-tle"] .breadcrumb:not(.breadcrumb-srodek):not(.breadcrumb-dol) a:not(:hover):not(:focus-visible):not(html.w-drodze .np-tu-w-drodze) {
            background-image: linear-gradient(135deg, color-mix(in srgb, var(--toz-granat-jasny) 70%, transparent),
                color-mix(in srgb, color-mix(in srgb, var(--toz-zloto) 14%, var(--toz-plyta)) 70%, transparent));
            -webkit-backdrop-filter: blur(10px) saturate(1.4);
            backdrop-filter: blur(10px) saturate(1.4);
        }
    }
}
