﻿: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
   tylko o jedną stronę dalej. Marker renderuje podsumowanie (GridRowCountSummary) wewnątrz pagera. */
.rz-pager:has(.hydra-count-unknown) .rz-pager-last {
    display: none;
}

/* 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 z przyciskiem "Policz wiersze" — trzymamy w jednej linii z numerem strony. */
.hydra-pager-summary {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
}

/* Przycisk liczący jest częścią zdania "Strona 1 z ...", a nie osobną akcją — zdejmujemy z niego chrom przycisku
   (padding, własny rozmiar i grubość czcionki), żeby czytał się jak odsyłacz i nie rozpychał paska stronicowania.
   Reguła celuje wyłącznie w stan nieznanego licznika, więc nie dotyka przycisku przeliczającego (ikona odświeżenia). */
.hydra-pager-summary.hydra-count-unknown .rz-button {
    padding: 0;
    min-width: 0;
    min-height: 0;
    font-size: inherit;
    font-weight: inherit;
    line-height: inherit;
    text-decoration: underline;
}

/* Wewnętrzne pudełko przycisku trzyma własne line-height i jest przyklejone do góry (vertical-align z motywu).
   Po zdjęciu paddingu byłoby niższe od samego przycisku, przez co tekst siadałby wyżej niż "Strona 1 z" obok —
   zrównanie line-height wypełnia przycisk w całości i wyrównuje oba napisy. */
.hydra-pager-summary.hydra-count-unknown .rz-button .rz-button-box {
    line-height: inherit;
}

.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;
}

/* 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 — 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-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;
}
/* 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;
}

/* === 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;
}
