h1:focus {
    outline: none;
}

/*
    K109, decyzje.md — domyślny rozmiar nagłówków TREŚCI STRONY, ustawiony RAZ w warstwie bazowej,
    zamiast klasy dopisywanej na ~30 stronach (odrzucone: to samo utrzymanie w wielu miejscach, a
    każda nowa strona zaczynałaby od tego samego błędu, bo brak klasy nie jest błędem kompilacji).

    Tailwind v4 (BlazorBlueprint, wczytywany PRZED tym plikiem w App.razor) resetuje globalnie
    "h1,h2,h3,h4,h5,h6 { font-size: inherit; font-weight: inherit }". Bez nadpisania, każdy goły
    <h1> dziedziczył rozmiar akapitu (16px) — stąd tytuł strony wyglądał jak zwykły tekst, a żaden
    pasek/breadcrumb nad nim (K105) nie miał się od czego odróżnić. Reguła niżej ma TĘ SAMĄ
    specyficzność (sam typ "h1"), więc wygrywa wyłącznie dzięki kolejności wczytania (ten plik ładuje
    się PO blazorblueprint.css) — potwierdzone testem na skompilowanych plikach, patrz
    HeadingTypographyTests.

    Wartości spójne z istniejącym KodUrDataPage.razor.css (.kodur-data-page__title) — strony na
    tym opakowaniu i bez niego wyglądają teraz tak samo.

    NIE dotyczy nagłówków komponentów biblioteki (karty, okna dialogowe, alerty) — BbCardTitle
    (domyślnie h3), BbDialogTitle/BbSheetTitle/BbAlertDialogTitle (h2), BbAlertTitle (h5) nigdy nie
    renderują się jako <h1> (sprawdzone w źródle BlazorBlueprint), więc bare "h1" ich nie dotyka.
*/
h1 {
    font-size: 1.375rem;
    font-weight: 700;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/*
    T-1515 (K156, decyzje.md) — style dla KodUrFormDialog (Components/Base), przeniesione TUTAJ
    z KodUrFormDialog.razor.css (usunięty), bo CSS izolowany (scoped) nie może ich dotknąć: cała
    treść dialogu renderuje się przez BbDialogPortal, czyli fizycznie w innym miejscu DOM-u niż
    <BbDialog> w KodUrFormDialog.razor (poza BbPortalHost, nie pod nim) — atrybut zasięgu Blazora
    (b-xxxx), który izolacja CSS dopisuje do elementów AUTOROWANYCH W TYM PLIKU, nie ma jak
    dotrzeć do portalowanej podgałęzi, więc ŻADNA reguła z wiodącym "::deep" w tamtym pliku
    faktycznie nie obowiązywała — TA SAMA klasa usterki co [[K110]] (okruszki, 66 wystąpień
    "::deep" bez realnej kotwicy w całym web), potwierdzona tu dekompilacją
    BlazorBlueprint.Primitives/.Components i namierzona dopiero w PRAWDZIWEJ przeglądarce
    (KodUR.Web.UiTests.NewWorkOrderFormScrollTests) — zielony build i zielone testy bUnit (które
    nie liczą CSS/layoutu) nie dawały żadnego sygnału. Globalny, NIEizolowany arkusz jest tu
    świadomym wyborem, nie obejściem: brak parametru biblioteki na wysokość/przewijanie
    (mcp__blazorblueprint, tabela API BbDialogContent) i brak sposobu na kotwicę scoped CSS przez
    portal (sprawdzone, nie zgadywane) nie zostawiają trzeciej opcji.

    Klasy nadawane przez KodUrFormDialog.razor (parametr `Class` — udokumentowany, potwierdzony
    mcp__blazorblueprint — na BbDialogContent/BbDialogHeader/BbDialogFooter) oraz literalne
    elementy autorowane w tym samym pliku (.kodur-form-dialog__body/__skeleton/__steps).
    Nazwy dostatecznie specyficzne (przedrostek "kodur-form-dialog__"), żeby globalny zasięg nie
    kolidował z niczym innym w projekcie (sprawdzone grepem).
*/
.kodur-form-dialog__error {
    margin-bottom: 0.75rem;
}

.kodur-form-dialog__skeleton {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

/* Treść między nagłówkiem a stopką przewija się, obie te części zostają na miejscu —
   .kodur-form-dialog__content jest jedynym elementem z ograniczoną wysokością, żeby przewijanie
   NIE trafiało w overlay/tło dialogu. Zgłoszenie właściciela produktu: formularz dłuższy niż okno
   kończył się w połowie, bez sposobu doscrollowania do stopki z przyciskami. */
.kodur-form-dialog__content {
    display: flex !important;
    flex-direction: column !important;
    max-height: 90vh !important;
    overflow: hidden !important;
}

/* T-1531 (K170, decyzje.md) — DialogSize.Xxl (formularz "Nowe zadanie", właściciel produktu:
   "okno moze byc szersze"). Pierwsza próba użyła nazwy klasy Tailwind "max-w-6xl" (wzorem
   istniejących Sm/Md/Lg/Xl) — ZŁAPANE test PRAWDZIWĄ przeglądarką, nie bUnit: bounding box okna
   wyszedł 504px zamiast oczekiwanych >1000px. Przyczyna sprawdzona grepem spakietowanego,
   PURGED `blazorblueprint.css` (biblioteka wysyła TYLKO klasy max-w-*, których SAMA gdzieś
   używa: sm/md/lg/2xl/4xl/full/max/none — NIE 3xl/5xl/6xl/7xl) — więc "max-w-6xl" była MARTWA
   dokładnie jak K156 (reguła nie istnieje, nie: kotwica nie sięga). Przy okazji sprawdzone (i
   NIEnaprawiane tutaj, poza zakresem T-1531): DialogSize.Fullscreen ma TEN SAM problem —
   "max-w-[95vw]"/"w-[95vw]"/"h-[90vh]" też nie istnieją w paczce, więc ten wariant też jest
   martwy dla żadnego obecnego konsumenta, który by to złapał. Naprawa dla Xxl: własna, jawna
   reguła (ten sam wzorzec co cały ten blok) zamiast zgadywania, która nazwa Tailwind akurat jest
   w paczce — 72rem (1152px, odpowiednik zamierzonego "max-w-6xl") na desktopie, bez wpływu na
   pozostałych 36 konsumentów KodUrFormDialog (osobna klasa, nie zmiana bazowej reguły wyżej).
   Poniżej breakpointu 767px reguła mobilna niżej i tak wygrywa (ta sama specyficzność, dalej w
   pliku) — telefon/tablet portret nie widzi żadnej różnicy. */
.kodur-form-dialog__content--xxl {
    max-width: 72rem !important;
}

.kodur-form-dialog__header,
.kodur-form-dialog__footer {
    flex-shrink: 0;
}

.kodur-form-dialog__content form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

.kodur-form-dialog__body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

.kodur-form-dialog__steps {
    display: flex;
    gap: 1rem;
    margin-bottom: 1rem;
    font-size: 0.8125rem;
    color: var(--kodur-text-muted);
}

.kodur-form-dialog__step--active {
    color: var(--kodur-primary);
    font-weight: 600;
}

@media (max-width: 767px) {
    .kodur-form-dialog__content {
        max-width: 100vw !important;
        width: 100vw !important;
        height: 100vh !important;
        max-height: 100vh !important;
        border-radius: 0 !important;
    }
}

/*
    T-1520 (K173, decyzje.md) — zgłoszenie właściciela produktu: rozwinięta lista pola
    "Przydzielony obszar" (KodUrTreePicker) w oknie "+ Nowy ekran" była ucięta na dolnej krawędzi
    przewijanego obszaru dialogu — widać było tylko "Szukaj..." i połowę pierwszego węzła.
    REGRESJA z T-1515/K156: przed K156 `.kodur-form-dialog__body` nie miało żadnej reguły
    overflow (CSS izolowane, martwe przez portal — patrz komentarz przy .kodur-form-dialog__body
    niżej), więc panel — wtedy zwykły `position: absolute` div wewnątrz tego kontenera — nie był
    niczym ograniczany. K156 przeniosło `overflow-y: auto` do TEGO pliku (nieizolowanego), więc
    reguła zaczęła faktycznie działać po raz pierwszy — i od razu zaczęła ucinać KAŻDEGO potomka
    wystającego poza jej ramkę, position:absolute nie robi wyjątku. Sprawdzone diffem
    KodUrFormDialog.razor.css sprzed K156 (git show <przed>:...razor.css) — potwierdzone, nie
    zgadywane.
    Naprawa: KodUrTreePicker.razor teraz owija wyzwalacz/panel w `BbPopover`/`BbPopoverContent`
    (Strategy=Fixed — domyślna wartość biblioteki, escapuje stacking/overflow context), która
    portaluje treść pod `BbPortalHost`, POZA drzewem DOM dialogu — dokładnie ta sama rodzina co
    `BbDialogPortal` (design-system.md §3 pkt 11), więc panel przestaje być potomkiem
    `.kodur-form-dialog__body` w ŻYWYM DOM-ie i overflow tego kontenera już go nie dotyczy.
    Ponieważ treść jest teraz portalowana, CSS izolowany (`KodUrTreePicker.razor.css`) znowu nie
    ma jak dotrzeć do niej z tego samego powodu co K156 — te reguły idą tutaj (poza samym
    przyciskiem-wyzwalaczem, który NIE jest portalowany i zostaje w pliku izolowanym).
    `!important` tam, gdzie trzeba przebić klasy Tailwind narzucone przez samą `BbPopoverContent`
    (`border`, `bg-popover`, `p-4`, `shadow-md`) — ten sam powód co `!important` na
    `.kodur-form-dialog__content` niżej.
*/
.kodur-tree-picker__skeleton {
    margin-bottom: 0.5rem;
}

.kodur-tree-picker__error {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    color: var(--kodur-status-awaria-fill);
    font-size: 0.875rem;
}

/*
    T-1535 (K263, decyzje.md) — zgłoszenie właściciela produktu: nazwy węzłów w tym panelu ucinane
    wielokropkiem ("Utrzymanie Ruchu - S...", "Pompa dozuj..."). Zmierzone dekompilacją: biblioteka
    (`BbPopoverContent`, Components) nadaje panelowi Tailwind "w-72" (18rem = 288px) NA SZTYWNO,
    niezależnie od `MatchTriggerWidth` — `min-width: 18rem` niżej był przypadkowo tej samej
    wartości i niczego realnie nie zmieniał. `width` tutaj PRZEBIJA "w-72" (ten sam mechanizm
    !important co reszta tego bloku, dla tych samych powodów — patrz komentarz K249/K169 przy
    regułach wcięcia niżej). 24rem (384px) zmierzone (przeglądarka, getBoundingClientRect) jako
    wystarczające, żeby przy mniejszym kroku wcięcia niżej etykieta miała >250px nawet na
    głębokości 6 — poprzednio (288px, krok pełnoekranowego drzewa) na tej głębokości zostawało 138px.
*/
.kodur-tree-picker__panel {
    width: 24rem !important;
    min-width: 18rem !important;
    max-height: 20rem !important;
    overflow-y: auto !important;
    padding: 0.5rem !important;
    border: 1px solid var(--kodur-border) !important;
    border-radius: 0.5rem !important;
    background: var(--kodur-bg-elevated) !important;
    box-shadow: 0 4px 12px rgb(0 0 0 / 0.12) !important;
}

@media (max-width: 767px) {
    .kodur-tree-picker__panel {
        width: 100vw !important;
        position: fixed !important;
        inset: 0 !important;
        margin: 0 !important;
        max-width: 100vw !important;
        max-height: 100vh !important;
        border-radius: 0 !important;
    }
}

/*
    T-1535 (K263, decyzje.md) — krok wcięcia WŁASNY dla tego panelu, mniejszy niż token kroku
    pełnoekranowego drzewa (K249 niżej, wartość 1.25rem). Oba konsumenty renderują IDENTYCZNY
    znacznik `[role="treeitem"][data-depth]` (ta sama biblioteka, `BbTreeView`), więc
    rozróżnienie idzie po przodku fizycznym w DOM — `.kodur-tree-picker__panel` (portalowany
    RAZEM ze swoim poddrzewem przez `BbPopover`, więc relacja przodek-potomek w żywym DOM jest
    zachowana, w odróżnieniu od pułapki K156/K169, gdzie ELEMENT Z KLASĄ zostawał, a potomek
    uciekał gdzie indziej). Selektor z dodatkową klasą ma WYŻSZĄ specyficzność niż generyczna
    reguła `[role="treeitem"][data-depth="N"] > [data-tree-node]` niżej (K249) — wygrywa
    niezależnie od kolejności w pliku, nie tylko dzięki niej.

    Właściciel produktu zaakceptował mniejszy krok jako świadomy kompromis: wcięcia mają pokazywać
    HIERARCHIĘ, nie odmierzać centymetry — 0.75rem nadal daje czytelne schodki. Odrzucone: tooltip
    z pełną nazwą (właściciel produktu, K223 — na tablecie nie ma czym najechać) i zawijanie nazwy
    na dwie linie (różna wysokość wierszy utrudnia trafienie palcem w gęstej liście).
*/
:root {
    --kodur-tree-picker-indent-base: 0.5rem;
    --kodur-tree-picker-indent-step: 0.75rem;
}

.kodur-tree-picker__panel [role="treeitem"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 16) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="0"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 0) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="1"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 1) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="2"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 2) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="3"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 3) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="4"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 4) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="5"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 5) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="6"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 6) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="7"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 7) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="8"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 8) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="9"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 9) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="10"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 10) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="11"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 11) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="12"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 12) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="13"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 13) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="14"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 14) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="15"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 15) !important; }
.kodur-tree-picker__panel [role="treeitem"][data-depth="16"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-picker-indent-base) + var(--kodur-tree-picker-indent-step) * 16) !important; }

/*
    T-1530 (K169, decyzje.md) — zgłoszenie właściciela produktu: "uciety tekst w rozwijalnej
    liście gdy miejsca jeszcze jest, aby był na całej długości okienka" (pole "Kategoria
    problemu", pozycja "Hydrauliczna/pneuma..." ucięta wielokropkiem mimo wolnego miejsca po
    prawej). Przyczyna zdekompilowana (ilspycmd, BlazorBlueprint 3.15.0), nie zgadywana:
    BbSelectItem<TValue> (Components) stawia na WŁASNYM <span> literalną klasę "truncate"
    (nowrap + ellipsis) NA STAŁE — brak parametru, żeby to wyłączyć — a BbSelectContent
    (Primitives) ma domyślnie MatchTriggerWidth=true, udokumentowane wprost w źródle jako
    "common pattern for selects": rozwijana lista jest zawsze tak szeroka jak SAM TRIGGER
    (BbFloatingPortal/MatchAnchorWidth), NIE jak okno dialogu wokół niego — stąd wolne miejsce
    obok. To zachowanie BIBLIOTEKI, nie naszego wrappera, i dotyczy KAŻDEGO z 44 użyć <BbSelect>
    w repo (16 plików pod src/KodUR.Web/Components/Pages, żadne nie nadpisuje
    MatchTriggerWidth) — naprawa idzie raz, tutaj, nie tylko dla pola zgłoszenia.

    Ta sama pułapka co K156/K164 (design-system.md §3 pkt 11): treść BbSelect PORTALUJE się
    (BbFloatingPortal, pod BbPortalHost), więc CSS izolowany/::deep z pliku żadnej strony nie ma
    jak dosięgnąć tego <span> — zwykły globalny arkusz jest jedyną działającą opcją, jak w
    poprzednim bloku wyżej (K156). Selektor "[data-select-content='true']" — atrybut, który
    WYŁĄCZNIE BbSelectContent<TValue>.BuildRenderTree nadaje kontenerowi listy (potwierdzone
    dekompilacją), nie generyczna klasa — dostatecznie wąski, żeby nie dotknąć ".truncate"
    używanego świadomie gdzie indziej w repo (okruszki, K110).

    Rozstrzygnięcie zawijać-czy-uciąć (świadome, nie domyślne): nazwy kategorii/maszyn w tym
    zakładzie bywają długie i podobne ("Utrzymanie Ruchu - Serownia" vs inny dział,
    "Hydrauliczna/pneumatyczna") — technik musi je rozróżnić, a dwie różne pozycje ucięte w tym
    samym miejscu wyglądają identycznie, co jest gorsze niż zawinięta linia. Stąd zawijanie do
    DWÓCH linii (display:-webkit-box + line-clamp — działa też poza WebKit, wspierane szeroko),
    z wielokropkiem jako ostatnią deską ratunku dopiero, gdy tekst realnie nie mieści się nawet
    w dwóch liniach.
*/
[data-select-content="true"] .truncate {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    white-space: normal;
    overflow: hidden;
    overflow-wrap: break-word;
    text-overflow: ellipsis;
}

/*
    T-1535 (K249, decyzje.md) — zgłoszenie właściciela produktu: wcięcia w drzewie aktywów
    (/urzadzenia, /lokalizacje, oraz KodUrTreePicker) renderowały się losowo — węzły z dziećmi w
    jednej kolumnie przy lewej krawędzi, liście z dużym wcięciem. Przyczyna NIE jest w naszym kodzie
    (AssetTreeView/KodUrTreePicker), tylko w BlazorBlueprint 3.15.0: `TreeItemNode<TItem>.NodeStyle`/
    `BbTreeItem.NodeStyle` (Components i Primitives.TreeView, potwierdzone dekompilacją ilspycmd)
    liczą wcięcie jako `$"padding-left: {(double)Depth * 1.25 + 0.5}rem;"` — string-interpolacja
    C# formatuje `double` przez `CultureInfo.CurrentCulture` BIEŻĄCEGO WĄTKU. Ta aplikacja ustawia
    `DefaultCulture: "pl-PL"` (appsettings.json, Program.cs: `UseRequestLocalization`), więc KAŻDY
    render pod domyślnym językiem produkuje separator dziesiętny PRZECINEK: "1,75rem" zamiast
    "1.75rem" — CSS parser przeglądarki odrzuca całą deklarację jako niepoprawną, węzeł dostaje
    computed padding-left:0. Wzór `1.25×depth+0.5` wychodzi liczbą całkowitą (więc przypadkiem
    POPRAWNY) tylko dla depth ≡ 2 (mod 4) — stąd pozornie losowy wzorzec na zrzucie: większość
    poziomów płaska, co czwarty poprawnie zagnieżdżony. Odtworzone wprost (nie zgadywane):
    formuła pod `CultureInfo.GetCultureInfo("pl-PL")` daje dla depth=1 "1,75rem" i depth=3
    "4,25rem" — DOKŁADNIE te same dwa węzły i dokładnie ten sam wynik (computed padding-left: 0px),
    co właściciel produktu zmierzył w DevTools na żywym stosie.

    Nie da się naprawić zmianą globalnej kultury aplikacji (zepsułoby formatowanie dat/liczb w
    całej polskojęzycznej reszcie produktu) ani przez bibliotekę (kod skompilowany, brak parametru
    na kulturę formatowania stylu w BbTreeView — sprawdzone w źródle, changelog do 2026-08-05 nie
    wspomina wcięć/głębokości). Jedyna opcja: własne reguły CSS kluczowane atrybutem `data-depth`
    (liczba całkowita — renderuje się identycznie w KAŻDEJ kulturze, bez separatora dziesiętnego,
    potwierdzone: właściciel produktu widział poprawne `data-depth` na obu zepsutych węzłach).

    Globalnie, NIE w plikach izolowanych (`.razor.css`) komponentów: `KodUrTreePicker` portaluje
    swoje drzewo przez `BbPopover`/`BbPortalHost` (K173 wyżej w tym pliku) — scoped CSS/`::deep`
    nie ma jak dosięgnąć portalowanej podgałęzi (ta sama pułapka co K156/K164/K169). Selektor po
    atrybutach działa niezależnie od miejsca w DOM, więc jeden zestaw reguł naprawia OBU
    konsumentów `BbTreeView` na raz. `!important` przebija inline `style` biblioteki także tam,
    gdzie przypadkiem wyszedł jej poprawny (depth ≡ 2 mod 4) — żeby skala wcięcia była spójna,
    niezależnie od parzystości głębokości, a nie przypadkowo zgodna z biblioteką tylko czasami.

    Głębokość NIE ma górnej granicy: `AssetNodeGrammar` pozwala zagnieżdżać `Component` w
    `Component` rekurencyjnie (`[Component] = [Component, MeasuringPoint]`), więc realna ścieżka
    Company→Site→Area→Department→Location→ProductionLine→Station→Machine→Component→Component→…
    →MeasuringPoint może przekroczyć dowolną skończoną tabelę. Jawne reguły idą do depth 16 (krok
    w jednym tokenie, `--kodur-tree-indent-step`, żeby zmiana skali nie wymagała przeliczania
    wszystkich ręcznie), a reguła NIŻSZEJ specyficzności (bez `[data-depth="N"]`) daje węzłom
    głębszym niż 16 wcięcie ZATRZYMANE na poziomie 16, zamiast spadku do zera — atrybutowe selektory
    CSS nie potrafią policzyć wcięcia z DOWOLNEJ wartości `data-depth` bez JS (odrzucone: `attr()`
    jako liczba w `calc()` nie ma pewnego wsparcia w docelowych przeglądarkach, a to jest dokładnie
    ten rodzaj założenia, które już raz zawiodło w tym pliku — patrz K169 wyżej, "max-w-6xl" które
    nie istniało). Zatrzymanie na 16 zamiast spadku do 0 nie jest idealne (bardzo głębokie węzły
    nie odróżniają się dalej wizualnie), ale nie jest to regresja zgłoszonego błędu — nigdy nie
    wygląda jak płaska kolumna.
*/
:root {
    --kodur-tree-indent-base: 0.5rem;
    --kodur-tree-indent-step: 1.25rem;
}

/* Zapasowa reguła dla depth > 16 — niższa specyficzność niż `[data-depth="N"]` niżej, więc jawne
   wpisy w tabeli zawsze wygrywają tam, gdzie istnieją; poza tabelą węzeł dostaje wcięcie
   ZATRZYMANE na poziomie 16 zamiast spadku do zera. */
[role="treeitem"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 16) !important; }

[role="treeitem"][data-depth="0"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 0) !important; }
[role="treeitem"][data-depth="1"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 1) !important; }
[role="treeitem"][data-depth="2"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 2) !important; }
[role="treeitem"][data-depth="3"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 3) !important; }
[role="treeitem"][data-depth="4"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 4) !important; }
[role="treeitem"][data-depth="5"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 5) !important; }
[role="treeitem"][data-depth="6"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 6) !important; }
[role="treeitem"][data-depth="7"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 7) !important; }
[role="treeitem"][data-depth="8"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 8) !important; }
[role="treeitem"][data-depth="9"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 9) !important; }
[role="treeitem"][data-depth="10"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 10) !important; }
[role="treeitem"][data-depth="11"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 11) !important; }
[role="treeitem"][data-depth="12"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 12) !important; }
[role="treeitem"][data-depth="13"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 13) !important; }
[role="treeitem"][data-depth="14"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 14) !important; }
[role="treeitem"][data-depth="15"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 15) !important; }
[role="treeitem"][data-depth="16"] > [data-tree-node] { padding-left: calc(var(--kodur-tree-indent-base) + var(--kodur-tree-indent-step) * 16) !important; }

/*
    T-1535 (K265, decyzje.md) — koordynator zmierzył: 23 strony pod `Components/Pages` nie mają
    WŁASNEGO pliku `.razor.css` (K264, `PartRequestListPage`, było jedną z nich — naprawione
    osobno). Własny pomiar (skrypt po plikach `.razor`, nie zgadywanie) zawęża to: **10 z tych 23
    JUŻ korzysta z `<KodUrDataPage>`** (Audyt×2, Druk/LabelRegistryPage, Druk/PrinterSettingsPage,
    Magazyn/StockDocumentsPage, Magazyn/StockLedgerPage, Powiadomienia, Prewencja/PmScheduleListPage,
    Ustawienia/Użytkownicy, Ustawienia/Zespoły) — ten komponent NIESIE WŁASNY układ
    (`KodUrDataPage.razor.css`, `.kodur-data-page*`), więc te strony mają spójny wygląd mimo braku
    OSOBNEGO pliku CSS; to były fałszywe trafienia prostego skanu "brak .razor.css" = "brak stylu".

    Prawdziwa luka to jedenaście stron, które NIE mają ani własnego arkusza, ani `<KodUrDataPage>`:
    Auth/MojProfilPage, Druk/BulkPrintPage, Kwalifikacje/KwalifikacjeListPage,
    Magazyn/Mapa/WarehouseMapIndexPage, Magazyn/PartDetailsPage, Magazyn/Struktura/WarehouseStructurePage,
    Prewencja/PmScheduleCalendarPreviewPage, Przestoje/PrzestojeListPage,
    Raporty/QualificationComplianceExtractPage, Ustawienia/Tlumaczenia/TlumaczeniaPage,
    Zapotrzebowania/PartRequestDetailPage — sprawdzone grepem, każda odtwarza WŁASNYMI, unikalnymi
    prefiksami (np. `.kwalifikacje__`, `.przestoje__`) DOKŁADNIE te same siedem reguł co
    `.andon__*` (`AndonListPage.razor.css`), `.zapotrzebowania__*` (K264) i `.kodur-data-page__*`
    (`KodUrDataPage.razor.css`) — nagłówek z tytułem i paskiem narzędzi, prosta tabela,
    sekcja-etykieta, szkielet ładowania. Trzy niezależnie napisane pliki, prawie identyczne reguły
    pod różnymi nazwami — dokładnie ryzyko, przed którym ostrzegał koordynator (N stron, N prawie
    takich samych arkuszy, N+1-sza strona i tak kiedyś powstanie bez żadnego).

    Wyjątki świadome, NIE część tej luki (sprawdzone treścią pliku, nie zgadywane): `Scan/ScanRouter`
    ma wprost w KOMENTARZU WŁASNYM zastrzeżenie "celowo BEZ komponentów BlazorBlueprint... wizualnie
    minimalna", udokumentowane osobno w `docs/modules/kody.md` — to nie jest przeoczenie. `Auth/Login`,
    `Auth/Logout`, `PublicComplaintPortal` używają INNEGO layoutu (`PublicPortalLayout`, ekran
    logowania/portal publiczny) — inny system wizualny, poza zakresem tego mechanizmu (list roboczych
    wewnątrz aplikacji), nie porównywane do `.andon`/`.wo-form`.

    Mechanizm — GLOBALNE, DODATKOWE klasy (`kodur-page*`), zamiast N-tego prawie identycznego pliku
    `.razor.css`. Istniejące strony (`.andon`, `.zapotrzebowania`, `.zapotrzebowania-overview`,
    `KodUrDataPage`) NIE są tu ruszane — zero ryzyka regresji na czymś, co już działa; nowa albo
    naprawiana strona może użyć tych klas WPROST zamiast pisać własny plik tylko po to, żeby
    odtworzyć te same siedem reguł po raz kolejny. Migracja jedenastu stron z luki NIE jest częścią
    TEGO wpisu — sekwencja i kolejność (Przestoje, Zapotrzebowania/PartRequestDetailPage,
    Ustawienia/Tłumaczenia, potem reszta) idzie osobno, po akceptacji koordynatora/właściciela
    produktu tego mechanizmu (zgłoszenie wprost: "zgłoś się PO wspólnym mechanizmie, przed
    przepisywaniem wszystkich stron").
*/
.kodur-page {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.kodur-page__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.kodur-page__toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* K289 (decyzje.md) — powrót ze szczegółu po przewijaniu bez końca (KodUrDataPage.InfiniteScroll):
   krótkotrwałe podświetlenie wiersza, do którego wraca `scrollToAndHighlight`
   (wwwroot/js/infinite-scroll.js). GLOBALNA, nie scoped — element podświetlany (<tr> renderowany
   przez BbDataGrid) nie żyje w zasięgu żadnego pojedynczego pliku .razor.css, więc scoped reguła
   nigdy by go nie dopasowała (ta sama klasa problemu co K105/K110 — kotwica scoped CSS musi
   fizycznie istnieć w drzewie tego samego pliku). Zdejmowana przez JS po 2 sekundach. */
.kodur-data-page__row--highlighted {
    animation: kodur-data-page-row-highlight 2s ease-out;
}

@keyframes kodur-data-page-row-highlight {
    from {
        background-color: color-mix(in srgb, var(--kodur-status-realizacja-fill, #3b82f6) 25%, transparent);
    }
    to {
        background-color: transparent;
    }
}

/* K280/K281 (decyzje.md) — wiersz okruszków + krzyżyk powrotu (KodUrCloseButton) na ekranach
   szczegółu (Zadania/Magazyn-części/Prewencja); DOKŁADNIE ten sam kształt co .kodur-page__header
   wyżej, osobna nazwa celowo — semantycznie inny wiersz (nad danymi strony, nie w nich), a te dwa
   mogą współistnieć na tej samej stronie. */
.kodur-page__breadcrumb-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.kodur-page__section {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* Pola formularza obok siebie — wzorem `.wo-form__row` z `NewWorkOrderForm.razor.css`, DRUGI
   niezależny konsument tego samego kształtu (Druk/BulkPrintPage, K265). Nazwa CELOWO inna niż
   `.kodur-page__row` niżej (ten sam token "row" oznacza tam klikalny WIERSZ TABELI — cursor
   pointer + hover — kolizja nazw omal nie nadała formularzowym polom kursora łapki). */
.kodur-page__field-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
}

.kodur-page__section > span:first-child,
.kodur-page__label {
    font-weight: 600;
    font-size: 0.875rem;
}

.kodur-page__actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.kodur-page__hint {
    font-size: 0.8125rem;
    color: var(--kodur-text-muted, #64748b);
    margin: 0;
}

/* Lista par etykieta-wartość (<dl>/<dt>/<dd>) — wzorem `.wo-detail__grid` z
   `WorkOrderDetailPage.razor.css`, DRUGI niezależny konsument tego samego kształtu
   (Magazyn/PartDetailsPage, K265), więc idzie tu zamiast zostać zduplikowany po raz trzeci. */
.kodur-page__grid {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.25rem 1rem;
}

.kodur-page__grid dt {
    font-weight: 600;
    color: var(--kodur-text-muted, #64748b);
}

.kodur-page__skeleton {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.kodur-page__table {
    width: 100%;
    border-collapse: collapse;
}

.kodur-page__table th,
.kodur-page__table td {
    padding: 0.5rem;
    border-bottom: 1px solid var(--kodur-border, #e2e8f0);
    text-align: left;
    vertical-align: top;
}

.kodur-page__row {
    cursor: pointer;
}

/*
    T-1535 (K265, decyzje.md) — `Ustawienia/Tlumaczenia/TlumaczeniaPage.razor` (ostatnia strona
    z bazowego długu) przekazuje "w-48" jako `Class` do `<BbSelect>`, licząc na Tailwind. Zmierzone
    grepem w spakietowanym `blazorblueprint.css`: klasa NIE ISTNIEJE — dokładnie pułapka [[K169]]/
    [[K170]] ("max-w-6xl"), tym razem trafiona przy okazji przeglądu długu K265, nie osobnym
    zgłoszeniem właściciela produktu. Idzie GLOBALNIE (nie do `TlumaczeniaPage.razor.css`), bo cel
    to element renderowany przez `<BbSelect>` (komponent BIBLIOTEKI) — ta sama ostrożność co
    K156/K169 (niepewne, czy scoped CSS dotrze przez granicę komponentu z innego assembly).
*/
.tlumaczenia-page__jezyk {
    width: 12rem;
}

.kodur-page__row:hover {
    background: var(--kodur-surface-hover, rgba(0, 0, 0, 0.04));
}

/*
    T-1535 (K283-K285, decyzje.md) — treść popovera pełnej ścieżki w `KodUrAssetPath` (rozwinięcie
    ucietej ścieżki na dotyk/klik, wzorem K223 — BbPopover, nie BbTooltip/hover). GLOBALNIE, nie w
    `KodUrAssetPath.razor.css`: `BbPopoverContent` portaluje swoją treść przez `BbFloatingPortal`
    (K173/K249/K263 — ta sama pułapka), więc scoped CSS z pliku komponentu by tu nie dotarł.
    `width` nadpisuje sztywne "w-72" biblioteki (18rem — DOKŁADNIE ten sam mechanizm co K263 dla
    `.kodur-tree-picker__panel`, ten sam powód: `MatchTriggerWidth` niepodany, biblioteka i tak
    wymusza stałą szerokość) — szerszy, żeby typowa ścieżka (kilka segmentów) zmieściła się w jednej
    lub dwóch liniach zamiast wielu wąskich. `flex-wrap` na wewnętrznym `<ol>` jest już domyślne w
    bibliotece (zdekompilowane `BbBreadcrumb.BuildRenderTree`, klasa "flex flex-wrap..." na stałe),
    więc nie trzeba tego dublować tutaj.
*/
.kodur-asset-path__popover {
    width: 22rem !important;
    max-width: 90vw !important;
}

/*
    T-1535 (K283-K285, decyzje.md) — przycisk-wyzwalacz popovera pełnej ścieżki. GLOBALNIE, nie w
    `KodUrAssetPath.razor.css`: `class`/`aria-label` idą jako atrybuty NIEDOPASOWANE na
    `<BbPopoverTrigger AsChild="false">`, przekazywane DALEJ przez DWIE warstwy komponentów
    (styled wrapper → headless prymityw `Primitives.Popover.BbPopoverTrigger`, potwierdzone
    dekompilacją obu) na `<button>`, który renderuje SAM prymityw z INNEGO assembly — ten sam
    rodzaj niepewności co do zasięgu CSS izolowanego co K156/K169/K265 (`.tlumaczenia-page__jezyk`),
    tylko o jedną warstwę głębiej, więc global jest jedyną PEWNĄ opcją.

    Świadomie INNY wygląd niż `.pokoj-maszyna-kafelek__sygnal` z K223 (tam: "wygląda jak zwykły
    tekst, nie jak kontrolka") — właściciel produktu w TYM zgłoszeniu wprost zastrzegł coś
    przeciwnego: "nie tylko trzy kropki, o które trzeba wpaść przypadkiem" — więc tło+kolor przy
    najechaniu/fokusie mają jawnie sygnalizować klikalność.
*/
.kodur-asset-path__ellipsis {
    border: none;
    background: var(--kodur-surface-hover, rgba(0, 0, 0, 0.04));
    border-radius: 0.375rem;
    padding: 0;
    cursor: pointer;
    color: var(--kodur-text-muted);
}

.kodur-asset-path__ellipsis:hover,
.kodur-asset-path__ellipsis:focus-visible {
    background: var(--kodur-border, #e2e8f0);
    color: var(--kodur-primary);
}