/* ============================================================================
   06-elementy.css — drobne elementy używane wszędzie
   ----------------------------------------------------------------------------
   Awatary, ikony, listy osób, znaczniki. Rzeczy, które same w sobie nie są
   komponentem, ale pojawiają się w każdym widoku.
   ============================================================================ */
/* --- IKONY -----------------------------------------------------------------
   Ikony to maski CSS na SVG (Lucide) — kolor bierze się z currentColor,
   dzięki czemu ikona dziedziczy kolor tekstu i działa w obu motywach.
   Konkretne maski (.icon-folder itd.) definiuje osobny arkusz ikon. */
.icon { display: inline-block; flex: 0 0 auto; width: 16px; height: 16px; /* Bez tego ikona siada na linii bazowej tekstu i „opada" względem napisu obok — widoczne wszędzie, gdzie ikona stoi w jednej linii z tekstem. */ vertical-align: middle; background-color: currentColor; -webkit-mask-position: center; mask-position: center; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-size: contain; mask-size: contain; }
.icon.mini { width: 13px; height: 13px; }
/* --- AWATARY ---------------------------------------------------------------
   JS ustawia kolor tła zmienną --avatar-bg i wstawia albo inicjały,
   albo <img>. Rozmiar MUSI być tutaj — bez tego zdjęcie wchodzi
   w naturalnej wielkości i rozsadza układ. */
/* NAPRAWA 11.08.2026 — kolor inicjałów DOBIERANY DO TŁA, nie na sztywno biały.
   Tło awatara to kolor DZIAŁU, który użytkownik sam ustawia w kartotece
   Użytkowników (`<input type="color" class="dept-color">`, zapis w bazie),
   więc może być dowolnie jasny. Zmierzone: białe inicjały na dziale w kolorze
   #64748b dawały 3,30:1 — poniżej progu, przy rozmiarze 10 px.
   Żadna stała paleta tego nie naprawi, bo kolor jest DANĄ, nie decyzją
   projektową. Dlatego `kolorNapisuNa()` (public/js/rdzen/dane-projektu.js) liczy luminancję
   tła wzorem WCAG i wybiera biel albo #19212e — ten, który daje wyższy
   kontrast. Wynik trafia tu przez `--avatar-tekst`.
   Wartość zapasowa `--text-invert`: awatary bez ustawionego działu wyglądają
   dokładnie jak dotąd.
   Obrys `--avatar-obrys` (tura 5): w jasnym motywie przezroczysty, w ciemnym cienki
   jasny — ciemnogranatowe koło działu znikało na ciemnym pasku (zostawały same litery). */
.avatar { --avatar-d: 28px; display: inline-grid; place-items: center; flex: 0 0 auto; width: var(--avatar-d); height: var(--avatar-d); border-radius: var(--r-pill); overflow: hidden; background: var(--avatar-bg, var(--accent)); color: var(--avatar-tekst, var(--text-invert)); outline: 1px solid var(--avatar-obrys); outline-offset: -1px; font-size: min(var(--t-xs), calc((var(--avatar-d) - 2 * var(--avatar-ramka, 0px)) * .44)); font-weight: var(--w-bold); line-height: 1; white-space: nowrap; user-select: none; }
.avatar > img { width: 100%; height: 100%; object-fit: cover; }
.avatar.small-avatar { --avatar-d: 24px; }
.avatar.tiny { --avatar-d: 18px; }
/* Ujednolicenie 11.08.2026 — szerokość 40px i wysokość var(--h-row) to TA SAMA
   liczba zapisana dwa razy inaczej; awatar ma być kołem, więc oba wymiary idą
   teraz z jednego źródła i nie rozjadą się przy zmianie tokenu. */
.avatar.large { --avatar-d: var(--h-row); font-size: var(--t-sm); }
/* Nakładające się awatary (zespół w jednym wierszu) */
.avatar-stack { display: flex; }
/* NAPRAWA 11.08.2026 — `-var(--s-2)` to NIEPOPRAWNY CSS. Przegladarka odrzucala
   cala deklaracje przy parsowaniu, wiec awatary zespolu staly obok siebie
   zamiast zachodzic na siebie o 8 px. calc() jest jedyna poprawna forma —
   reszta projektu robi to tak (np. 15-zadania.css:208). */
/* Zakładka 2 px (było 8): sąsiad z białą obwódką zasłaniał końcówkę drugiej litery („AR” → „A|”, „BK” → „B|”). */
.avatar-stack .avatar + .avatar { margin-left: -2px; }
.avatar-stack .avatar { box-shadow: 0 0 0 2px var(--surface); }
/* „+2” za osobami, które nie zmieściły się w stosie (public/js/czat/osoby-i-awatary.js renderAvatarsZReszta) — neutralne kółko. */
.avatar.avatar-reszta { --avatar-bg: var(--surface-3); --avatar-tekst: var(--text); }
/* --- GRUPY AKCJI -----------------------------------------------------------
   Przyciski w wierszu tabeli albo w nagłówku sekcji. */
/* Monolit (linia 261) NIE zawija tych akcji i daje gap 7 px. U nas `flex-wrap: wrap`
   powodowało, że w kolumnie o szerokości `auto` pasek akcji zapadał się do jednego
   przycisku — na Zamówieniach różnica sięgała 319 px. Zawijanie zostaje tylko
   w drzewie tabeli, dokładnie jak w monolicie (linia 1644). */
/* Ujednolicenie 11.08.2026 — gap 7px → --s-2 (8px). Pasek akcji ma w aplikacji
   DWA rytmy: --s-2 (grupa samodzielna, ~20 miejsc) i --s-1 (grupa w ciasnym
   wierszu tabeli, ~15 miejsc). Wartość 7 px była trzecim, ślepym rytmem
   w 4 miejscach (tu, .top-actions, .toolbar, .catalog-col-tools) — różnica
   1 px, ale to ona sprawiała, że sąsiadujące paski nie stały w jednej osi. */
.inline-actions { display: inline-flex; align-items: center; gap: var(--s-2); }
.tree-table .inline-actions { flex-wrap: wrap; gap: var(--s-1); }
.row-actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--s-1); }
/* --- POLE WYSZUKIWANIA -----------------------------------------------------
   Ikona lupy WEWNĄTRZ pola, tekst odsunięty, żeby na nią nie wchodził.

   Opakowanie w markupie nazywa się `.search` (`<div class="search">`), a nie
   `.search-field` — sama `.search-field` prawie nie występuje. Reguła tylko na
   `.search-field` nigdy nie działała: lupa stawała OBOK pola zamiast w środku. */
/* Szerokość pola szukania: bazowo 340 px, wolno mu się zwężać — 1:1 z monolitem
   (`.search-field { flex: 0 1 340px }`, linia 349). Bez tego pole kurczyło się
   do treści (182 px) i szukajka była o połowę węższa niż w v8. */
.search-field { flex: 0 1 340px; }
.search-field .search { flex: none; width: 100%; }
.search-field, .search { position: relative; }
.search-field > .icon, .search > .icon { position: absolute; left: var(--s-2); top: 50%; transform: translateY(-50%); color: var(--text-faint); pointer-events: none; }
/* Powtórzony pancerz `:not()` jest KONIECZNY: baza pola w 03-kontrolki.css to
   `input:not([type="checkbox"]):not([type="radio"])` o wadze (0,2,1). Zwykłe
   `.search > input` ma (0,1,1) i PRZEGRYWA — wcięcie zostawało 12 px, a lupa
   leżała na tekście. Z tym samym pancerzem wagi są równe i decyduje kolejność
   arkuszy (06 ładuje się po 03).

   `width: 100%` jest tu równie konieczne: to POLE ma ramkę i białe tło
   (opakowanie `.search` ma `border: 0`), a bez szerokości bierze domyślną
   z przeglądarki — ~179 px. Kontener miał 340 px (Projekty) albo 420 px
   (kartoteki), więc ramka kończyła się w połowie miejsca, a placeholder ucinał
   się na „…nazwa, kl". Jedna reguła prostuje szukajki we WSZYSTKICH oknach. */
.search-field > input:not([type="checkbox"]):not([type="radio"]), .search > input:not([type="checkbox"]):not([type="radio"]) { width: 100%; padding-left: var(--s-6); }
/* --- DROBIAZGI -------------------------------------------------------------- */
/* Tekst wyglądający na link, ale będący przyciskiem */
.linklike { color: var(--accent-strong); cursor: pointer; }
/* DEC-06: nazwa projektu w wierszu listy też otwiera stronę projektu — podkreślenie jak przy numerze. */
.linklike:hover { text-decoration: underline; }
.clipped-line { display: -webkit-box; max-width: 100%; overflow: hidden; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
/* --- PASEK NARZĘDZI (szukajka, filtry, akcje) — JEDNA reguła na całą apkę ---
   Do tej pory pasek był ostylowany WYŁĄCZNIE w widoku Projektów
   (`.project-main-grid > .toolbar` w arkuszu 10), więc w każdej innej
   kartotece pola i guziki leciały bez wyrównania — stąd bałagan w nagłówkach.
   v8 (monolit 259 + 325): wyrównanie do DOŁU, bo etykieta stoi NAD polem
   i przy `center` pola różnej wysokości rozjeżdżają się w pionie. */
/* JEDEN pasek narzędzi na całą aplikację — Projekty, Klienci, Materiały, Bloki,
   Bloki-Stare, Zamówienia. Zasady:
   1. WYŚCIÓŁKA 12/14 — bez niej pierwsze pole i ostatni guzik dotykały krawędzi
      karty i wyglądały na przycięte (w Projektach było `padding: 0`).
   2. BEZ własnego tła, ramki i promienia — kartą jest RODZIC (`.panel`,
      `.main-grid`). Pasek z własną ramką w środku karty dawał ramkę w ramce
      (tak było w kartotekach).
   3. Wyrównanie do DOŁU, bo etykieta stoi nad polem.
   Rodzic oddziela pasek od tabeli kreską — patrz `.panel > .toolbar` niżej. */
/* Ujednolicenie 11.08.2026 — gap 7px → --s-2, jak w `.inline-actions` wyżej.
   Wyściółka `var(--s-3) 14px` ZOSTAJE: 14 px nie pasuje do żadnego tokenu
   (--s-3=12, --s-4=16 — po 2 px w obie strony), a ta sama para 12/14 stoi
   w stopce (`.pager`, 05:170), w kartach osób (12:110) i w siatce Wyników
   (16:24), więc jest wartością OSI aplikacji, nie przypadkiem. */
.toolbar, .catalog-toolbar { display: flex; flex-wrap: wrap; align-items: end; gap: var(--s-2); margin: 0; padding: var(--s-3) 14px; border: 0; border-radius: 0; background: transparent; box-shadow: none; }
.toolbar .field, .catalog-toolbar .field { min-width: 132px; }
.toolbar .spacer, .catalog-toolbar .spacer { flex: 1; }
/* Napis pod wyłączonym przyciskiem paska (przegląd 26.09: „Przelicz wszystkie projekty" bez prawa) — widoczny bez
   dymka (tablet, telefon); leży w dolnym marginesie paska, więc nie zmienia wyrównania przycisków.
   Margines paska z takim napisem rośnie o wysokość napisu: sam margines (12 px) był niższy niż napis (1 + 14,4 px),
   więc dolna część „Wymaga prawa „Przeliczanie”” wchodziła pod przyklejony nagłówek listy projektów
   (Aneta/David przy 1440 i 1920 — „Wvmaga prawa”). */
.toolbar-przycisk-z-napisem { position: relative; display: inline-flex; }
.toolbar-przycisk-z-napisem > small { position: absolute; top: calc(100% + 1px); left: 0; right: 0; color: var(--text-muted); font-size: var(--t-xs); line-height: 1.2; text-align: center; white-space: nowrap; }
.toolbar:has(.toolbar-przycisk-z-napisem) { padding-bottom: calc(1px + var(--t-xs) * 1.2 + var(--s-2)); }
/* JEDEN ROZMIAR PRZYCISKU W PASKU — w każdym oknie aplikacji.
   Zmierzone przed poprawką: „Nowy projekt" w Projektach 32 px, ten sam typ
   przycisku w kartotekach 40 px, a „Filtry kolumn" obok niego 27 px — trzy
   rozmiary tej samej rzeczy. Pasek narzędzi wyrównuje do dołu
   (`align-items: end`), więc różne wysokości od razu rzucały się w oczy.
   Klasa `mini` jest tu celowo unieważniana: w pasku decyduje pasek, nie
   wariant przycisku. Poza paskiem `mini` działa normalnie (27 px w stopce). */
.toolbar .button, .catalog-toolbar .button,
.toolbar .button.mini, .catalog-toolbar .button.mini { height: var(--h-control); padding: 0 9px; font-size: var(--t-control); }
/* Element rozpychający flexa — wypycha resztę do prawej */
.spacer { flex: 1 1 auto; }
/* Wyciete 11.08.2026 — martwe reguly, zero wystapien w public/js. Szczegoly: AUDYT-CSS-2026-08-11.md B9. */
/* Kwadratowy przycisk ikonowy w wierszu tabeli */
/* Ujednolicenie 11.08.2026 — ten sam token co reszta przycisków-ikon: --h-ikona
   (dziś = --h-control-sm, czyli 27 px; wcześniejszy dopisek „(30)" był nieaktualny
   od chwili, gdy --h-ikona przestało być osobnym rozmiarem — patrz 00-tokens). */
.square-button { width: var(--h-ikona); height: var(--h-ikona); }
/* Pasek ostrzegawczy nad menu (prace serwisowe) */
.service-banner { flex: none; margin: var(--s-1) var(--s-3) var(--s-2); padding: var(--s-2); border-radius: var(--r-sm); background: var(--danger); color: var(--text-invert); font-size: var(--t-xs); font-weight: var(--w-bold); line-height: var(--lh-tight); }
/* --- CHIP UŻYTKOWNIKA W PASKU GÓRNYM -----------------------------------------
   Awatar + imię. Bez ograniczenia wysokości rozpycha cały pasek, bo w środku
   siedzi rozwijana lista kont. */
/* PODWÓJNA RAMKA — nie nadawaj tu wysokości, wyściółki, tła ani promienia.
   Chip to TYLKO opakowanie pozycjonujące dla rozwijanego menu (monolit 1354).
   Wygląd niesie przycisk w środku. Gdy opakowanie dostało własną pigułkę
   32 px, a przycisk w środku ma 34 px i swoją pigułkę, powstawały dwa
   pierścienie jeden w drugim, przy czym wewnętrzny wystawał o 2 px. */
.user-chip { position: relative; display: inline-flex; align-items: center; gap: var(--s-2); min-width: 0; max-width: min(260px, 100%); white-space: nowrap; cursor: pointer; }
.user-chip > strong { font-weight: var(--w-medium); }
/* --- PODGLĄD KONTA (admin ogląda aplikację oczami innej osoby) ---------------
   Lista wszystkich osób MUSI być wyjęta z układu (position: absolute),
   inaczej rozlewa się na cały pasek górny. */
.view-as { position: relative; display: inline-flex; align-items: center; }
/* Jak wyżej: samo opakowanie, bez ramki (monolit ma tu wyłącznie
   `position: relative`). Pigułkę rysuje `.view-as-trigger`. */
/* Rozwijaną listę osób obsługuje `.view-as-menu` niżej — klas `.view-as-list`
   i `.view-as-panel` nie ma w markupie (sprawdzone: node narzedzia-css/martwe-reguly.mjs). */
.view-as-option { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: var(--s-2); width: 100%; padding: var(--s-1) var(--s-2); border-radius: var(--r-sm); text-align: left; cursor: pointer; }
.view-as-option:hover { background: var(--surface-2); }
/* --- AWATAR W CHIPIE UŻYTKOWNIKA -------------------------------------------
   To osobna klasa niż .avatar (inna gałąź szablonu), więc potrzebuje
   własnego wymiaru — inaczej zdjęcie wchodzi w pełnej rozdzielczości. */
/* Kolor inicjałów dobierany do tła — patrz `.avatar` wyżej. */
/* RM5 (v15 b14): awatar konta jak we wzorze — 32 px, inicjały 12/700. */
.user-chip-avatar { --avatar-d: 32px; display: inline-grid; place-items: center; flex: 0 0 auto; width: var(--avatar-d); height: var(--avatar-d); border-radius: var(--r-pill); overflow: hidden; background: var(--avatar-bg, var(--accent)); color: var(--avatar-tekst, var(--text-invert)); outline: 1px solid var(--avatar-obrys); outline-offset: -1px; font-size: min(var(--t-xs), calc((var(--avatar-d) - 2 * var(--avatar-ramka, 0px)) * .44)); font-weight: var(--w-strong); line-height: 1; white-space: nowrap; }
.user-chip-avatar > img { width: 100%; height: 100%; object-fit: cover; }
/* DWA RÓŻNE przyciski, nie jeden wspólny — w v8 tylko „Podgląd konta" jest
   pigułką z ramką (monolit 7459); chip użytkownika jest CAŁKIEM goły:
   `border: 0`, tło przezroczyste, kolor dziedziczony (monolit 1489).
   Sklejenie ich w jedną regułę dokładało ramkę tam, gdzie jej nie ma. */
/* Ujednolicenie 11.08.2026 — WYSOKOŚĆ 34 px → --h-control (32).
   Zmierzone na żywym pasku górnym: stały tam obok siebie TRZY wysokości —
   „Pomoc/Dark/Język" (.ghost-button) 32, dzwonek i koperta (.icon-button) 30,
   a „Podgląd konta" i chip użytkownika 34. Trzy różne wysokości w jednym
   rzędzie to dokładnie to, co sprawia, że pasek wygląda na posklejany
   z kawałków. Wygląd (pigułka z ramką vs goły chip) zostaje bez zmian —
   równa się tylko wysokość.
   Ujednolicenie 11.08.2026 — gap 6px → --s-2: `.user-chip-trigger` obok w tym
   samym pasku ma --s-2, a to ta sama rola (pigułka-wyzwalacz z awatarem). */
.view-as-trigger { display: inline-flex; align-items: center; gap: var(--s-2); height: var(--h-control); padding: 0 var(--s-3); border: 1px solid var(--line-strong); border-radius: var(--r-pill); background: var(--surface); color: var(--text); font-size: var(--t-base); font-weight: var(--w-strong); white-space: nowrap; cursor: pointer; }
.view-as-trigger .icon { width: 15px; height: 15px; }
.view-as-trigger:hover { background: var(--surface-2); }
.user-chip-trigger { display: inline-flex; align-items: center; gap: var(--s-2); min-width: 0; max-width: 100%; min-height: var(--h-control); padding: 0; border: 0; background: transparent; color: inherit; font: inherit; white-space: nowrap; cursor: pointer; }
.user-chip-trigger > strong { font-weight: inherit; }
.user-chip-trigger:hover { color: var(--accent-strong); }
/* Menu użytkownika i podglądu konta — wyjęte z układu, nad treścią */
.user-menu, .view-as-menu { position: absolute; top: calc(100% + var(--s-1)); right: 0; z-index: var(--z-menu-lokalne); min-width: 260px; max-height: calc(60vh / var(--skala-ui)); overflow: auto; padding: var(--s-2); background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--r); box-shadow: var(--cien-2); }
.user-chip, .view-as-chip { position: relative; }
.view-as-hint { padding: var(--s-2); font-size: var(--t-xs); color: var(--text-muted); line-height: var(--lh-tight); }
/* Pasek Podglądu konta: druga linijka w pigułce z ustawieniami funkcji podglądanego
   (funkcja · projekty · ceny · cennik). Pigułka rośnie z 1 do 2 linii, więc przy
   podglądzie wysokość schodzi z twardej na minimalną. Akcentowa ramka = wyraźny
   sygnał „patrzysz cudzymi oczami". */
.view-as-copy { display: inline-flex; flex-direction: column; align-items: flex-start; min-width: 0; line-height: var(--lh-tight); }
.view-as-meta { max-width: 360px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--t-xs); font-weight: var(--w-regular); color: var(--text-muted); }
.view-as-chip.is-impersonating .view-as-trigger { height: auto; min-height: var(--h-control); padding-top: var(--s-1); padding-bottom: var(--s-1); border-color: var(--accent); }
/* --- MINIATURY PLIKÓW (PDF, zdjęcia, rysunki) ----------------------------- (z dawnego 27, K16)
   Jedna kafelkowa miniatura obsługuje trzy przypadki, przełączane klasą:
   • bez klasy  — sama ikona typu pliku (nie ma czego pokazać),
   • .has-image — podgląd graficzny na całej powierzchni, ikona schowana,
   • .has-document — podgląd PDF-a, podpis jako pasek NA podglądzie.
   .thumb-failed = podgląd się nie wczytał: chowamy obraz i wracamy do ikony,
   żeby zamiast pustej ramki było widać, że plik istnieje. */
.pdf-thumb { --kafel-w: 252px; --kafel-h: 202px; display: inline-grid; gap: var(--s-2); width: var(--kafel-w); border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); color: var(--text-muted); text-decoration: none; vertical-align: top; }
.pdf-thumb-main { display: grid; gap: var(--s-1); justify-items: center; min-height: var(--kafel-h); padding: var(--s-3) var(--s-2) var(--s-2); color: inherit; text-align: center; text-decoration: none; }
.pdf-thumb-main.has-image, .pdf-thumb-main.has-document { position: relative; place-items: center; padding: 0; overflow: hidden; }.pdf-thumb-image { width: 100%; height: 100%; background: var(--surface); object-fit: contain; }
.pdf-thumb-icon { display: grid; place-items: center; width: 70px; height: 84px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); color: var(--accent-strong); }
.pdf-thumb-icon .icon { width: var(--s-6); height: var(--s-6); }
.pdf-thumb-label { max-width: 100%; overflow: hidden; font-size: var(--t-xs); font-weight: var(--w-bold); text-overflow: ellipsis; white-space: nowrap; }
.pdf-thumb-main.has-image .pdf-thumb-icon, .pdf-thumb-main.has-document .pdf-thumb-icon { display: none; }
.pdf-thumb-main.has-image .pdf-thumb-label { width: 100%; padding: 0 var(--s-2) var(--s-2); }
/* Podpis nad podglądem PDF-a: półprzezroczysty pasek, żeby dało się czytać
   nazwę bez zasłaniania całej strony dokumentu. */
.pdf-thumb-main.has-document .pdf-thumb-label { position: absolute; inset: auto 0 0 0; padding: var(--s-1) var(--s-2); background: color-mix(in srgb, var(--surface) 92%, transparent); }
.pdf-thumb-main.thumb-failed .pdf-thumb-image, .pdf-thumb-main.has-image.thumb-failed .pdf-thumb-icon { display: none; }
.pdf-thumb-main.thumb-failed .pdf-thumb-icon { display: block; }
/* Pasek akcji pod miniaturą — równe kolumny bez względu na liczbę guzików. */
.pdf-thumb-actions { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; border-top: 1px solid var(--line); }
.pdf-thumb-actions a, .pdf-thumb-actions button { display: grid; place-items: center; min-height: var(--h-control-sm); border: 0; background: none; color: var(--accent-strong); font-size: var(--t-xs); font-weight: var(--w-bold); text-decoration: none; cursor: pointer; }
.pdf-thumb-actions a + a, .pdf-thumb-actions button { border-left: 1px solid var(--line); }
.pdf-thumb.empty { place-items: center; min-height: calc(var(--kafel-h) / 2); font-size: var(--t-xs); font-weight: var(--w-bold); }
/* Płótno PDF-a pokazujemy dopiero po narysowaniu (.is-rendered) — inaczej
   przez ułamek sekundy widać biały prostokąt. */
.pdf-preview-frame { position: relative; display: grid; place-items: center; overflow: hidden; }
.pdf-preview-canvas { display: block; width: 100%; height: 100%; background: var(--surface); object-fit: contain; }
.pdf-preview-canvas:not(.is-rendered), .pdf-preview-frame.thumb-failed .pdf-preview-canvas { opacity: 0; }
/* --- ZASOBY W WIERSZU (pliki przy konstrukcji / projekcie) ---------------- (z dawnego 27, K16)
   Skrót „PDF ▾ DWG ▾" w wąskiej komórce tabeli: klikalny znacznik rozwija
   małe menu (Otwórz / Pobierz). Bez pliku znacznik jest wyszarzony (.missing)
   i dopiero na hover robi się czerwony — brak pliku to nie błąd, tylko fakt. */
.resource-menu { position: relative; flex: 0 0 auto; }
.resource-menu[open] { z-index: var(--z-menu-lokalne); }
/* Wyciete 11.08.2026 — martwe reguly, zero wystapien w public/js. Szczegoly: AUDYT-CSS-2026-08-11.md B9. */
/* Suma kosztu nad paskiem zasobów. Kolor mówi, czy BOM się rozpoznał. */
.resource-total-stack { display: grid; justify-items: end; gap: 2px; min-width: 0; }
.resource-total { color: var(--text); font-size: var(--t-xs); font-weight: var(--w-bold); font-variant-numeric: tabular-nums; text-align: right; }
.resource-total-note { color: var(--text-muted); font-size: var(--t-xs); font-weight: var(--w-bold); }
/* KAL-14: .money.money-bom-error = kwota z NIEROZPOZNANYMI blokami (część pozycji BOM ma cenę 0) — czerwona jak w v8
   (reguła zgubiona przy przepisywaniu CSS; klasę dokleja JS na liście projektów, w ofertach i w Designie). */
.resource-total-note-error, .resource-total-stack.resource-total-error .resource-total, .money.money-bom-error,
.mkarta-kwota small.resource-total-note-error { color: var(--danger); }
/* KAL-14: „18 pozycji bez ceny (129 szt.)" pod „Razem" / „Dla klienta" — napis może się zawinąć (wąska kolumna kwot). */
/* DECYZJA 3: licznik obiegu wyceny („2 zestawienia do zatwierdzenia”) pod kwotą — ten sam drobny, łamany napis co pozycje bez ceny
   (zwykła wielkość notki łamała go w wąskiej kolumnie listy na 3–4 linie). */
/* Zwykłymi literami i 12 px — tak samo jak ten sam napis w pasku listy, w oknie kosztów i na telefonie. Wersaliki 11 px
   zostały tylko na wizytówce (tablet) i na stronie projektu na komputerze (przegląd E1, 27.09). */
small.resource-total-note[data-pozycje-bez-ceny], small.resource-total-note[data-obieg-wyceny-licznik] { font-size: var(--t-xs); white-space: normal; line-height: 1.2; letter-spacing: normal; text-transform: none; }
/* .money.money-bom-ok = kwota konstrukcji z BOM rozpoznanym w całości — zielona jak w v8 (reguła też zgubiona przy przepisywaniu CSS). */
.resource-total-stack.resource-total-ok .resource-total, .money.money-bom-ok { color: var(--ok-strong); }
.money-bom-neutral { color: var(--text); }
/* v15 P1: waluta przy kwocie „całej” (kwotaCala w rdzen/formaty-i-jednostki.js) — mała i szara, nie mniej niż 11 px. */
.kwota-waluta { margin-left: .15em; font-size: max(.72em, var(--t-3xs)); font-weight: var(--w-medium); color: var(--text-muted); }
/* --- OSOBA W WIERSZU I MAŁE KARTY DANYCH ---------------------------------- (z dawnego 27, K16) */
.row-user-inline { display: inline-flex; align-items: center; gap: var(--s-2); max-width: 100%; min-width: 0; }
.row-user-inline strong { min-width: 0; overflow: hidden; font-weight: var(--w-medium); text-overflow: ellipsis; white-space: nowrap; }
.row-user-label { color: var(--text-muted); font-size: var(--t-xs); }
/* Kafelek „etykieta na górze, wartość pod spodem" — opiekun klienta, kontakty. */
.client-owner-card, .client-contact-stat { display: grid; gap: 2px; padding: var(--s-2); border: 1px solid var(--line-strong); border-radius: var(--r-sm); background: var(--surface-2); }
.client-owner-card span, .client-contact-stat span { color: var(--text-muted); font-size: var(--t-xs); line-height: var(--lh-tight); }
.client-owner-card strong, .client-contact-stat strong { min-width: 0; color: var(--text); font-size: var(--t-sm); font-weight: var(--w-bold); line-height: var(--lh-tight); }
/* --- KLASY STANU — jeden zestaw dla całej aplikacji ----------------------- (z dawnego 27, K16)
   Klasa ustawia TON, a nie wygląd, więc jedna definicja obsługuje wszystkie
   komponenty, które ton już czytają (.status-pill, .stage-dot, .toast
   z 05-komponenty) — bez kopiowania stanu do każdego z osobna. Malowania
   tabeli walidacji BOM tu NIE ma: własne, mocniejsze reguły ma 24-bom-katalogi,
   a te niżej mają niską specyficzność właśnie po to, żeby mu nie przeszkadzać. */
.is-error { --ton: var(--danger); }
.is-warning, .pending, .is-stale { --ton: var(--warn); }
.is-ok, .positive { --ton: var(--ok); }
/* Stany bez własnego koloru: wygaszenie i przygaszenie. .is-disabled zostaje
   CZYTELNE — jego wartość dalej jest informacją dla użytkownika. */
/* ROL-1: przycisk wyłączony z braku prawa (`data-blokada-prawa`) wygląda na wyłączony w KAŻDYM miejscu —
   także zwykły <button> bez klasy (np. „Usuń projekt" na ekranie projektu w telefonie wyglądał na aktywny). */
.is-disabled, .is-inactive, .is-loading, [data-blokada-prawa="1"]:disabled { opacity: .55; cursor: not-allowed; }
.is-disabled input, .is-disabled button, .is-disabled label { cursor: not-allowed; }
.is-dimmed { opacity: .6; }
.is-hidden { display: none; }
.is-readonly input, .is-readonly textarea { border-color: var(--pole-ramka-zablokowane); background: var(--pole-tlo-zablokowane); color: var(--pole-napis-zablokowane); cursor: not-allowed; }
/* Wyszarzenia tekstu — „nic tu nie ma" i „brak pliku" to nie błędy. */
.empty, .placeholder { color: var(--text-faint); }
.missing, .private, .compact-recognized { color: var(--text-muted); }
.small { font-size: var(--t-sm); }
.xs { font-size: var(--t-xs); }
.is-due { color: var(--danger); font-weight: var(--w-bold); }
:where(:root[data-ui="mobile"]) .pdf-thumb { --kafel-w: 100%; --kafel-h: 160px; }
/* --- Awatar ze zdjęciem (z dawnego 28, K17) --- */
.small-avatar.has-photo { padding: 0; overflow: hidden; }
.small-avatar.has-photo img { width: 100%; height: 100%; border-radius: var(--r-pill); object-fit: cover; }
/* --- Menu konta i podgląd konta (z dawnego 28, K17) --- */
.user-menu-head { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-2) var(--s-3) var(--s-3); }
.user-menu-id { display: grid; gap: 1px; min-width: 0; }
.user-menu-id strong { overflow: hidden; font-size: var(--t-base); font-weight: var(--w-bold); text-overflow: ellipsis; white-space: nowrap; }
.user-menu-id span { overflow: hidden; color: var(--text-muted); font-size: var(--t-xs); text-align: left; text-overflow: ellipsis; white-space: nowrap; }
.user-menu-sep, .view-as-sep { height: 1px; margin: var(--s-1) var(--s-2); background: var(--line); }
.view-as-label { max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Powrót z podglądu cudzego konta — bursztynowy, bo to stan wyjątkowy. */
/* Ujednolicenie 11.08.2026 — dodane `transition`: tło wskakiwało skokiem. */
/* Tura 5 (ergonomia): pozycje menu konta („Ustawienia", „Wyloguj") nie miały żadnej reguły — stały sklejone
   w jednej linii, ikona dotykała napisu, cel 20 px wysokości. Dostają wygląd wiersza menu stąd: każda
   w osobnej linii na całą szerokość, wysokość kontrolki (32 px komputer, 44 px telefon i tablet). */
.view-as-back, .user-menu > [role="menuitem"] { display: flex; align-items: center; gap: var(--s-2); width: 100%; min-height: var(--h-control); padding: var(--s-2); border: 0; border-radius: var(--r-sm); background: transparent; color: var(--warn-strong); font: inherit; font-weight: var(--w-bold); text-align: left; cursor: pointer; transition: background var(--szybko); }
.user-menu > [role="menuitem"] { color: var(--text); }
.view-as-back:hover, .user-menu > [role="menuitem"]:hover { background: var(--surface-2); }
.view-as-opt-copy { display: flex; flex-direction: column; min-width: 0; }
.view-as-opt-copy strong { overflow: hidden; font-size: var(--t-base); text-overflow: ellipsis; white-space: nowrap; }
.view-as-opt-copy small { color: var(--text-muted); font-size: var(--t-xs); }
/* RM5 (v15 b14): „Podgląd konta” w menu konta i w arkuszu „Więcej” — wiersz menu; lista osób rozwija się POD nim,
   w tym samym okienku (w górnym pasku pigułka stoi tylko w trakcie podglądu — reguły wyżej). */
:is(.user-menu, .sidebar) :is(.view-as, .view-as-chip) { display: block; }
:is(.user-menu, .sidebar) .view-as-trigger { width: 100%; padding: var(--s-2); border: 0; border-radius: var(--r-sm); background: transparent; font-weight: var(--w-bold); }
:is(.user-menu, .sidebar) .view-as-trigger:hover { background: var(--surface-2); }
:is(.user-menu, .sidebar) .view-as-trigger .icon { width: 16px; height: 16px; }
:is(.user-menu, .sidebar) .view-as-menu { position: static; min-width: 0; max-height: calc(40dvh / var(--skala-ui)); padding: 0; border: 0; border-radius: 0; box-shadow: none; overflow-y: auto; }
:is(.user-menu, .sidebar) .view-as-menu, :is(.user-menu, .sidebar) .view-as-opt-copy :is(strong, small) { white-space: normal; overflow-wrap: anywhere; }
/* Telefon: menu boczne jest tam arkuszem albo szyną — „Zwiń menu” nie ma czego zwijać. */
:root[data-ui="mobile"] .user-menu > .collapse-button { display: none; }
/* RM8: menu konta ma stałą szerokość (opis osoby w podglądzie zawija się, zamiast rozpychać okienko na cały ekran) i sięga
   najwyżej do dołu ekranu — wtedy przewija się w środku. Na telefonie poziomo (390 px wysokości) pozycje stoją w dwóch
   kolumnach, żeby Wyloguj, motyw i język były widoczne bez przewijania. */
.user-menu { width: 300px; max-width: calc(100vw / var(--skala-ui) - 2 * var(--s-4)); max-height: calc(100dvh / var(--skala-ui) - var(--topbar-h) - var(--s-4)); }
:root[data-telefon-poziomo] .user-menu { display: grid; grid-template-columns: 1fr 1fr; align-content: start; column-gap: var(--s-1); width: 420px; }
:root[data-telefon-poziomo] .user-menu[hidden] { display: none; }
:root[data-telefon-poziomo] .user-menu > :is(.user-menu-head, .user-menu-sep, .view-as) { grid-column: 1 / -1; }
:root[data-telefon-poziomo] .user-menu > .user-menu-head { padding-bottom: var(--s-1); }
.sidebar .view-as-trigger { min-height: 48px; padding-inline: var(--s-4); border: 1px solid var(--line); border-radius: var(--r); background: var(--surface-2); }
.chevron { font-size: var(--t-xs); }
