/* ============================================================================
   24-bom-katalogi.css — WALIDACJA BOM, kartoteka BLOKÓW i wnętrza kartotek
   ----------------------------------------------------------------------------
   Trzy rzeczy, których nie ma w plikach niżej:
   1. STATUS POZYCJI BOM. Cztery role — błąd / OK / stare bloki / uwaga —
      pokazywane w trzech miejscach naraz (wiersz tabeli walidacji, pigułka
      podsumowania, wiersz szybkiego sprawdzenia w oknie konstrukcji). Kolor
      nazwany JEDEN raz jako --ton/--tlo; każde miejsce tylko go maluje.
   2. Kartoteka BLOKÓW — szkielet tabeli jest w 12-kartoteki.css, tu tylko to,
      co odróżnia ją od Materiałów (kod BOM, lampka zdrowia, plakietki cech).
   3. Wnętrza okien kartotekowych: sekcje, które w 19-modale-tresc.css dostały
      pudełko, a tutaj dostają zawartość (koszt bloku, logistyka, certyfikaty,
      załączniki dostawcy, pomoc).
   Rama okien → 05-komponenty · powłoka edytora → 19-modale-tresc ·
   tabele kartotek → 12-kartoteki · magazyn i przyjęcia → 13-zamowienia.
   ============================================================================ */
/* === 1. CZTERY ROLE STATUSU BOM ===========================================
   --ton = kolor znaczenia, --tlo = jego przygaszone tło. Tekst przyciemniamy
   domieszką --text: samo --warn na --warn-soft jest za jasne do czytania,
   a mieszanka działa w obie strony (w ciemnym --text jest jasny). */
.bom-validation-table tr.is-error, .validation-stats .is-error { --ton: var(--danger); --tlo: var(--danger-soft); }
.bom-validation-table tr.is-ok, .validation-stats .is-ok { --ton: var(--ok); --tlo: var(--ok-soft); }
.bom-validation-table tr.is-warning, .validation-stats .is-warning { --ton: var(--warn); --tlo: var(--warn-soft); }
/* === 2. WALIDACJA BOM — krok „sprawdź plik" w oknie kalkulacji ============
   Krok wypełnia okno: nagłówek stały, wyniki przewijają się same. */
.validation-step { grid-template-rows: auto minmax(0, 1fr); min-height: 0; height: 100%; overflow: hidden; }
.validation-title-row { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; }
/* Nagłówek wyniku: status z lewej, pigułki na środku, licznik pozycji z prawej. */
.validation-head { display: grid; grid-template-columns: minmax(190px, auto) minmax(0, 1fr) auto; align-items: center; gap: var(--s-3); margin-bottom: var(--s-2); }
.validation-head > p:last-child { justify-self: end; color: var(--text-muted); font-size: var(--t-xs); text-align: right; white-space: nowrap; }
.validation-stats { display: inline-flex; flex-wrap: wrap; align-items: center; justify-self: center; gap: var(--s-1); }
/* ERG6-04: plakietka ze statusem to też FILTR listy (przycisk) — ten sam wygląd, wciśnięta ma pełną ramkę. */
.validation-stats :is(span, button) { --ton: var(--text-muted); --tlo: var(--surface-2); display: inline-flex; align-items: center; min-height: var(--h-control-sm); padding: 0 var(--s-2); border: 1px solid color-mix(in srgb, var(--ton) 45%, transparent); border-radius: var(--r-pill); background: var(--tlo); color: color-mix(in srgb, var(--ton) 70%, var(--text)); font-size: var(--t-xs); font-weight: var(--w-bold); }
.validation-stats button { cursor: pointer; }
.validation-stats button[aria-pressed="true"] { border-color: var(--ton); box-shadow: inset 0 0 0 1px var(--ton); }
.validation-result-pane { min-height: 0; overflow: hidden; }
.validation-result-pane .table-wrap { max-height: 100%; overflow: auto; }
/* Podgląd surowego pliku przed walidacją: nazwa i liczba wierszy. */
.validation-summary-line { display: flex; align-items: center; gap: var(--s-3); min-height: var(--h-control); }
/* Obie tabele BOM: JEDEN ekran = jak najwięcej wierszy, więc komórki są niskie
   i NIGDY nie zawijają — długa nazwa ucina się wielokropkiem (pełna w title).
   Szerokości kolumn ustawia JS inline, tutaj ich nie ruszamy. */
.bom-validation-table :is(th, td), .bom-preview-table :is(th, td) { height: calc(var(--h-control-sm) + var(--s-1)); padding: var(--s-1) var(--s-2); overflow: hidden; line-height: var(--lh-tight); white-space: nowrap; text-overflow: ellipsis; vertical-align: middle; }
/* ERG6-04: nagłówek kolumny może zejść do drugiej linii („Wysokość / A”) — na tablecie ucinał się do „Wysok…”. */
.bom-validation-table th { position: sticky; top: 0; z-index: 2; background: var(--surface); white-space: normal; text-overflow: clip; }
/* jedzie z przewijaniem; tło jawne, bo wiersze pod nim mają własne */
.bom-validation-table td { border-top: 1px solid color-mix(in srgb, var(--ton) 45%, transparent); border-bottom: 1px solid color-mix(in srgb, var(--ton) 45%, transparent); background: var(--tlo); color: color-mix(in srgb, var(--ton) 70%, var(--text)); }
/* Wiersz z rozpoznanym blokiem otwiera kartotekę — kursor to zapowiada. */
.bom-validation-table tr[data-bom-validation-row] { cursor: pointer; }
/* Ujednolicenie 11.08.2026 — wiersz klikalny MUSI reagować na kursor (audyt B6).
   Ton wiersza wzmocniony do 26%, żeby podświetlenie działało w każdej z czterech
   ról statusu i nie gubiło ich koloru. */
.bom-validation-table tr[data-bom-validation-row]:hover td { background: color-mix(in srgb, var(--ton) 26%, var(--surface)); }
/* Dopisek przy nazwie (dostawca) — cichszy od nazwy, w tej samej linii. */
.bom-validation-table .tiny { display: inline; margin-left: var(--s-1); color: inherit; opacity: .72; }
/* ERG6-04: powód błędu pod kodem bloku — jedno zdanie, w kolorze wiersza. */
.bom-blad-powod { display: block; overflow: hidden; font-size: var(--t-xs); font-weight: var(--w-medium); text-overflow: ellipsis; white-space: nowrap; }
/* Nazwa bloku jest przyciskiem, ale ma wyglądać jak tekst wiersza. */
.bom-block-name-button { display: block; max-width: 100%; padding: 0; border: 0; background: transparent; color: inherit; font: inherit; font-weight: var(--w-bold); overflow: hidden; text-align: left; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; transition: color var(--szybko); }
/* Ujednolicenie 11.08.2026 — wyglądał jak zwykły tekst i był bez reakcji, więc
   nic nie mówiło, że można w niego kliknąć. Bliźniaczy przycisk nazwy niżej
   w tym samym pliku odzew MA — to była niespójność, nie decyzja. */
.bom-block-name-button:hover { color: var(--accent-strong); text-decoration: underline; }
/* Ujednolicenie 11.08.2026 — jeden rozmiar przycisku-ikony (--h-ikona).
   Był 31×27, czyli jedyny niekwadratowy w aplikacji. */
.bom-row-actions .icon-button { flex: none; width: var(--h-ikona); height: var(--h-ikona); padding: 0; }
/* Notatka do pozycji: zielona, gdy wpis istnieje. Zielony „+" = dodaj brakujący blok. */
.icon-button.bom-comment-button.has-comment, .icon-button.bom-add-block { border-color: transparent; background: var(--accent-soft); color: var(--accent-strong); }
/* Podgląd surowego CSV: stała siatka, poziomy scroll zamiast ściskania kolumn. */
.bom-preview-table { table-layout: fixed; min-width: max(900px, 100%); }
/* Pasek akcji nad listą BOM (import, przelicz, komentarz). */
.bom-action-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.bom-action-row span { min-width: 0; overflow: hidden; color: var(--text-muted); font-size: var(--t-xs); text-overflow: ellipsis; white-space: nowrap; }
/* ROL-3: odmowa zapisu zestawienia — cały powód w osobnej linii pod przyciskami, nie ucięty. */
.bom-action-row span.is-error { grid-column: 1 / -1; color: var(--danger); white-space: normal; }
/* M6 (18.10.2026): obieg wyceny, pasek zestawienia („Błędy / OK”) i wiersz pliku w oknie konstrukcji — wzór v99 w 25c-konstrukcja-okno.css §4. */
/* === 4. KARTOTEKA BLOKÓW ==================================================
   Szerokości kolumn daje <colgroup> w JS — tu tylko zachowanie treści. */
.block-catalog-table { table-layout: fixed; width: 100%; }
.block-catalog-table th, .block-catalog-table td { overflow-wrap: anywhere; vertical-align: middle; white-space: nowrap; }
/* Liczby (cena, pojemność) do prawej; menu wiersza na środku. POPR-n31: po kluczu kolumny (data-kol), bo kolumny
   można chować i numer kolumny się zmienia. */
.block-catalog-table :is(th, td):is([data-kol="price"], [data-kol="capacity"]) { font-variant-numeric: tabular-nums; text-align: right; }
.block-catalog-table :is(th, td):last-child { text-align: center; }
/* Wiersz filtrów (`<th>`, nie `<td>`) obsługuje 12-kartoteki.css — tam jest
   jego właściciel. Duplikat usunięty, żeby nie było dwóch źródeł prawdy. */
/* Trzy kolumny WOLNO zawijać (prefiks tabeli konieczny — inaczej przegrywają
   z nowrap wyżej). Kod BOM bywa długi i rozpychał tabelę poza ekran z menu. */
.block-catalog-table :is(.block-name-cell, .block-price-cell, .block-typ-cell) { white-space: normal; }
/* POPR-n31: kod bloku w JEDNEJ linii z wielokropkiem (pełny kod w dymku komórki) — łamany po każdym myślniku
   dawał 4–7 linii („ANCHOR-WIT-VM250+ROD-…”) i wiersz 110 px. Nazwa najwyżej w dwóch liniach (pełna w dymku). */
.block-catalog-table .block-code-cell { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.block-catalog-table .block-name-cell .material-name-line { display: -webkit-box; overflow: hidden; overflow-wrap: anywhere; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.block-catalog-table td:is([data-kol="category"], [data-kol="attraction"]) { overflow: hidden; text-overflow: ellipsis; }
/* Tablet (dotyk): dymka nie widać, więc kod i nazwa pokazują się w całości — łamane w dowolnym miejscu (2 linie), nie po myślnikach. */
:where(:root[data-ui="tablet"]) .block-catalog-table .block-code-cell { overflow-wrap: anywhere; white-space: normal; }
:where(:root[data-ui="tablet"]) .block-catalog-table .block-name-cell .material-name-line { display: inline; -webkit-line-clamp: unset; }
.block-price-cell > strong { white-space: nowrap; }
/* ERG6-06: rozbicie ceny w JEDNEJ krótkiej linii (pełne kwoty w dymku komórki) — dawniej 3–4 linie pod ceną. */
.block-price-split { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.block-price-split > span { display: block; }   /* 20.10.2026: kwoty z walutą („materiały 35,23 EUR” / „praca 0,00 EUR”) — dwie krótkie linie zamiast liczb bez jednostki */
/* POPR2-n31: tablet (dotyk, bez dymka) — rozbicie ceny widać w całości: „mat. 35,18 ·” i „praca 0,00” mogą zejść do drugiej
   linii (twarde spacje w kwotach, więc łamie się tylko przy „·”), zamiast uciętego „mat. 35,18 · praca 0…” w 187 z 200 wierszy. */
:where(:root[data-ui="tablet"]) .block-catalog-table .block-price-split { overflow: visible; text-overflow: clip; white-space: normal; }
:where(:root[data-ui="tablet"]) .block-catalog-table td:is([data-kol="category"], [data-kol="attraction"]) { overflow: visible; text-overflow: clip; white-space: normal; }   /* kategoria („TP-STEEL-MOUNTING”) też w całości */
/* Lampka kompletności bloku: zielona / bursztyn / czerwona, z aureolą.
   Ujednolicenie 11.08.2026 — aureola 3px → var(--s-1) (4 px). W aplikacji jest
   jeden wzór poświaty: `0 0 0 var(--s-1) color-mix(… 18%, transparent)` —
   pole z fokusem (03:76, 03:100), pole daty (15:197), lista wyszukiwania
   (27:211), pole nabywcy (28:268). Te trzy kropki były jedynym miejscem,
   gdzie ta sama aureola miała 3 px. Procent 18% już się zgadzał. */
.block-health-dot { display: inline-block; flex: none; width: var(--s-2); height: var(--s-2); margin-right: var(--s-2); border-radius: var(--r-pill); vertical-align: middle; }
.block-health-dot.is-green { background: var(--ok); box-shadow: 0 0 0 var(--s-1) color-mix(in srgb, var(--ok) 18%, transparent); }
.block-health-dot.is-orange { background: var(--warn); box-shadow: 0 0 0 var(--s-1) color-mix(in srgb, var(--warn) 18%, transparent); }
.block-health-dot.is-red { background: var(--danger); box-shadow: 0 0 0 var(--s-1) color-mix(in srgb, var(--danger) 18%, transparent); }
/* Plakietki cech bloku (dynamiczny, instalacja) — jedna pod drugą, nie w rzędzie. */
.block-flags { display: flex; flex-direction: column; gap: var(--s-1); }
/* NAPRAWA 11.08.2026 — napis przez `--ton-tekst`, jak `.status-pill` i `.dash-chip`.
   Trzeci komponent powtarzający ten sam wzór (napis pełnym tonem na 12-procentowym
   odcieniu tego samego tonu) i trzeci z tym samym defektem kontrastu:
   zmierzone „Montaż" 3,89:1 przy progu 4,5. */
.block-flag { display: inline-block; width: fit-content; padding: 0 var(--s-1); border: 1px solid color-mix(in srgb, var(--ton) 30%, transparent); border-radius: var(--r-pill); background: color-mix(in srgb, var(--ton) 12%, transparent); color: var(--ton-tekst, var(--ton)); font-size: var(--t-xs); font-weight: var(--w-bold); white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.block-flag.is-dynamic { --ton: var(--accent); --ton-tekst: var(--accent-strong); }
.block-flag.is-install { --ton: var(--etap-montaz); --ton-tekst: color-mix(in srgb, var(--etap-montaz) 90%, var(--text)); }
/* Reguły cięcia stali: numer reguły i wynik liczbowy do prawej. */
.bom-steel-rules-table :is(th, td):nth-child(1), .bom-steel-rules-table :is(th, td):nth-child(6) { font-variant-numeric: tabular-nums; text-align: right; }
/* Przyjęcie dostawy: cztery kolumny ilości do prawej (13-zamowienia równa od 3.). */
.receipt-table :is(th, td):nth-child(2) { font-variant-numeric: tabular-nums; text-align: right; }
/* Wspólne drobiazgi kartotek: pasek filtrów, pusty stan, rozwijanie kolorów. */
.catalog-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
.catalog-filter-toggle.is-active { border-color: var(--accent-strong); color: var(--accent-strong); }
.catalog-col-unit { color: var(--text-muted); font-size: var(--t-xs); white-space: nowrap; }
.catalog-empty-row td { padding: var(--s-5); color: var(--text-muted); text-align: center; }
/* Strzałka „pokaż kolory" — rysowana ramką, dziedziczy kolor akcentu, bez ikony. */
.material-expand-caret-btn { display: inline-flex; align-items: center; padding: var(--s-1); margin-right: var(--s-1); cursor: pointer; }
.material-expand-caret { display: inline-block; width: 0; height: 0; border-left: 5px solid var(--accent); border-top: 4px solid transparent; border-bottom: 4px solid transparent; transition: transform var(--szybko) ease; }
.material-expand-caret.open { transform: rotate(90deg); }
/* Kwoty w drzewie kalkulacji stoją w jednej linii z nazwą pozycji. */
.material-price-cell, .transport-price-cell { vertical-align: middle; }
/* === 5. OKNO MATERIAŁU ====================================================
   Magazyn i Zamawianie to formularze „etykieta ....... WARTOŚĆ": jedna kolumna
   pól o STAŁEJ szerokości przy prawej krawędzi, żeby liczby stały w słupku. */
.material-stock-panel .material-basic-grid { grid-template-columns: minmax(0, 1fr); align-items: center; max-width: 380px; }
.material-stock-panel .field { display: grid; grid-template-columns: minmax(0, 1fr) 150px; align-items: center; gap: var(--s-3); }
.material-stock-panel input:not([type="checkbox"]) { justify-self: end; width: 150px; text-align: right; }
/* Panel Zamawianie jest kotwicą dla dymka „Co to jest nadwyżka?" w rogu. */
.material-ordering-panel { position: relative; }
/* Ceny i masa: liczba zawsze przy jednostce, czyli do prawej. */
.material-commercial-panel input[type="number"] { text-align: right; }
/* Combo jednostki (waga) nie może rozpychać wiersza z liczbą. */
.measure-row .combo { flex: 0 0 96px; max-width: 96px; }
/* Tabela kolorów to ARKUSZ do wpisywania: pola wtapiają się w komórki,
   ramka pojawia się dopiero przy interakcji — liczy się liczba widocznych wierszy. */
.material-colors-panel input[type="text"], .material-colors-panel input[type="number"] { height: var(--h-control-sm); border-color: transparent; background: transparent; }
.material-colors-panel input:not([type="checkbox"]):hover { background: color-mix(in srgb, var(--accent) 6%, transparent); }
.material-colors-panel input:not([type="checkbox"]):focus { border-color: var(--accent-strong); background: var(--surface); }
/* Certyfikaty: sekcja jest ostatnia w boku, więc rośnie do dołu okna, a nadmiar przewija się PIONOWO w liście. */
.material-certificates-section { display: flex; flex: 1 1 auto; flex-direction: column; gap: var(--s-2); min-height: 0; }
.material-cert-scope { display: flex; flex: none; flex-wrap: wrap; gap: var(--s-3); }
.material-cert-scope-option { display: inline-flex; align-items: center; gap: var(--s-2); font-size: var(--t-sm); cursor: pointer; }
.material-cert-existing { display: flex; flex: none; align-items: center; gap: var(--s-2); }
.material-cert-existing[hidden] { display: none; }
.material-cert-existing select { flex: 1 1 auto; min-width: 0; }
.material-cert-preview { flex: 1 1 auto; min-height: 110px; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }
.material-cert-info { display: flex; flex: 1 1 auto; flex-direction: column; gap: var(--s-1); min-width: 0; }
.material-cert-link { color: var(--accent-strong); font-size: var(--t-xs); font-weight: var(--w-medium); }
.material-cert-pending { color: var(--text-muted); font-size: var(--t-xs); font-style: italic; }
.material-cert-remove { flex: none; display: inline-grid; place-items: center; width: var(--s-5); height: var(--s-5); padding: 0; border: 0; background: transparent; color: var(--danger); cursor: pointer; }
.material-photo-clickable { cursor: zoom-in; }
/* === 6. OKNO BLOKU ========================================================
   Koszt bloku: tabela składników w ramce + pasek sum nad nią. */
.block-cost-panel .table-wrap { max-height: none; overflow-x: hidden; overflow-y: visible; border-radius: var(--r-sm); }
.block-cost-panel .component-table { table-layout: fixed; min-width: 0; width: 100%; }
/* Tabela SKŁADNIKÓW (panel komponentów) układa się AUTOMATYCZNIE — sztywny
   układ dostaje w v8 wyłącznie tabela kosztów wyżej (monolit 4963). Klasa
   `compact-data-table` narzucała jej `table-layout: fixed` + `min-width: 980px`,
   przez co kolumny bez zadanej szerokości („Materiał" i „Waga") dzieliły
   resztę PO RÓWNO — 338 px każda. W v8 pierwsza kolumna bierze 590 px na
   wybierak, a „Waga" tylko 118 px. */
.block-component-panel .component-table { table-layout: auto; min-width: 0; }
/* ERG6-02: pole „Ilość” nie oddaje miejsca wybierakom — na tablecie 1024 ściskało się do ~20 px („1”, „9”, „(”). */
.block-component-panel .component-table [data-component-qty] { min-width: 72px; }
.block-cost-summary { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--s-1); }
.block-cost-summary span { display: inline-flex; align-items: center; gap: var(--s-1); min-height: var(--h-control-sm); padding: 0 var(--s-2); border: 1px solid var(--line-strong); border-radius: var(--r-pill); background: var(--surface-2); color: var(--text-muted); font-size: var(--t-xs); font-weight: var(--w-bold); }
.block-cost-summary strong { color: var(--text); }
/* Cena końcowa bloku to wynik całej sekcji — jedyna pigułka na akcencie. */
.block-grand-total { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); background: var(--accent-soft); }
/* „+ Wiersz" ma być POD tabelą, a nie nad nią — DOM zostaje, zmieniamy kolejność. */
.block-component-panel { display: grid; gap: var(--s-1); }
.block-component-panel > .table-wrap { order: 1; }
.block-component-panel > .component-table-toolbar { order: 2; justify-content: flex-end; }
/* Dynamika i Instalacja stoją obok siebie, z tą samą rynną co odstęp pionowy. */
.block-editor-panel-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
.block-rule-panel .panel-head-toggle { margin-left: auto; white-space: nowrap; }
.block-installation-grid { align-items: start; }
.block-two-field-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
.block-two-field-grid > * { min-width: 0; }
.block-short-help { margin: 0; color: var(--text-muted); font-size: var(--t-xs); line-height: var(--lh-base); }
.block-table-divider, .block-transport-divider { height: 1px; background: var(--line); }
.block-transport-divider { margin: var(--s-1) 0; background: var(--line-strong); }
.block-notes-field .catalog-rich-notes { min-height: 96px; }
/* Zdjęcie bloku: stała proporcja, obraz zawsze w całości i wyśrodkowany. */
.block-image-preview { position: relative; overflow: hidden; aspect-ratio: 4 / 3; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-2); }
.block-image-preview img { display: block; width: 100%; height: 100%; object-fit: contain; }
.block-image-preview-large { width: 100%; min-height: 260px; }
.block-image-frame { display: grid; place-items: center; width: 100%; height: 100%; }
/* Skąd wzięło się zdjęcie (ręczne / z konstrukcji) — przypis, nie nagłówek. */
.block-image-source { padding: var(--s-1) var(--s-2); border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-2); color: var(--text-muted); font-size: var(--t-xs); line-height: var(--lh-base); }
/* Dodaj / usuń zdjęcie leżą NA podglądzie, w przeciwnych rogach. */
.block-image-overlay-action { position: absolute; z-index: 2; width: var(--h-control-sm); height: var(--h-control-sm); padding: 0; background: color-mix(in srgb, var(--surface) 92%, transparent); }
.block-image-add-action { top: var(--s-1); left: var(--s-1); }
.block-image-clear-action { top: var(--s-1); right: var(--s-1); }
/* Logistyka: wymiary transportowe bloku w zwartej pod-karcie. */
.block-transport-card { display: grid; gap: var(--s-1); padding: var(--s-2); border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-2); }
/* Wiersz „etykieta | przeliczenie | pole": przeliczenie („= 0,095 m") rośnie W LEWO, pola stoją w słupku. */
.transport-line { display: grid; grid-template-columns: auto minmax(0, 1fr) 96px; align-items: center; gap: var(--s-2); min-width: 0; font-size: var(--t-xs); font-weight: var(--w-bold); }
.transport-line em { justify-self: end; color: var(--text-muted); font-size: var(--t-xs); font-style: normal; white-space: nowrap; }
.transport-line input { width: 100%; min-width: 0; text-align: right; font-variant-numeric: tabular-nums; }
.transport-stackable { grid-column: 1 / -1; }
/* Zapis odrzucony → pulsująca ramka na winnej sekcji (bywa poza widokiem, sam kolor umyka). */
.block-attention { box-shadow: 0 0 0 2px var(--danger), 0 0 16px color-mix(in srgb, var(--danger) 30%, transparent); animation: block-attention-pulse 1.6s ease-in-out infinite; }
@keyframes block-attention-pulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--danger), 0 0 16px color-mix(in srgb, var(--danger) 30%, transparent); }
  50% { box-shadow: 0 0 0 2px color-mix(in srgb, var(--danger) 55%, transparent), 0 0 6px color-mix(in srgb, var(--danger) 12%, transparent); }
}
/* Pomoc „po ludzku": przycisk po lewej stronie stopki, karty rysunek + opis. */
.block-help-btn { display: inline-flex; align-items: center; gap: var(--s-2); margin-right: auto; }
.block-help-body { display: flex; flex-direction: column; gap: var(--s-3); overflow-y: auto; }
.block-help-card { display: flex; align-items: flex-start; gap: var(--s-4); padding: var(--s-3); border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-2); }
/* Ujednolicenie 11.08.2026 — .02em → kanon .04em, jak `.transport-mode-table th` w tym samym arkuszu. */
.block-help-segment { margin: var(--s-2) 0 0; color: var(--accent-strong); font-size: var(--t-sm); font-weight: var(--w-bold); }
.block-help-intro, .block-help-outro { margin: 0; line-height: var(--lh-base); }
.block-help-outro { padding-top: var(--s-3); border-top: 1px solid var(--line); color: var(--text-muted); }
/* Kategorie bloków: tabela trybów liczenia transportu, aktywny tryb z paskiem. */
.transport-mode-table { width: 100%; margin-top: var(--s-3); line-height: var(--lh-base); }
/* Ujednolicenie 11.08.2026 — komórki wyrównane w pionie do środka, jak w każdej
   innej tabeli aplikacji (było `top`). */
.transport-mode-table :is(th, td) { padding: var(--s-2) var(--s-3); border-bottom: 1px solid var(--line); background: var(--akt-tlo, transparent); box-shadow: var(--akt-pasek, none); text-align: left; vertical-align: middle; }
.transport-mode-table th { color: var(--text-muted); font-size: var(--t-xs); font-weight: var(--w-bold); }
.transport-mode-table td:first-child { font-weight: var(--w-bold); white-space: nowrap; }
/* Ujednolicenie 11.08.2026 — pasek akcentu --s-1, jeden na całą aplikację. */
.transport-mode-table .is-active { --akt-tlo: var(--surface-2); }
/* POPR-n45: aktywny tryb = tło wiersza (--akt-tlo wyżej), bez paska akcentu z lewej. */
.block-category-form [data-category-param][hidden] { display: none; }
/* === 7. DOSTAWCA, EKIPA, USŁUGA, TRANSPORT ================================
   Kontakty są dwuwierszowymi wizytówkami (§19), więc rząd etykiet kolumn
   nie ma czego opisywać — zostaje w DOM dla czytników, znika z ekranu. */
.supplier-contact-head { display: none; }
.supplier-contact-name input { font-weight: var(--w-medium); }
.supplier-contact-remove { align-self: center; justify-self: center; }
.supplier-add-contact-btn { justify-self: end; margin-top: var(--s-2); }
/* Wizytówka w boku: teksty ZAWIJANE, nie ucinane — adres musi być czytelny w całości. */
.supplier-card-lines { display: grid; gap: var(--s-1); }
.supplier-card-lines span { min-width: 0; color: var(--text-muted); font-size: var(--t-xs); overflow-wrap: anywhere; }
.supplier-logo-tools { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-1); }
.supplier-logo-tools > * { min-width: 0; overflow: hidden; }
.supplier-attachment-tools { grid-template-columns: minmax(0, 1fr); }
.supplier-attachment-list { display: grid; gap: var(--s-1); }
/* Wiersz załącznika ma 4 dzieci, a wspólny raster z §19 ma 3 kolumny: kosz wypada
   z układu (leży NA wierszu, stąd position:relative), a typ pliku schodzi pod nazwę. */
.supplier-attachment-item { position: relative; grid-template-columns: auto minmax(0, 1fr); }
.supplier-attachment-item small { grid-column: 2; }
/* Nazwa załącznika rozwija menu (Otwórz / Pobierz) — bez własnego przycisku,
   bo wiersz jest wąski; kropkowane podkreślenie mówi „to się klika". */
.supplier-attachment-menu { position: relative; min-width: 0; }
.supplier-attachment-menu summary { display: block; min-width: 0; overflow: hidden; font-weight: var(--w-bold); list-style: none; text-decoration: underline dotted var(--text-faint); text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
.supplier-attachment-menu summary::-webkit-details-marker { display: none; }
/* Ujednolicenie 11.08.2026 — promień panelu pływającego = --r (był --r-sm). */
.supplier-attachment-dropdown { position: absolute; top: calc(100% + var(--s-1)); left: 0; z-index: var(--z-menu-nad-trescia); display: grid; min-width: 128px; overflow: hidden; border: 1px solid var(--line-strong); border-radius: var(--r); background: var(--surface); box-shadow: var(--cien-2); }
.supplier-attachment-dropdown a, .supplier-attachment-dropdown span { padding: var(--s-1) var(--s-2); font-size: var(--t-xs); font-weight: var(--w-bold); }
.supplier-attachment-dropdown a:hover { background: var(--surface-2); }
/* Kosz odsłania się na hoverze wiersza — nie zaśmieca listy, ale jest pod ręką. */
.supplier-attachment-remove { position: absolute; top: 50%; right: var(--s-1); display: grid; place-items: center; width: var(--s-5); height: var(--s-5); padding: 0; border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent); border-radius: var(--r-sm); background: var(--danger-soft); color: var(--danger); opacity: 0; transform: translateY(-50%); transition: opacity var(--szybko) ease; cursor: pointer; }
.supplier-attachment-item:hover .supplier-attachment-remove, .supplier-attachment-remove:focus-visible { opacity: 1; }
/* Checkbox „Platforma zakupowa" ma etykietę-flex, która ściskała go do zera. */
.supplier-platform-field input[type="checkbox"] { flex: none; width: 18px; min-width: 18px; height: 18px; }
/* Etykieta-wiersz „Platforma zakupowa” (dawniej styl w atrybucie): na dotyku cały wiersz jest celem klikania — 44 px (było 21 px). */
.supplier-platform-label { display: flex; align-items: flex-start; gap: var(--s-2); cursor: pointer; font-weight: var(--w-medium); }
:root:is([data-ui="mobile"], [data-ui="tablet"]) .supplier-platform-label { align-items: center; min-height: var(--h-control); }
/* Stawki ekipy i notatki: pudełka mają już ramkę z §19, tu tylko wypełnienie. */
.crew-rates-panel { display: grid; gap: var(--s-2); }
.crew-rates-panel .table-wrap { max-height: none; overflow-x: auto; overflow-y: visible; }
.crew-notes-panel { align-content: start; min-height: 0; overflow: hidden; }
/* Notatki usługi sięgają dołu kolumny — flex przez cały łańcuch, inaczej pole zostaje niskie. */
.work-service-notes-panel { display: flex; flex: 1 1 auto; flex-direction: column; min-height: 0; padding-bottom: 0; }
.work-service-notes-panel .field { display: flex; flex: 1 1 auto; flex-direction: column; min-height: 0; }
/* Trasa certyfikatora: nieaktywny sposób rozliczenia wygaszony, ale CZYTELNY
   (readonly, nie disabled — wartość musi zostać widoczna). */
.crew-travel-editor-form .field.is-inactive { opacity: .5; }
.crew-travel-editor-form .field-hint { display: block; margin-top: var(--s-1); color: var(--text-muted); font-size: var(--t-xs); line-height: var(--lh-base); }
/* Karta podsumowania pojazdu / usługi w kolumnie bocznej. */
.transport-side-card > strong { min-width: 0; overflow: hidden; font-weight: var(--w-bold); text-overflow: ellipsis; white-space: nowrap; }
.transport-side-card > span, .transport-summary-grid span { color: var(--text-muted); font-size: var(--t-xs); }
/* NAPRAWA 11.08.2026 — KOLUMNY ZAMIENIONE ROLAMI.
   Było `minmax(0, 1fr) auto`: kolumna ETYKIETY miała pozwolenie zapaść się do
   zera, a kolumna WARTOŚCI (`strong` z `white-space: nowrap`) brała tyle, ile
   chciała. Zmierzone w oknie Materiału: wartości rozepchnęły się do 265 px,
   a na etykiety zostało 19,7 px — „Jednostka", „Dostawca" i „Kategoria" były
   ucięte do dwóch liter (potrzebowały 52, 50 i 47 px).
   Teraz etykieta ma `auto` (nigdy się nie skróci — to ona mówi, co się czyta),
   a wartość dostaje `minmax(0, 1fr)` i wielokropek, gdy jest za długa. */
.transport-summary-grid { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: var(--s-1) var(--s-2); }
.transport-summary-grid strong { min-width: 0; overflow: hidden; font-weight: var(--w-bold); text-align: right; text-overflow: ellipsis; white-space: nowrap; }
.transport-group-label { color: var(--text-muted); font-size: var(--t-xs); font-weight: var(--w-bold); }
/* NAPRAWA 11.08.2026 — napis --accent → --accent-strong. `--accent` na
   `--accent-soft` daje 3,93:1 przy 11 px, czyli poniżej progu 4,5:1.
   Ta sama poprawka co na przycisku głównym (03-kontrolki). Tło i ramka bez zmian. */
.transport-mode-badge { display: inline-flex; align-items: center; width: fit-content; min-height: var(--h-control-sm); padding: 0 var(--s-2); border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); border-radius: var(--r-pill); background: var(--accent-soft); color: var(--accent-strong); font-size: var(--t-xs); font-weight: var(--w-bold); }
.transport-dimension-preview { padding: var(--s-2); border: 1px solid var(--line-strong); border-radius: var(--r-sm); background: var(--surface); font-size: var(--t-xs); font-weight: var(--w-bold); }
/* Formularz pojazdu: trzy kolumny; wymiary ładunku zajmują cały rząd. */
.transport-form-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-2); align-items: end; }
.transport-cost-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.transport-form-grid > .full, .transport-dimension-fields { grid-column: 1 / -1; }
.transport-dimension-fields { display: grid; gap: var(--s-1); padding: var(--s-2); border: 1px solid var(--line-strong); border-radius: var(--r-sm); background: var(--surface-2); }
/* dł × szer × wys w jednej linii — „x" jest separatorem, nie polem. */
.transport-dimensions-row { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr); align-items: end; gap: var(--s-1); min-width: 0; }
.transport-dimensions-row label { display: grid; gap: var(--s-1); min-width: 0; color: var(--text-muted); font-size: var(--t-xs); }
.transport-dim-separator { display: inline-flex; align-items: center; justify-content: center; min-height: var(--h-control-sm); color: var(--text-muted); font-size: var(--t-xs); font-weight: var(--w-bold); }
/* ============================================================================
   8. RESPONSYWNOŚĆ — progi 1180 / 980 / telefon
   ============================================================================ */
@media (max-width: 1180px) {
  /* Podgląd zdjęcia zjada wysokość kolumny bocznej — przycinamy mu zakres. */
  .block-image-preview-large { min-height: 240px; max-height: 360px; }
  .transport-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* ERG6-02: węższe okno bloku — kategoria i składnik jeden pod drugim (nazwa nad polami), ilość i koszt mają miejsce. */
  .block-component-panel .component-picker { grid-template-columns: minmax(0, 1fr); }
  .block-component-panel .component-picker-with-mode { grid-template-columns: auto minmax(0, 1fr); }
  .block-component-panel .component-picker-with-mode > :last-child { grid-column: 1 / -1; }
  .block-component-panel .component-table :is(th, td):first-child { width: 40%; }
}
@media (max-width: 980px) {
  /* Dwa panele reguł obok siebie robią się węższe niż ich pola. */
  .block-editor-panel-row { grid-template-columns: minmax(0, 1fr); }
  /* Nagłówek walidacji: pigułki wracają pod status, licznik pod nie. */
  .validation-head { grid-template-columns: minmax(0, 1fr); justify-items: start; }
  .validation-stats, .validation-head > p:last-child { justify-self: start; text-align: left; white-space: normal; }
}
/* Telefon: wszystkie siatki tego pliku schodzą do jednej kolumny. */
:where(:root[data-ui="mobile"]) .catalog-grid, :where(:root[data-ui="mobile"]) .block-two-field-grid, :where(:root[data-ui="mobile"]) .transport-form-grid, :where(:root[data-ui="mobile"]) .transport-cost-grid, :where(:root[data-ui="mobile"]) .transport-dimensions-row, :where(:root[data-ui="mobile"]) .supplier-logo-tools { grid-template-columns: minmax(0, 1fr); }
/* Separator „x" bez sąsiadów w linii traci sens. */
:where(:root[data-ui="mobile"]) .transport-dim-separator { display: none; }
/* Karta pomocy: rysunek nad opisem, całość wyśrodkowana. */
:where(:root[data-ui="mobile"]) .block-help-card { flex-direction: column; align-items: center; text-align: center; }
/* Podgląd zdjęcia nie może zająć całego ekranu przed formularzem. */
:where(:root[data-ui="mobile"]) .block-image-preview { max-width: 180px; }
:where(:root[data-ui="mobile"]) .block-image-preview-large { min-height: 0; max-height: none; }
/* Dotyk zamiast myszy: przyciski na zdjęciu i kosz załącznika muszą być trafialne. */
:where(:root[data-ui="mobile"]) .block-image-overlay-action { width: var(--h-row); height: var(--h-row); }
:where(:root[data-ui="mobile"]) .supplier-attachment-remove { opacity: 1; }
/* Pola „etykieta | wartość" nie mieszczą stałej kolumny 150px. */
:where(:root[data-ui="mobile"]) .material-stock-panel .field { grid-template-columns: minmax(0, 1fr); }
:where(:root[data-ui="mobile"]) .material-stock-panel input:not([type="checkbox"]) { justify-self: stretch; width: 100%; }

/* NAZWA WGRANEGO PLIKU BOM + DATA (13.08.2026). Nazwa w pierwszej linii, data pod nią —
   długie nazwy plików mają się skracać wielokropkiem, a nie rozpychać wiersza ani
   spychać przycisku „Wgraj". Pełna nazwa zostaje w dymku (title). */
.bom-action-row .bom-plik-info { display: grid; gap: 1px; min-width: 0; white-space: normal; } /* E2 (27.09): napis bez pliku („Zapisz konstrukcję, żeby wgrać zestawienie.”) łamie się zamiast ucinać — nazwa pliku ma własne „…”; selektor jak `.bom-action-row span`, z którym się ściera */
.bom-plik-nazwa { display: block; overflow: hidden; min-width: 0; color: var(--text); font-size: var(--t-sm); font-weight: var(--w-bold); text-overflow: ellipsis; white-space: nowrap; }
.bom-plik-data { display: block; color: var(--text-muted); font-size: var(--t-xs); white-space: normal; } /* E2 (27.09): data i stan łamią się pod nazwą pliku — wcześniej „kalkulacja zapisana” była ucięta w pół słowa (okno konstrukcji, 1440 i telefon) */
.bom-action-row { min-width: 0; }

/* === 9. SZKIELET OKNA KALKULACJI (okno BOM) =============================== (z dawnego 27, K16)
   Stała lewa kolumna (kontekst + marże) i szeroki obszar roboczy. Sidebar
   przyklejony do góry, bo przy przewijaniu długiej listy pozycji trzeba stale
   widzieć, KTÓREGO projektu i konstrukcji dotyczy liczenie. */
/* JEDNA kolumna (12.08.2026): okno BOM straciło boczny panel z marżami i kwotami —
   marże ustawia się w kalkulatorze, kwoty pokazuje panel konstrukcji. Tabela BOM
   dostaje całą szerokość okna. Kontekst projektu przeniesiony do nagłówka. */
.calculation-shell { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-4); align-items: start; }
.calc-header-context { margin-left: var(--s-3); color: var(--text-muted); font-size: var(--t-xs); }
.calculation-sidebar { position: sticky; top: 0; display: grid; gap: var(--s-3); padding: var(--s-3); border: 1px solid var(--line); border-radius: var(--r); background: var(--surface-2); }
.calculation-workspace { display: grid; gap: var(--s-3); }
.calc-step { display: grid; gap: var(--s-3); padding: var(--s-3); border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.calc-step-head { display: flex; align-items: center; gap: var(--s-3); }
/* Numer kroku w kółku — pokazuje kolejność bez pisania „Krok 1". */
.calc-step-head > span:first-child { display: grid; place-items: center; flex: none; width: var(--s-5); height: var(--s-5); border-radius: var(--r-pill); background: var(--accent); color: var(--text-invert); font-size: var(--t-sm); font-weight: var(--w-bold); }
.calc-step-head h3 { font-size: var(--t-md); font-weight: var(--w-bold); }
.calc-step-head p { color: var(--text-muted); font-size: var(--t-base); }
.calc-context-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-4); align-items: start; }
.calc-context { display: grid; gap: var(--s-1); min-width: 0; }
.calc-context span { color: var(--text-muted); font-size: var(--t-xs); font-weight: var(--w-bold); }
.calc-context small { color: var(--text-muted); }
.calc-context-construction { justify-items: end; text-align: right; }
.calculation-kpis { display: grid; gap: var(--s-2); }
.calculation-kpis div { display: grid; gap: 2px; padding: var(--s-3); border: 1px solid var(--line); border-radius: var(--r); background: var(--surface-2); }
.calculation-kpis span { color: var(--text-muted); font-size: var(--t-sm); }
/* Okno kalkulacji (BOM) na wąskim ekranie. */
@media (max-width: 980px) {
  /* Sidebar kalkulacji nad obszarem roboczym — 280 px + tabela się nie mieszczą. */
  .calculation-shell { grid-template-columns: minmax(0, 1fr); }
  .calculation-sidebar { position: static; }
}
/* ZNACZNIK „BOM" — jeden i ten sam we WSZYSTKICH miejscach, gdzie wgrywa się BOM:
   edytor konstrukcji (Design), plany (BOM techniczny) i przycisk otwierający okno BOM
   w kalkulatorze. Napis zamiast ikony: żadna ikona w tej aplikacji nie jest wolna,
   a „BOM" czyta się od razu i z niczym nie myli (12.08.2026). */
/* Mniejsza czcionka i ciaśniejsze wcięcie (13.08: przy „Wgraj” był za duży) — etykieta, nie drugi przycisk. W2 (27.09): jedna reguła
   zamiast dwóch po sobie (druga nadpisywała wcięcie, czcionkę i rozstrzelenie pierwszej) — wynik ten sam. */
.bom-znacznik { display: inline-block; padding: 0 3px; border: 1px solid currentColor; border-radius: var(--r-sm); font-size: var(--t-3xs); font-weight: var(--w-bold); letter-spacing: .04em; opacity: .75; }
/* --- Okno materiału: rezerwa, kolory (z dawnego 28, K17) --- */
/* Znak zapytania w rogu panelu zamawiania rozwija kartę pomocy o rezerwie. */
.reserve-help-pop { position: absolute; top: var(--s-2); right: var(--s-2); z-index: 6; }
.reserve-help-pop > summary { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--line)); border-radius: var(--r-pill); background: var(--accent-soft); color: var(--accent-strong); font-size: var(--t-base); font-weight: var(--w-bold); line-height: 1; list-style: none; cursor: pointer; transition: background var(--szybko), border-color var(--szybko), color var(--szybko); }
/* Ujednolicenie 11.08.2026 — znak zapytania reagował TYLKO na otwarcie, pod
   kursorem stał martwy. MUSI stać PRZED regułą `[open]` (ta sama waga 0,2,1),
   inaczej hover zjadałby stan otwarty. */
.reserve-help-pop > summary:hover { border-color: var(--accent-strong); background: color-mix(in srgb, var(--accent) 20%, var(--surface)); }
.reserve-help-pop[open] > summary { background: var(--accent); color: var(--text-invert); }
.reserve-help-pop[open] .reserve-help-card { display: block; }
.reserve-help-card { display: none; position: absolute; top: 26px; right: 0; z-index: var(--z-menu-lokalne); width: min(340px, 80vw / var(--skala-ui)); padding: var(--s-3); border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent); border-radius: var(--r-sm); background: color-mix(in srgb, var(--accent) 7%, var(--surface)); font-size: var(--t-control); line-height: 1.5; box-shadow: var(--cien-2); }
.reserve-help-card strong { display: block; margin-bottom: var(--s-2); font-size: var(--t-base); }
.reserve-help-card p { margin: 0 0 var(--s-2); }
.reserve-field { display: grid; grid-template-columns: minmax(0, 1fr) 150px; align-items: center; gap: var(--s-3); }
.reserve-field > label { margin: 0; font-size: var(--t-base); font-weight: var(--w-bold); white-space: nowrap; }
.reserve-field input[type="number"], .reserve-field select, .reserve-field > .combo { width: 150px; max-width: 150px; justify-self: end; }
.reserve-field input[type="number"] { text-align: right; font-weight: var(--w-bold); }
.reserve-field.is-dimmed { opacity: .45; }
.reserve-pct { position: relative; display: block; width: 150px; justify-self: end; }
.reserve-pct > input[type="number"] { width: 100%; padding-right: 22px; text-align: right; }
.reserve-pct::after { content: "%"; position: absolute; top: 50%; right: var(--s-2); color: var(--text-muted); font-size: var(--t-xs); font-weight: var(--w-bold); transform: translateY(-50%); pointer-events: none; }
.colors-reserve { display: block; margin-top: 2px; }
.colors-reserve-fields { display: grid; max-width: 380px; gap: var(--s-2); }
.colors-reserve-list { line-height: 1.7; }
.colors-reserve-example { margin-top: var(--s-1); padding: var(--s-2) var(--s-3); border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); font-weight: var(--w-bold); }
/* Pomoc do bloków: rysunek po lewej, tekst po prawej; opisy w SVG tokenowe. */
.bh-fig { display: flex; align-items: center; justify-content: center; flex: 0 0 116px; }
.bh-svg { width: 116px; height: auto; }
.bh-emoji { font-size: var(--t-3xl); line-height: 1; }
.bh-txt h3 { margin: 0 0 var(--s-1); font-size: var(--t-md); font-weight: var(--w-bold); }
.bh-txt p { margin: 0 0 var(--s-2); font-size: var(--t-base); line-height: var(--lh-base); }
.bh-list { margin: var(--s-2) 0; padding-left: var(--s-4); }
/* Ujednolicenie 11.08.2026 — margines 3px → --s-1 (4 px). */
.bh-list li { margin: var(--s-1) 0; font-size: var(--t-base); line-height: 1.5; }
.bh-dim, .bh-mul, .bh-op, .bh-cap { font-family: var(--font); font-weight: var(--w-bold); }
.bh-dim { fill: var(--accent); font-size: var(--t-base); }
.bh-mul { fill: var(--accent); font-size: var(--t-xs); }
.bh-op { fill: var(--text-faint); font-size: var(--t-lg); }
/* Ujednolicenie 11.08.2026 — 8,5px → --t-4xs (8 px), najdrobniejszy stopień skali.
   `.bh-op` zostaje na 20px: leży 2 px od --t-lg i 2 px od --t-xl, więc nie ma
   tokenu, w który „wpada" — to znak działania w rysunku pomocy, nie tekst UI. */
.bh-cap { fill: var(--text-faint); font-size: var(--t-4xs); }
.ws-rate-grid { display: grid; grid-template-columns: 128px 92px 176px 116px; justify-content: start; align-items: end; gap: var(--s-3); }
.ws-rate-hint { display: block; margin-top: var(--s-2); color: var(--text-muted); font-size: var(--t-xs); line-height: var(--lh-base); }
.ws-supplier-card strong { display: block; font-size: var(--t-base); font-weight: var(--w-bold); line-height: var(--lh-tight); }
.ws-supplier-card-lines { display: flex; flex-direction: column; gap: 2px; margin-top: var(--s-1); }
.ws-supplier-card-lines span { color: var(--text-muted); font-size: var(--t-xs); }
.ws-supplier-empty { color: var(--text-muted); font-size: var(--t-xs); font-style: italic; }
/* Rozliczenie „od godziny / ryczałt” — dwa pola jako jeden przełącznik. */
/* Ujednolicenie 11.08.2026 — wyściółka toru 3px → --s-1, a wysokość połówki
   28px → --h-control-sm (27). Aplikacja ma DWIE wysokości kontrolek: 32 px
   (kontrolka samodzielna) i 27 px (kontrolka w wierszu/w grupie) — 28 px było
   trzecią, o piksel od tej drugiej. */
.billing-toggle { display: inline-grid; grid-template-columns: repeat(2, minmax(112px, 1fr)); gap: var(--s-1); width: fit-content; max-width: 100%; padding: var(--s-1); border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--surface-3); }
.billing-toggle label { display: inline-flex; align-items: center; justify-content: center; position: relative; min-height: var(--h-control-sm); padding: 0 var(--s-3); border-radius: var(--r-pill); color: var(--text-muted); font-size: var(--t-xs); font-weight: var(--w-bold); white-space: nowrap; cursor: pointer; transition: background var(--szybko), color var(--szybko); }
.billing-toggle input { position: absolute; opacity: 0; pointer-events: none; }
/* Ujednolicenie 11.08.2026 — połówki przełącznika („od godziny" / „ryczałt")
   nie dawały żadnego znaku pod kursorem; widać było tylko wybraną. Waga 0,2,1
   przegrywa z `.billing-toggle label.active` (0,3,1) niżej, więc stan wybrany
   zostaje nietknięty niezależnie od kolejności.
   Fokus klawiaturą: radio jest przezroczyste i bez zdarzeń, więc pierścień
   z 01-reset.css:19 przenosimy na etykietę — inaczej nie widać, gdzie stoi
   kursor klawiatury. */
.billing-toggle label:hover { background: var(--surface); color: var(--text); }
.billing-toggle label:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.billing-toggle label.active { background: var(--accent); color: var(--text-invert); }
.compact-help { padding: var(--s-2); border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-2); color: var(--text-muted); font-size: var(--t-xs); font-weight: var(--w-bold); }
/* --- Okno Kalkulacja: polecenia i marże (z dawnego 28, K17) --- */
/* Okno „Kalkulacja”: dwie kolumny poleceń (plik · rozpoznane kolumny). */
.calculation-command-panel { display: grid; gap: var(--s-3); padding: var(--s-2) var(--s-3); border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface); }
.calculation-command-grid { display: grid; grid-template-columns: minmax(280px, 1.1fr) minmax(260px, .9fr); align-items: start; gap: var(--s-3); }
.calculation-command-section { display: grid; gap: var(--s-2); min-width: 0; }
/* M6 (18.10.2026): na telefonie cała ramka „Plik zestawienia” jest zwijana (`.kst-imp`, 9-telefon/13-zestawienie-okno.css). */
/* Ujednolicenie 11.08.2026 — podpis nagłówkowy do kanonu (--t-2xs / --w-heavy /
   .04em). Był JEDYNYM uppercase w aplikacji BEZ `letter-spacing` — wersaliki
   bez rozstrzelenia zlewają się w blok. Treść to podpisy sekcji („Rozpoznane
   kolumny"), więc wersaliki zostają. */
.calc-command-label { color: var(--text-muted); font-size: var(--t-2xs); font-weight: var(--w-heavy); }
.calculation-margin-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
.calculation-margin-grid > .full { grid-column: 1 / -1; }
@media (max-width: 1180px) {
  .calculation-command-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 980px) {
  .ws-rate-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
:where(:root[data-ui="mobile"]) .reserve-field { grid-template-columns: minmax(0, 1fr); }
:where(:root[data-ui="mobile"]) .calculation-margin-grid { grid-template-columns: minmax(0, 1fr); }
:where(:root[data-ui="mobile"]) .reserve-field input[type="number"], :where(:root[data-ui="mobile"]) .reserve-field select, :where(:root[data-ui="mobile"]) .reserve-field > .combo, :where(:root[data-ui="mobile"]) .reserve-pct { width: 100%; max-width: none; justify-self: stretch; }
