﻿:root {
    /* odstępy elementów na formach */
    --rz-gap: .75rem !important;
    /* ciaśniejszy odstęp wewnętrzny paneli zakładek */
    --rz-tabs-padding: 0.5rem !important;
    /* kolor karty (domyślnie taki sam, jak nagłówek grida, żeby uwzględniać motyw) */
    --hydra-card-background-color: var(--rz-grid-header-background-color);
    /* brak ramki outline dla komponentów na focus (poza inputami, które mają border) */
    --rz-outline-focus: none !important;
    /* kolory tła i czcionki ekranu logowania — referencowane też z LoginLayout w Aquili */
    --sente-login-background-color: #f3f6f9;
    --sente-login-font-color: var(--rz-text-primary-color);
}

/* ustawienia dla kontrolek przy logowaniu */
.sente-login-input {
    --rz-input-value-color: var(--sente-login-font-color);
    --rz-form-field-label-floating-background-color: var(--sente-login-background-color);
}

/* forma logowania */
.rz-login .rz-form {
    gap: var(--sente-login-gap) !important;
    background-color: var(--sente-login-background-color);
    color: var(--sente-login-font-color);
}

.rz-header {
    padding: .25rem !important;
    box-shadow: none !important;
}

.rz-sidebar {
    border-inline-end-width: 0 !important;
}

.rz-sidebar-expanded {
    box-shadow: var(--rz-header-shadow);
    z-index: 3 !important;
}

/* Prawy sidebar (AI chat) — ponad dialog mask (1000), aby czat był aktywny przy otwartym dialogu */
.rz-sidebar-expanded[style*="rz-right-sidebar"] {
    z-index: 1002 !important;
    position: relative;
}

/* padding i margin dla body */
.rz-body {
    --rz-layout-body-padding: .25rem;
    --rz-layout-body-margin: 0;
}

.container,
.container-fluid,
.container-lg,
.container-md,
.container-sm,
.container-xl,
.container-xxl {
    --bs-gutter-x: .5rem;
}

/* nagłówek grida */
.sente-grid-header {
    --rz-gap: .25rem !important;
}

/* Input wyszukiwania ma domyślnie 40px (--rz-input-height), a przyciski akcji paska
   (Medium) 36px (2.25rem). Pokazanie wyższego inputu rozpychało rząd i powodowało
   "skok" paska w górę o kilka pikseli — wyrównujemy wysokość inputu do przycisków. */
.sente-grid-header .rz-textbox {
    height: 2.25rem !important;
}

/* padding nagłówka grida */
.rz-group-header {
    --rz-grid-group-header-padding: .5rem;
}

/* wysokość wierszy grida - dla uspójnienia */
.rz-data-row {
    height: 2.25rem !important;
}


.rz-group-row {
    height: 2rem !important;
}

/* zwiększona czcionka w gridzie (dla układu Compact) */
.rz-datatable-data td .rz-cell-data,
.rz-grid-table td .rz-cell-data {
    --rz-grid-cell-font-size: 0.9375rem;
    --rz-grid-cell-line-height: 1.25rem;
}

.rz-datatable-thead th .rz-column-title,
.rz-grid-table thead th .rz-column-title {
    --rz-grid-header-font-size: 0.9375rem;
}

.rz-datatable-loading {
    background-color: inherit !important;
}
/* padding dla dolnego panelu podsumowania grida - uspójnienie z pozostałymi elementami grida */
.rz-paginator.rz-density-compact {
    --rz-paginator-padding: 0.5rem !important;
}

/* Dopóki nie znamy dokładnej liczby wierszy, nie wiemy też, która strona jest ostatnia — chowamy przycisk
   "ostatnia strona". Pager wylicza liczbę stron z licznika, więc na liczniku minimalnym przycisk prowadziłby
   tam, gdzie "następna". Znacznik hydra-count-unknown renderuje podsumowanie (GridRowCountSummary) wewnątrz pagera;
   pozostałe trzy przyciski nawigacji zostają. */
.rz-pager:has(.hydra-count-unknown) .rz-pager-last {
    display: none;
}

/* Lista numerów stron powstaje z licznika, więc przy liczniku minimalnym pokazuje numery do bieżącej strony plus
   jedną następną — tę, której istnienie dowiodła sonda: „1 2", na stronie 3 „1 2 3 4". Lista nie pamięta
   odwiedzonych stron: po powrocie na pierwszą znów pokazuje „1 2". Za ostatnim numerem dokładamy wielokropek
   jako sygnał, że stron może być więcej. Wielokropek ma szerokość numeru strony, ale nie jest przyciskiem.

   Lista jest kontenerem flex, który domyślnie rozciąga pozycje do najwyższej z nich — wielokropek nie może więc
   być wyższy od numerów, bo pastylka bieżącej strony zamieniłaby się w wydłużony owal, a numery uciekłyby ponad
   strzałki. Dlatego wielokropek nie ma paddingu w pionie, ma wysokość jednej linii i jest wyśrodkowany, a zamiast
   „…" (kropki na linii bazowej, wiszące pod numerami) składamy go z kropek środkowych „···". */
.rz-pager:has(.hydra-count-unknown) .rz-pager-pages {
    align-items: center;
}

.rz-pager:has(.hydra-count-unknown) .rz-pager-pages::after {
    content: "\00B7\00B7\00B7";
    align-self: center;
    min-width: var(--rz-pager-numeric-button-min-width);
    line-height: 1;
    letter-spacing: 0.1em;
    text-align: center;
    color: var(--rz-pager-numeric-button-color);
}

/* Radzen centruje grupę przycisków parą marginesów auto: na "pierwszej" (od lewej) i na "ostatniej" (od prawej).
   Ukrycie "ostatniej" zabiera prawy margines, więc całą wolną przestrzeń zjada lewy i grupa ucieka w prawo —
   oddajemy margines przyciskowi, który po ukryciu jest ostatni w grupie. */
.rz-pager.rz-align-center:has(.hydra-count-unknown) .rz-pager-next {
    margin-inline-end: auto;
}

/* Podsumowanie i stojący obok przycisk (liczący albo przeliczający) trzymamy w jednej linii. */
.hydra-pager-summary {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
}

.sente-grid-row-green {
    background-color: var(--rz-success-lighter) !important;
}

.sente-grid-row-yellow {
    background-color: var(--rz-warning-lighter) !important;
}

.sente-grid-row-rose {
    background-color: var(--rz-danger-lighter) !important;
}

.sente-grid-row-blue {
    background-color: var(--rz-info-lighter) !important;
}

/* okna dialogowe */
.rz-dialog {
    /* kolor tła, żeby był taki sam jak tło labelek w FormField */
    background-color: var(--rz-body-background-color);
    --rz-dialog-background-color: var(--rz-body-background-color);
}

.rz-dialog-title {
    /* pogrubiona czcionka nagłówka okna dialogowego */
    --rz-dialog-title-font-weight: 500;
    /* kolor tła, żeby był taki sam jak tło labelek w FormField */
    background-color: var(--rz-body-background-color);
    --rz-dialog-title-background-color: var(--rz-body-background-color);
    /*powstrzymanie najeżdżania tytułu na przycisk zamykania okna*/
    display: block !important;
    margin-right: 2.5rem;
}

.rz-dialog-titlebar {
    /* kolor tła, żeby był taki sam jak tło labelek w FormField */
    background-color: var(--rz-body-background-color);
    --rz-dialog-title-background-color: var(--rz-body-background-color);
}

.rz-dialog-content {
    --rz-dialog-content-padding: 1.25rem;
    display: flex !important;
    flex-direction: column;
    height: 100%;
    /* kolor tła, żeby był taki sam jak tło labelek w FormField */
    background-color: var(--rz-body-background-color);
}

/* forma z układem pionowym flex, żeby można było sterować odstępami */
.rz-form {
    display: flex;
    flex-direction: column;
    gap: var(--rz-gap);
    height: 100%;
    width: 100%;
}

/* klasa przypisywana dla wieszy, które mają wypełnić całą szerokość rodzica */
.sente-row-full-parents-width {
    width: 100%;
}

/* klasa przypisywana dla kolumn, które mają wypełnić całą wysokość rodzica */
.sente-column-full-parents-height {
    height: 100%;
}

.rz-text-subtitle1 {
    --rz-card-heading-margin-bottom: 0rem;
}

/* klasa ustawiająca się na dowolny komponent, robiąc jego wysokość 100% */
.hydra-fill-height {
    height: 100%
}

/* klasa ustawiająca się na dowolny komponent, robiąc jego szerokość 100% */
.hydra-fill-width {
    width: 100%
}

/* klasa przypisywana do nieaktywnych ikonek sortowania, która je ukrywa
   widać tylko, jeżeli sortowanie jest zastosowane na kolumnie */
span[class~="rz-sortable-column-icon"]:not(.rzi-sort-asc):not(.rzi-sort-desc) {
    display: none !important;
}

/* klasa przypisywana do nieaktywnych ikonek filtrowania, która je ukrywa*/
i[class~="rz-grid-filter-icon"] {
    display: none !important;
}

/* klasa przypisywana do nieaktywnych ikonek sortowania, po najechaniu na nagłówek kolumny grida, która pokazuje te ikonki */
th:hover span[class~="rz-sortable-column-icon"] {
    display: block !important;
}

/* klasa przypisywana do nieaktywnych ikonek filtrowania, po najechaniu na nagłówek kolumny grida, która pokazuje te ikonki */
th:hover i[class~="rz-grid-filter-icon"] {
    display: block !important;
}

/* klasa przypisywana do aktywnych ikonek filtrowania */
i[class~="rz-grid-filter-active"] {
    display: block !important;
}

/* klasa przypisywana do ikonek filtrowania, która usuwa domyślny margines*/
.rzi.rz-grid-filter-icon {
    margin: 0 !important
}

/* kolor tła przypiętej kolumny grida */
.rz-grid-table-fixed td.rz-frozen-cell-left,
.rz-grid-table-fixed td.rz-frozen-cell-right,
.rz-grid-table-fixed td.rz-frozen-cell-left-inner,
.rz-grid-table-fixed td.rz-frozen-cell-right-inner {
    background: transparent;
}

/* komponent wewn. RadzenSteps */
.rz-widget-content {
    padding: 1rem 0;
}

/* komponent przycisków RadzenSteps */
.rz-steps-buttons {
    --rz-steps-buttons-padding: 1rem 0 0 0;
}

.rz-card {
    background-color: var(--hydra-card-background-color) !important;
}

/* styl rozwijanej akcji na rekordzie */
.hydra-expanded-action {
    padding: 10px;
}

/* styl aktywnej rozwijanej akcji na rekordzie */
.hydra-active-expanded-action {
    cursor: pointer;
}

.hydra-active-expanded-action:hover {
    background-color: var(--rz-base-300);
}

/* styl nieaktywnej rozwijanej akcji na rekordzie */
.hydra-inactive-expanded-action {
    opacity: var(--rz-dropdown-item-disabled-opacity);
    cursor: default;
}

/* styl nieaktywnego przycisku zapisu — wygaszenie bez atrybutu disabled, żeby kliknięcie dochodziło */
.hydra-inactive-submit {
    opacity: var(--rz-dropdown-item-disabled-opacity);
    cursor: default;
}

/* maksymalna możliwa wysokość panelu zawartości zakładek */
.rz-tabview-panel {
    height: 100%;
    min-height: 0;
}
    
.rz-tabview.rz-tabview-top {
    height: 100%;
    min-height: 0;
}

/* brak niebieskiej ramki przy focusie grida */
.rz-data-grid {
    outline: none !important;
}

.rz-data-grid-data {
    outline: none;
}

/* Radzen zdejmuje ramkę z ostatniego wiersza; prefiks .rz-data-grid wygrywa z motywem, który ładuje się po sente.css */
.rz-data-grid .rz-grid-table:not(.rz-grid-gridlines-none):not(.rz-grid-gridlines-vertical) > tbody > tr:last-child > td {
    border-bottom: var(--rz-grid-bottom-cell-border);
}

/* brak paddingu po lewej stronie przy nazwie kolumny wyrównanej do prawej */
.rz-grid-table thead th.rz-text-align-right.rz-sortable-column .rz-column-title {
    padding-inline-start: 0 !important;
}

/* brak wyświetlania floating-label i ramki dla chechboxów w formfield */
.hydra-bool-form-field .rz-form-field-label {
    display: none;
}

.hydra-bool-form-field .rz-form-field-content:before {
    display: none;
}

.hydra-bool-form-field .rz-form-field-content:after {
    display: none;
}

/* ===== Kompaktowe kontrolki w toolbarze nad gridem (HydraDataGridToolbar) ===== */

/* usunięcie górnego marginesu FormField Outlined w toolbarze —
   margines rezerwuje miejsce na floating label, który w toolbarze wychodzi ponad element
   (position: absolute), więc rezerwacja jest zbędna */
.hydra-datagrid-toolbar .rz-form-field-content {
    margin-block-start: 0;
}

/* wymuszenie minimalnej wysokości dropdowna w FormField na toolbarze —
   w trybie tekstowym ("N elementów wybrano") dropdown ma tylko 32px (content-sized),
   podczas gdy inne kontrolki mają 40px (--rz-input-height). Min-height wyrównuje wysokość
   we wszystkich trybach: tekst, chipy, placeholder */
.hydra-datagrid-toolbar .rz-form-field .rz-dropdown {
    min-height: var(--rz-input-height);
}

/* usunięcie wewnętrznego spacera FormField Outlined (.rz-form-field-start, 12px) —
   bez niego dropdown wypełnia FormField od krawędzi, a własny padding-inline zapewnia
   wyrównanie tekstu z pozostałymi kontrolkami (~15px od ramki) */
.hydra-datagrid-toolbar .rz-form-field-content .rz-form-field-start {
    display: none;
}

/* wyrównanie left-padding dropdowna w FormField —
   .rz-dropdown-chips w Radzen ma mniejszy padding (~7px) niż standardowy .rz-dropdown (15px).
   Po usunięciu spacera trzeba wymusić 15px, aby tekst/chipy startowały na tej samej
   pozycji co placeholder w Date/Status kontrolkach */
.hydra-datagrid-toolbar .rz-form-field .rz-dropdown.rz-dropdown-chips {
    padding-inline-start: 15px;
}

/* redukcja paddingu kontenera chipów w multi-select dropdownach na toolbarze —
   domyślny padding-block (7px) + chip (28.88px) = 42.88px przekracza bazową wysokość (41.33px).
   :has(.rz-chip) celuje TYLKO gdy są widoczne chipy — tryb tekstowy i placeholder
   dziedziczą domyślny padding Radzen, więc wyrównanie z innymi kontrolkami jest automatyczne */
.hydra-datagrid-toolbar .rz-dropdown-chips:has(.rz-chip) {
    padding-block: 0.25rem;
}

.hydra-datagrid-toolbar .rz-dropdown-chips .rz-chip {
    padding-block: 0;
}

.user-message {
    background-color: var(--rz-panel-menu-item-2nd-level-active-background-color);
    padding: 16px;
    border-radius: 16px;
    border-top-right-radius: 0px;
    margin-left: 2rem;
    margin-top: 1rem;
    position: relative;
}

.user-message::after {
    content: '';
    position: absolute;
    top: 0px;
    right: -12px;
    width: 0;
    height: 0;
    border-left: 12px solid var(--rz-panel-menu-item-2nd-level-active-background-color);
    border-bottom: 16px solid transparent;
}

.agent-message {
    font-size: 12px;
    font-weight: 300;
    opacity: 0.6;
    letter-spacing: 0.02em;
        border-width: 1px;
        border-style: solid;
        border-color: var(--rz-base-400);
        padding: 0.5rem;
        padding-left: 1.25rem;
        border-radius: 0.5rem;
        background-color: var(--rz-body-background-color);
}

.agent-message b {
    font-weight: 500;
}

.agent-message summary {
    margin-left: -0.75rem;
}

.minor-agent-message {
    font-size: 12px;
    font-weight: 300;
    opacity: 0.5;
    letter-spacing: 0.02em;
    }
    
    .minor-agent-message b {
        font-weight: 500;
}

.hover-border .rz-dropdown {
    border-color: transparent !important;
    transition: border-color 0.2s ease-in-out;
}

.hover-border:hover .rz-dropdown {
    border-color: var(--rz-input-border-color) !important;
}

.chat-area {
    font-size: var(--rz-panel-menu-font-size);
    color: var(--rz-panel-menu-item-color);
    opacity: 1;
    position: relative;
    -webkit-mask-image: linear-gradient(to bottom,
            transparent 0%,
                black 1rem,
                black calc(100% - 1rem),
                transparent 100%);
                mask-image: linear-gradient(to bottom,
                            transparent 0%,
                            black 1rem,
                            black calc(100% - 1rem),
                            transparent 100%);
}

.chat-area h1 {
    font-size: 1.4em;
    opacity: 1.2;
}

.chat-area h2 {
    font-size: 1.2em;
    opacity: 1.2;
}

.chat-area h3 {
    font-size: 1.1em;
    opacity: 1.2;
}

.chat-area h4 {
    font-size: 1em;
    opacity: 1;
}

.chat-area h5 {
    font-size: 1em;
    opacity: 0.8;
}

.chat-area h6 {
    font-size: 1em;
    opacity: 0.6;
}

.chat-area a {
    color: var(--rz-link-color);
}

.chat-area a:hover {
    color: var(--rz-link-color-hover);
}

.chat-area table {
    width: 100%;
    border-collapse: collapse;
    margin: 1em 0;
    font-size: 0.97em;
}

.chat-area th,
.chat-area td {
    border: 1px solid var(--rz-base-400);
    padding: 0.5em 0.75em;
    text-align: left;
}

.chat-area th {
    background-color: var(--rz-panel-menu-item-2nd-level-active-background-color);
    font-weight: 500;
}

.chat-area pre {
    background-color: transparent;
    margin-top: 0.5em;
    margin-left: 0;
    margin-bottom: 0;
    padding-left: 0;
        line-height: normal;
}

.chat-area pre p {
    margin-bottom: 0;
}

.chat-status {
    display: inline-grid;
    place-items: center;
    width: 1em;
    height: 1em;
    vertical-align: text-top;
    line-height: 1;
    box-sizing: border-box;
    border: 2px solid transparent;
    border-radius: 50%;
}

.chat-status.loader {
    border-color: currentColor;
    border-top-color: transparent;
    animation: spin 0.7s linear infinite;
}

.chat-status.pending {
    border-color: currentColor;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

.chat-status.success::before,
.chat-status.error::before,
.chat-status.warning::before {
    content: '';
    display: block;
    width: 150%;
    height: 150%;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
}

.chat-status.success::before {
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3 8.5 L6.5 12 L13 5' fill='none' stroke='green' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.chat-status.error::before {
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 4 L12 12 M12 4 L4 12' fill='none' stroke='red' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
}

.chat-status.warning::before {
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 3 L14 13 L2 13 Z' fill='none' stroke='%23e6a117' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cline x1='8' y1='7' x2='8' y2='10' stroke='%23e6a117' stroke-width='1.5' stroke-linecap='round'/%3E%3Ccircle cx='8' cy='11.5' r='0.7' fill='%23e6a117'/%3E%3C/svg%3E");
}
/* Notyfikacje — przy dolnej krawędzi, przesunięcie w lewo o szerokość prawego sidebara + wyższy z-index aby nie były zasłaniane */
.rz-notification {
    z-index: 1003 !important;
    inset-block-start: auto !important;
    inset-block-end: 1rem !important;
    inset-inline-end: calc(var(--right-sidebar-width, 0px) + 1rem) !important;
}

/* Jeśli wiadomość w powiadomieniu jest wyjątkowo długa, to ograniczamy ją wysokościowo ze scrollem */
.rz-notification-message {
    max-height: 20vh;
    overflow-y: auto;
    overflow-wrap: anywhere;
}

.rz-fileupload-files>div {
    display: flex;
    flex-wrap: wrap;
    column-gap: 2em;
}

.rz-arc-gauge-value {
    font-weight: 600;
    font-size: larger;
}

/* Obrócone etykiety osi kategorii (LabelRotation=90) były ucinane.
   Radzen wymierza pas pod osią z WYSOKOŚCI etykiety, a nie z jej długości po obrocie, więc tekst
   wychodzi poniżej ramki SVG — a inline SVG domyślnie ma overflow:hidden i go przycina.
   Zmierzone: przy foncie 12 px brakuje 6 px, przy 16 px już 14 px (deficyt rośnie z fontem),
   dlatego pozwalamy etykiecie wyjść poza SVG i rezerwujemy na nią pas w kontenerze.
   Ani LabelAutoRotation, ani zwiększenie Padding osi tego nie załatwiają — sprawdzone pomiarem. */
.hydra-chart-canvas svg {
    overflow: visible;
}

.hydra-chart-canvas {
    padding-bottom: 1.5rem;
}
/* AI Conversation - Navigation Link Styles.
   Odnośnik z odpowiedzi sub-agenta (reference-link-*) dzieli wygląd z linkiem nawigacyjnym: oba są
   zwykłymi odsyłaczami w toku rozmowy, więc nie zasługują na ramkę. Ramka zostaje wyłącznie karcie
   pobrania pliku, bo tam obramowanie niesie treść — to artefakt do zabrania, nie odsyłacz.
   Klasy pozostają ROZDZIELNE mimo wspólnego wyglądu: auto-nawigacja czatu skanuje linki nawigacyjne,
   a odnośnik do dokumentacji ani akcja kontaktowa (tel:/sms:/mailto:) nie mogą przejmować ekranu
   użytkownika w środku rozmowy. Wygląd dzielą wszystkie trzy — to ten sam gatunek odsyłacza. */
.navigation-link-message,
.reference-link-message,
.contact-action-message {
    margin: 0.5rem 0;
}

.navigation-link-button,
.reference-link-button,
.contact-action-button {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    color: var(--rz-link-color, #0066cc);
    padding: 0.5rem;
    margin-left: -0.5rem;
    border-radius: 4px;
    transition: background-color 0.2s ease;
}

.navigation-link-button:hover,
.reference-link-button:hover,
.contact-action-button:hover {
    background-color: var(--rz-base-200, rgba(0, 0, 0, 0.05));
    text-decoration: none;
}

.navigation-link-button:active,
.reference-link-button:active,
.contact-action-button:active {
    background-color: var(--rz-base-300, rgba(0, 0, 0, 0.1));
}

/* flex-shrink: 0 — na wąskim ekranie długa etykieta (nazwa kontrahenta + numer) ściskała ikonę
   do zera i łamała ją do własnego wiersza. Ikona ma zostać nienaruszona, zawija się sam tekst. */
.navigation-link-button .rzi,
.reference-link-button .rzi,
.contact-action-button .rzi {
    margin-right: 0.5rem;
    vertical-align: middle;
    font-size: 1.2em;
    flex-shrink: 0;
}

/* Blok preformatowany wyodrebniony z odpowiedzi sub-agenta — to, o czym model glosowy mowi
   „wyglada tak". Zawartosc moze byc czymkolwiek, wiec zero interpretacji: monospace, zawijanie
   dlugich linii i wlasny scroll, zeby dluga tresc nie rozpychala panelu rozmowy. */
.preformatted-block-message {
    margin: 0.5rem 0;
    border: 1px solid var(--rz-base-300, rgba(0, 0, 0, 0.1));
    border-radius: 4px;
    background-color: var(--rz-base-100, rgba(0, 0, 0, 0.03));
    overflow: hidden;
}

.preformatted-block-language {
    display: block;
    padding: 0.25rem 0.5rem;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--rz-text-tertiary-color);
    border-bottom: 1px solid var(--rz-base-300, rgba(0, 0, 0, 0.1));
}

.preformatted-block-message pre {
    margin: 0;
    padding: 0.5rem;
    max-height: 18rem;
    overflow: auto;
    font-size: 0.8rem;
    line-height: 1.4;
    white-space: pre-wrap;
    word-break: break-word;
}

/* Karta pobrania pliku wygenerowanego przez skrypt (eksport) — celowo INNA klasa niż
   navigation-link-*: auto-nawigacja czatu skanuje linki nawigacyjne i nie może "nawigować"
   do pliku (wywołałaby pobranie w środku rozmowy). Ramka zostaje TYLKO tutaj: karta niesie
   artefakt do zabrania, więc ma wyglądać jak obiekt, a nie jak odsyłacz w zdaniu. */
.file-download-message {
    margin: 0.5rem 0;
}

.file-download-button {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    color: var(--rz-link-color, #0066cc);
    padding: 0.5rem;
    margin-left: -0.5rem;
    border: 1px dashed var(--rz-base-400, rgba(0, 0, 0, 0.2));
    border-radius: 4px;
    transition: background-color 0.2s ease;
}

.file-download-button:hover {
    background-color: var(--rz-base-200, rgba(0, 0, 0, 0.05));
    text-decoration: none;
}

.file-download-button:active {
    background-color: var(--rz-base-300, rgba(0, 0, 0, 0.1));
}

.file-download-button .rzi {
    margin-right: 0.5rem;
    vertical-align: middle;
    font-size: 1.2em;
}
.subagent-message {
    font-size: 12px;
    font-weight: 300;
    opacity: 0.7;
    letter-spacing: 0.02em;
    border-width: 1px;
    border-style: solid;
    border-color: color-mix(in srgb, var(--rz-base-400) 70%, green 30%);
    padding: 0.5rem;
    border-radius: 0.5rem;
    margin-bottom: 1rem;
    background-color: color-mix(in srgb, var(--rz-body-background-color) 85%, green 15%);
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.subagent-message b {
    font-weight: 500;
}

.subagent-view-btn {
    background: none;
    border: none;
    cursor: pointer;
    opacity: 0.5;
    padding: 2px;
    margin-left: auto;
}

.subagent-view-btn:hover {
    opacity: 1;
}
.typing-indicator {
    display: inline-flex;
    gap: 1px;
    align-items: flex-end;
}

.typing-indicator span {
    display: inline-block;
    animation: bounce 1.2s infinite ease-in-out;
}

.typing-indicator span:nth-child(1) {
    animation-delay: 0s;
}

.typing-indicator span:nth-child(2) {
    animation-delay: 0.2s;
}

.typing-indicator span:nth-child(3) {
    animation-delay: 0.4s;
}

@keyframes bounce {

    0%,
    80%,
    100% {
        transform: translateY(0);
        opacity: 0.6;
    }

    40% {
        transform: translateY(-8px);
        opacity: 1;
    }
}

.shimmer-indicator {
    position: relative;
    /* animowana maska liniowa powoduje przesuwające się przyciemnienie od lewej do prawej */
    -webkit-mask-image: linear-gradient(90deg,
            rgba(0, 0, 0, 1.00) 0%,
            rgba(0, 0, 0, 1.00) 20%,
            rgba(0, 0, 0, 0.35) 30%,
            rgba(0, 0, 0, 0.35) 70%,
            rgba(0, 0, 0, 1.00) 80%,
            rgba(0, 0, 0, 1.00) 100%);
    mask-image: linear-gradient(90deg,
            rgba(0, 0, 0, 1.00) 0%,
            rgba(0, 0, 0, 1.00) 20%,
            rgba(0, 0, 0, 0.35) 30%,
            rgba(0, 0, 0, 0.35) 70%,
            rgba(0, 0, 0, 1.00) 80%,
            rgba(0, 0, 0, 1.00) 100%);
    -webkit-mask-size: 200% 100%;
    mask-size: 200% 100%;
    -webkit-mask-position: -100% 0%;
    mask-position: -100% 0%;
    animation: shimmer 1.2s linear infinite;
}

@keyframes shimmer {
    0% {
        -webkit-mask-position: 100% 0%;
        mask-position: 100% 0%;
    }

    100% {
        -webkit-mask-position: -100% 0%;
        mask-position: -100% 0%;
    }
}

/* Drag & Drop styles for HydraTree */
.hydra-tree-dragging {
    opacity: 0.5;
    cursor: grabbing !important;
}

.hydra-tree-drag-over {
    background-color: var(--rz-primary-lighter, #e3f2fd);
    border: 2px dashed var(--rz-primary, #1976d2);
    border-radius: 4px;
}

.rz-treenode-content[data-drag-initialized="true"] {
    cursor: grab;
}

.rz-treenode-content[data-drag-initialized="true"]:active {
    cursor: grabbing;
}

.rz-treenode[data-selected="true"]>.rz-treenode-content {
    font-weight: 700;
}

/* Zmiana kolejnosci wierszy grida przeciaganiem */
tr.rz-data-row[draggable="true"] {
    cursor: move;
}

.hydra-grid-row-dragging {
    opacity: 0.5;
}
/* Custom tooltipy - pozycjonowanie */
.rz-splitbutton-menu .rz-menuitem[data-description] {
    position: relative;
}

/* Custom tooltip po prawej stronie elementu */
.rz-splitbutton-menu .rz-menuitem[data-description]:hover::after {
    content: attr(data-description);
    position: absolute;
    right: 100%;
    top: 0;
    margin-left: 0.75rem;
    padding: 0.75rem 1rem;
    background-color: var(--rz-text-color, #333);
    color: var(--rz-base-background-color, #fff);
    border-radius: var(--rz-border-radius, 4px);
    font-size: 0.9rem;
    line-height: 1.5;
    white-space: normal;
    max-width: 650px;
    min-width: 200px;
    width: max-content;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    z-index: 10000;
    pointer-events: none;
    animation: fadeInTooltip 0.2s ease-in-out;
    animation-delay: 0.5s;
    opacity: 0;
    animation-fill-mode: forwards;
}

/* Strzałka tooltipu */
.rz-splitbutton-menu .rz-menuitem[data-description]:hover::before {
    content: '';
    position: absolute;
    left: 0;
    top: 1rem;
    margin-right: 0.25rem;
    width: 0;
    height: 0;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    border-left: 6px solid var(--rz-text-color, #333);
    z-index: 10001;
    pointer-events: none;
    animation: fadeInTooltip 0.2s ease-in-out;
    animation-delay: 0.5s;
    opacity: 0;
    animation-fill-mode: forwards;
}

@keyframes fadeInTooltip {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

/* Padding dla zawartości w krokach formularza */
.rz-steps > .rz-widget-content > .rz-form {
    padding: 0.125rem;
}

/* Popup filtra kolumn grida — gwarantowany z-index nad zawartością grida (sticky header,
   sticky scroll-container) tak, aby na wąskim oknie checklistowy popup multi-select
   (np. filtr kolumny Status) nie chował się za stacking-contextem nagłówka/grida. */
.rz-overlaypanel:has(.rz-grid-filter) {
    z-index: 1010 !important;
}

/* ===== Akcja przy pozycji listy podpowiedzi (HydraAutoComplete: ItemActionIcon + ItemAction) ===== */

/* pozycja listy rozkłada się na treść z lewej i ikonę akcji dosuniętą do prawej krawędzi */
.hydra-autocomplete-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
}

/* ikona akcji nie jest częścią tekstu pozycji, więc trzyma się drugiego planu
   i podświetla dopiero pod kursorem */
.hydra-autocomplete-item-action {
    display: inline-flex;
    align-items: center;
    margin-inline-start: auto;
    cursor: pointer;
    color: var(--rz-text-secondary-color, #6c757d);
}

.hydra-autocomplete-item-action:hover {
    color: var(--rz-text-color, #333);
}

.hydra-autocomplete-item-action .rzi {
    font-size: 1.1rem;
}

/* lista podpowiedzi skanera bez pozycji to pusta ramka pod polem — skaner otwiera ją na kursorze,
   zanim podpowiedzi dojdą, i zostawia otwartą, gdy nie ma czego pokazać */
.rz-autocomplete-panel[style*="--hydra-scanner-suggestions"]:not(:has(li)) {
    display: none !important;
}

/* === Voice Assistant === */

.voice-transcript-area {
    font-size: var(--rz-panel-menu-font-size);

    /* Wstawienie dymka nie moze pociagac za soba przeliczenia ukladu calego panelu i sidebara. */
    contain: layout paint style;

    /* Zakotwiczanie scrolla to dodatkowa praca przegladarki przy KAZDYM wstawieniu tresci — a my
       i tak zawsze przewijamy na dol, wiec te obliczenia sa zmarnowane. */
    overflow-anchor: none;
    color: var(--rz-panel-menu-item-color);
    -webkit-mask-image: linear-gradient(to bottom,
            transparent 0%,
            black 1rem,
            black calc(100% - 1rem),
            transparent 100%);
    mask-image: linear-gradient(to bottom,
            transparent 0%,
            black 1rem,
            black calc(100% - 1rem),
            transparent 100%);
}

.voice-message {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    line-height: 1.5;
}

.voice-message-icon {
    flex-shrink: 0;
    opacity: 0.7;
}

.voice-message-text {
    flex: 1;
    min-width: 0;
    word-wrap: break-word;
}

.voice-message-user .voice-message-text {
    font-weight: 500;
}

.voice-cursor {
    display: inline-block;
    width: 0.5em;
    height: 1em;
    background-color: currentColor;
    opacity: 0.6;
    vertical-align: text-bottom;
    animation: voiceCursorBlink 0.8s step-end infinite;
}

@keyframes voiceCursorBlink {
    50% {
        opacity: 0;
    }
}

/* Karty sub-agentow */
.voice-subagent-card {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--rz-base-400);
    border-radius: var(--rz-border-radius);
    background: var(--rz-panel-menu-item-2nd-level-active-background-color);
    font-size: 0.9em;
}

.voice-subagent-card.voice-subagent-completed {
    border-color: var(--rz-success);
    opacity: 0.8;
}

.voice-subagent-card.voice-subagent-failed,
.voice-subagent-card.voice-subagent-cancelled {
    border-color: var(--rz-danger);
    opacity: 0.8;
}

.voice-subagent-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Przycisk mikrofonu */
/* Kolumna mikrofonu ma STALA szerokosc — dokladnie taka sama jak kolumna statusu pod nim
   (zmienna nizej), zeby status byl wycentrowany pod przyciskiem niezaleznie od tego, ile miejsca
   zajmuja przyciski po prawej i jak dlugi jest tekst stanu. */
.voice-mic-container {
    display: flex;
    justify-content: center;
    flex: 0 0 var(--voice-mic-column-width, 8rem);
}

.voice-mic-button {
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    border: 2px solid var(--rz-base-400);
    background: transparent;
    color: var(--rz-panel-menu-item-color);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s ease;
}

.voice-mic-button:hover:not(:disabled) {
    border-color: var(--rz-primary);
    background: var(--rz-primary-lighter);
}

.voice-mic-button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.voice-mic-idle {
    border-color: var(--rz-base-500);
}

/* Nagrywanie ma JEDNA rodzine kolorow — `danger` — te sama co przycisk panelu w nagorku, zeby oba
   miejsca mowily to samo: mikrofon pracuje. Fazy nadal rozroznia RUCH, nie barwa: laczenie i nasluch
   pulsuja, odtwarzanie odpowiedzi ma statyczna poswiate. Wyciszenie zostaje na `warning`. */
.voice-mic-connecting {
    border-color: var(--rz-danger);
    animation: voicePulse 1.5s ease-in-out infinite;
}

.voice-mic-listening {
    border-color: var(--rz-danger);
    box-shadow: 0 0 0 0 var(--rz-danger);
    animation: voicePulse 2s ease-in-out infinite;
}

.voice-mic-speaking {
    border-color: var(--rz-danger);
    box-shadow: 0 0 8px var(--rz-danger-lighter);
}

/* Asystent mowi, ale mikrofon NIE WYSYLA ani jednej ramki (pol-dupleks) — droga glosnik->mikrofon
   nie kasuje echa, wiec barge-in jest wylaczony. Barwa neutralna, bo rodzina `danger` obok znaczy
   „mikrofon pracuje"; roznice niesie tez ikona (volume_down zamiast volume_up). Bez poswiaty,
   bo poswiata w tym panelu towarzyszy stanom, w ktorych cos od uzytkownika jest przyjmowane. */
.voice-mic-speaking-deaf {
    border-color: var(--rz-base-400);
    box-shadow: none;
}

.voice-mic-muted {
    border-color: var(--rz-warning);
    animation: none;
}

/* Przepuszczanie audio do modelu — stan WEWNATRZ nasluchu, nie kolejna faza. Dlatego nie dostaje
   ani nowej barwy (rodzina `danger` znaczy „mikrofon pracuje" i ma tak zostac), ani nowego ruchu
   (bramka przelacza sie w skali setek ms, a ikona migajaca kilka razy na sekunde rozprasza
   kierowce bardziej niz brak informacji). Rozroznienie niesie JASNOSC PLAMY: wypelnione tlo
   i wypelniona ikona wobec pustego tla i konturu. Widac to katem oka i dziala tez wtedy, gdy
   barwy sa nieczytelne — w sloncu albo przy zaburzeniach rozpoznawania kolorow. */
.voice-mic-passing {
    background: var(--rz-danger-lighter);
}

/* Ta sama ikona, inna waga rysunku: os FILL zmiennego fontu Material Symbols. Zmiana glifu
   na inna ikone zmuszalaby do rozpoznawania nowego ksztaltu przy kazdym przelaczeniu bramki. */
.voice-mic-passing .voice-mic-icon-default {
    font-variation-settings: 'FILL' 1;
}

/* Hover na przycisku mikrofonu — zamiana ikony mic na mic_off (tylko gdy nie zmutowany) */
.voice-mic-button .voice-mic-icon-hover {
    display: none;
}

/* WYLACZNIE dla urzadzen, ktore naprawde maja kursor. Dotyk nie ma najechania, ale przegladarka
   mobilna zostawia stan :hover na ostatnio dotknietym elemencie az do dotkniecia czegos innego —
   po wylaczeniu wyciszenia przycisk wracal do klasy hover-swap i ten zalepiony :hover pokazywal
   ikone najechania (mic_off), czyli dokladnie te sama co przed chwila. Wygladalo to jak brak
   reakcji na klikniecie: ikona zmieniala sie dopiero po dotknieciu czegokolwiek obok. */
@media (hover: hover) and (pointer: fine) {
    .voice-mic-hover-swap:hover .voice-mic-icon-default {
        display: none;
    }

    .voice-mic-hover-swap:hover .voice-mic-icon-hover {
        display: inline;
    }
}

.voice-mic-processing {
    border-color: var(--rz-warning);
}

/* Prog odciecia szumu — suwak na dole panelu glosowego z kreska biezacego poziomu mikrofonu.
   Kreska ma inny kolor niz suwak (info vs base), zeby na pierwszy rzut oka bylo widac, czy
   aktualny szum tla siega ustawionego progu. */
/* Bez wlasnego paddingu bocznego: suwak ma konczyc sie DOKLADNIE tam, gdzie grupa przyciskow
   powyzej i panel plikow ponizej — wszystkie trzy w jednej kolumnie. */
.voice-threshold {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0;
}

.voice-threshold-label {
    display: block;
    font-size: 0.75rem;
    color: var(--rz-text-tertiary-color);
    margin-bottom: 0.125rem;
}

.voice-threshold-track {
    position: relative;
    display: flex;
    align-items: center;
    min-height: 1.5rem;
}

/* Suwak Radzena zajmuje pelna szerokosc panelu; wysokosc toru zostaje z motywu. */
.voice-threshold-track .rz-slider {
    width: 100%;
}

/* Biezacy poziom dzwieku — pasek od lewej krawedzi suwaka do aktualnego poziomu. Geometria (wysokosc,
   przesuniecie o -1px, zaokraglenie lewych rogow) celowo powtarza `.rz-slider-range`, zeby pasek
   pokrywal sie co do piksela z wypelnieniem toru po lewej stronie galki i przykrywal je. Nie
   przechwytuje klikniec, zeby nie przeszkadzal w przeciaganiu galki. */
.voice-threshold-level {
    position: absolute;
    top: 50%;
    height: 6px;
    margin-top: -3px;
    left: -1px;
    background: var(--rz-info);
    border-radius: 4px 0 0 4px;
    pointer-events: none;
    z-index: 1;

    /* Szerokosc ustawia miernik w JS (voiceLevelMeter) jako --voice-input-x w pikselach, w tej samej
       skali co suwak: pasek siegajacy przed galke znaczy „ten dzwiek zostanie odciety". */
    width: var(--voice-input-x, 0px);
    transition: width 0.45s linear;
    will-change: width;
}

/* Galka musi zostac NAD paskiem poziomu — u Radzena obie warstwy maja z-index auto, wiec o kolejnosci
   decydowalaby pozycja w DOM (pasek jest pozniej). Podnosimy wylacznie galke naszego suwaka. */
.voice-threshold-track .rz-slider-handle {
    z-index: 2;
}

@keyframes voicePulse {
    0% {
        box-shadow: 0 0 0 0 currentColor;
    }

    50% {
        box-shadow: 0 0 0 6px transparent;
    }

    100% {
        box-shadow: 0 0 0 0 transparent;
    }
}

/* Szuflada zadan sub-agentow — pas miedzy transkrypcja a panelem sterowania. Zadania nie sa
   wiadomosciami rozmowy, wiec maja wlasne, stale miejsce zamiast pozycji w historii. */
.voice-tasks {
    flex: 0 0 auto;

    /* Widoczne maksymalnie 4 zadania, dalej scroll: 4 wiersze po 2.75rem + 3 odstepy 0.375rem
       + 1rem paddingu = 13.125rem. Szesc zadan naraz zjadalo transkrypcje rozmowy.
       Cap procentowy zostaje na wypadek niskiego okna — bierzemy mniejsza z wartosci. */
    max-height: min(13.125rem, 30%);
    overflow-y: auto;
    border-top: var(--rz-panel-menu-item-border);
    padding: 0.5rem 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;

    /* Zmiany WEWNATRZ szuflady (tekst kroku workera zmienia sie co chwile) nie moga pociagac za soba
       przeliczenia ukladu calego panelu. Bez izolacji kazda taka zmiana dotykala transkrypcji nad
       szuflada i panelu sterowania pod nia, a przy rozmowie glosowej ten sam watek planuje audio. */
    contain: layout paint style;
}

.voice-task {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0.5rem;
    border-radius: var(--rz-border-radius);
    background: var(--rz-base-background-color);
    border-left: 3px solid var(--rz-base-400);

    /* STALA wysokosc wiersza. Wysokosc zalezna od tresci zmieniala sie dwukrotnie w cyklu zycia
       zadania: gdy pojawial sie podtytul i gdy znikal po zakonczeniu. Kazda taka zmiana zmieniala
       wysokosc szuflady, a to wymusza ponowne wyliczenie ukladu transkrypcji obok niej. */
    height: 2.75rem;
    box-sizing: border-box;
    contain: layout paint;
}

.voice-task-icon {
    font-size: 1.25rem;
    flex: 0 0 auto;
}

/* Dwie linie i ani jednej wiecej: nazwa zadania oraz to, co worker robi TERAZ. */
.voice-task-lines {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
}

.voice-task-name {
    font-size: 0.85rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.voice-task-step {
    font-size: 0.75rem;
    opacity: 0.7;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Komunikat postepu niesie wlasna kropke statusu — w kafelku byloby to drugie oznaczenie tego
   samego stanu, obok ikony po lewej. Pogrubien tez nie potrzebujemy w drugiej linii. */
.voice-task-step .chat-status {
    display: none;
}

.voice-task-step b {
    font-weight: inherit;
}

/* Myśl asystenta — tura zamknięta narzędziem Note, czyli coś, czego w pokoju nikt nie usłyszał.
   Kursywa i wyciszony kolor odrozniaja ja od wypowiedzi na glos, ktore sa pelnym glosem w rozmowie. */
/* Myśl asystenta jest wiadomością AgentMinor, a ta ma juz opacity 0.5 — własne przygaszenie
   mnożyło się z nim do 0.3 i tekst zlewał się z tłem. Wygaszenie bierzemy więc RAZ i kolorem,
   nie przezroczystością, a stopień pisma zrównujemy z pozostałymi komunikatami AgentMinor. */
.minor-agent-message:has(.voice-thought) {
    opacity: 1;
}

.voice-thought {
    font-style: italic;
    font-size: 12px;
    color: var(--rz-text-tertiary-color);
}

/* Stan widoczny kolorem obwodki i ikony — od razu wiadomo, czy worker jeszcze pracuje. */
.voice-task-running {
    border-left-color: var(--rz-primary);
}

.voice-task-running .voice-task-icon {
    color: var(--rz-primary);
    animation: spin 1.2s linear infinite;
}

.voice-task-done {
    border-left-color: var(--rz-success);
}

.voice-task-done .voice-task-icon {
    color: var(--rz-success);
}

.voice-task-awaiting {
    border-left-color: var(--rz-warning);
}

.voice-task-awaiting .voice-task-icon {
    color: var(--rz-warning);
}

.voice-task-error {
    border-left-color: var(--rz-danger);
}

.voice-task-error .voice-task-icon {
    color: var(--rz-danger);
}

.voice-task-cancelled {
    border-left-color: var(--rz-warning);
}

.voice-task-cancelled .voice-task-icon {
    color: var(--rz-warning);
}

/* Wiersz: status pod mikrofonem + suwak progu zajmujacy reszte szerokosci. */
/* Odstep rowny paddingowi dolnej sekcji (0.75rem): wtedy prosswiet po lewej stronie mikrofonu
   (od krawedzi panelu) i po prawej (do suwaka) wychodza takie same. */
.voice-status-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
}

.voice-status-text {
    font-size: 0.85rem;
    opacity: 0.7;
    text-align: center;

    /* Ta sama kolumna co mikrofon powyzej — status stoi dokladnie pod przyciskiem i nie przesuwa
       sie przy dluzszym tekscie stanu, wiec suwak obok ma staly punkt zaczepienia. */
    flex: 0 0 var(--voice-mic-column-width, 8rem);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
