/*
 * Design tokens (D1, BRAND-NEW-BRAND-78). Every color, spacing and font-size
 * used anywhere in the app comes from a token defined here — no hardcoded
 * values in templates. Light/dark handled by `color-scheme` + `light-dark()`.
 *
 * Palette re-themed in Design system Phase 0 (design-system-phase0) to the
 * Trezo Bootstrap 5 admin template's tokens (html-bootstrap/assets/scss/
 * _variables.scss), which now drives every new/restyled component
 * (sidebar, Bootstrap dropdowns, buttons going forward).
 *
 * BNB-GAP-W18: `light-dark()` only follows `color-scheme`, which by default
 * tracks `prefers-color-scheme` — it has no idea about the `data-theme`
 * attribute theme_controller.js toggles (BNB-GAP-W17). Pinning
 * `color-scheme` to whichever `data-theme` is set makes every existing
 * `--color-*` token (and everything built on it: badges, buttons, flash,
 * cards, fields, tables) respond to the manual toggle for free, with no
 * per-component `[data-theme=dark]` duplication needed.
 */
:root[data-theme='dark'] {
    color-scheme: dark;
}

:root[data-theme='light'] {
    color-scheme: light;
}

:root {
    color-scheme: light dark;
    font-family: "Inter", system-ui, sans-serif;
    line-height: 1.6;

    /* Colors */
    --color-bg: light-dark(#f6f7f9, #0a0e19);
    --color-bg-raised: light-dark(#ffffff, #0c1427);
    --color-border: light-dark(#eceef2, #172036);
    --color-text: light-dark(#1a1f28, #e7eaf0);
    --color-text-muted: light-dark(#64748b, #8695aa);
    --color-link: light-dark(#605dff, #8b89ff);
    --color-accent: light-dark(#605dff, #605dff);
    --color-accent-contrast: #ffffff;
    --color-success: light-dark(#1e8308, #82fc5a);
    --color-success-bg: light-dark(#eeffe5, #14251b);
    --color-warning: light-dark(#92400e, #ffbc2b);
    --color-warning-bg: light-dark(#fef3c7, #2a2210);
    --color-error: light-dark(#d71c00, #fd5812);
    --color-error-bg: light-dark(#fff5ed, #2a1414);
    --color-neutral-bg: light-dark(#f1f0f3, #15203c);

    /* Sidebar (fixed, Design system Phase 0) */
    --sidebar-width: 260px;
    --sidebar-bg: light-dark(#ffffff, #0c1427);

    /* Spacing scale */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-8: 3rem;

    /* Typography */
    --font-size-sm: 0.875rem;
    --font-size-base: 1rem;
    --font-size-lg: 1.25rem;
    --font-size-xl: 1.75rem;

    /* Shape */
    --radius: 0.5rem;
    --radius-sm: 0.25rem;
}

* {
    box-sizing: border-box;
}

/* `header` block (sidebar + topbar) is placed AFTER `.main-content` in DOM
   source (CSRF DOM-order rule, see base.html.twig) — `order` puts topbar
   back above the content visually. The sidebar itself doesn't need this
   (`.sidebar-area` is `position: fixed`, out of flow regardless of order). */
body {
    margin: 0;
    background: var(--color-bg);
    color: var(--color-text);
    display: flex;
    flex-direction: column;
}

/* Trezo nests .header-area inside .main-content, inheriting its
   sidebar-reserving padding-left; ours is a <body> sibling (DOM-order rule
   above), so it needs the same offset explicitly. BNB-GAP-W16 updates this
   alongside .main-content when the sidebar collapses. */
.header-area {
    order: -1;
    margin-left: 273px;
    transition: margin-left ease 0.5s;
}

[sidebar-data-theme='sidebar-hide'] .header-area {
    margin-left: 92px;
}

.layout-bare .header-area {
    display: none;
}

/* BNB-GAP-W13: Trezo's `.main-content` unconditionally reserves 273px for
   the fixed sidebar (theme/trezo/style.css) — `.layout-bare` (only /login,
   which has no sidebar to render, see login.html.twig) overrides that back
   to a centered, unreserved layout. `.layout-app` needs no override: Trezo's
   own rule already does the right thing. */
.layout-bare .main-content {
    padding-left: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
}

/* /login's own two-column row already fills min-vh-100 by itself — the
   footer stacked below it (a sibling in .main-content, see base.html.twig)
   only ever added scrollbar-triggering height with nothing useful to show
   (no page identity to attribute here; the login screen already carries the
   brand's own logo). Hidden only for `bare`, not `.layout-app`. */
.layout-bare .footer-area {
    display: none;
}

a {
    color: var(--color-link);
}

/* Visible keyboard-focus ring (BRAND-NEW-BRAND-56, WCAG 2.4.7/2.4.11):
   `:focus-visible` only (not plain `:focus`) so a mouse/touch click never
   shows it, only actual keyboard navigation — supported by every browser
   this app targets. AA contrast against both the light and dark
   `--color-bg` (light-dark()-derived --color-accent already meets it). */
:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

h1 {
    font-size: var(--font-size-xl);
    margin: 0 0 var(--space-5);
}

.footer-area {
    padding: var(--space-4) 0;
    text-align: center;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* --- Navigation / sidebar (D11) ---
   BNB-GAP-W14: root markup now follows Trezo's own `.sidebar-area`/
   `.menu-inner`/`.menu-item`/`.menu-link` (theme/trezo/style.css styles
   these directly) — only our functional hooks live here: the icon-as-
   sibling layout (see nav.html.twig for why it's not nested inside the
   link) and the disabled-placeholder state Trezo has no concept of. */
.menu-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.menu-item .menu-icon {
    flex: none;
    margin-left: 1.5rem;
}

.menu-item .nav__link {
    flex: 1;
}

.nav__link.is-disabled {
    color: var(--color-text-muted);
    opacity: 0.5;
    cursor: default;
    pointer-events: none;
}

/* BNB-GAP-W16: Trezo's own collapsed-sidebar rules target `.menu-link
   .title` — our label is plain text directly in `.nav__link` (see
   nav.html.twig's docblock for why), so hide it the same way without that
   wrapper span, and restore it on the hover-to-peek Trezo already does. */
[sidebar-data-theme='sidebar-hide'] .sidebar-area:not(:hover) .nav__link {
    font-size: 0;
}

[sidebar-data-theme='sidebar-hide'] .sidebar-area:not(:hover) .logo-text {
    display: none;
}

/* --- User menu (Bootstrap dropdown, in topbar.html.twig — BNB-GAP-W15) --- */
.app-user-menu__toggle {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border: none;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--color-text);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.app-user-menu__toggle:hover {
    background: var(--color-neutral-bg);
}

.app-user-menu__avatar {
    flex: none;
    width: 34px;
    height: 34px;
    font-weight: 600;
    font-size: var(--font-size-sm);
}

.app-user-menu__meta {
    display: none;
    flex-direction: column;
    overflow: hidden;
    font-size: var(--font-size-sm);
    text-align: left;
}

@media (min-width: 640px) {
    .app-user-menu__meta {
        display: flex;
    }
}

.app-user-menu__meta > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 12rem;
}

#current-actor-role {
    color: var(--color-text-muted);
    font-size: 0.8em;
}

.app-user-menu.show .app-user-menu__caret {
    transform: rotate(180deg);
}

/* --- Flash messages --- */
/* BNB-GAP-W08: Trezo alert look (alert alert-success|danger|warning),
   built on Bootstrap's own --bs-*-rgb custom properties from theme/trezo. */
.flash {
    padding: var(--space-3) var(--space-4);
    border: 1px solid transparent;
    border-radius: var(--bs-border-radius, var(--radius));
    margin-bottom: var(--space-4);
    font-size: var(--font-size-sm);
}

.flash--success {
    background-color: rgba(var(--bs-success-rgb), 0.1);
    border-color: rgba(var(--bs-success-rgb), 0.2);
    color: var(--bs-success-text-emphasis, var(--color-success));
}

.flash--warning {
    background-color: rgba(var(--bs-warning-rgb), 0.1);
    border-color: rgba(var(--bs-warning-rgb), 0.2);
    color: var(--bs-warning-text-emphasis, var(--color-warning));
}

.flash--error {
    background-color: rgba(var(--bs-danger-rgb), 0.1);
    border-color: rgba(var(--bs-danger-rgb), 0.2);
    color: var(--bs-danger-text-emphasis, var(--color-error));
}

/* --- Components --- */
/* BNB-GAP-W09: Trezo card look. Bootstrap's own .card is a flex column
   expecting a nested .card-body — our sections use `.card` as a single
   padded box directly, so this intentionally overrides that. */
.card {
    background-color: var(--bs-body-bg, var(--color-bg-raised));
    border: 0;
    border-radius: var(--bs-border-radius-lg, 0.75rem);
    box-shadow: var(--box-shadow, 0 0 13px 0 rgba(100, 100, 111, 0.1));
    padding: 1.5rem;
    margin-bottom: var(--space-4);
}

.card > h2 {
    font-size: 18px;
    font-weight: 600;
    padding-bottom: var(--space-3);
    margin-bottom: var(--space-4);
    border-bottom: 1px solid var(--color-border);
}

/* BNB-GAP-W06: Trezo "soft badge" look — tinted background at the token's
   own color, no hardcoded hex. */
.badge {
    display: inline-block;
    padding: 0.5rem;
    border-radius: var(--bs-border-radius, 999px);
    font-size: 12px;
    font-weight: 400;
    background-color: rgba(var(--bs-secondary-rgb), 0.1);
    color: var(--bs-secondary, var(--color-text));
}

.badge--success {
    background-color: rgba(var(--bs-success-rgb), 0.1);
    color: var(--bs-success, var(--color-success));
}

.badge--warning {
    background-color: rgba(var(--bs-warning-rgb), 0.1);
    color: var(--bs-warning, var(--color-warning));
}

.badge--error {
    background-color: rgba(var(--bs-danger-rgb), 0.1);
    color: var(--bs-danger, var(--color-error));
}

/* BNB-GAP-W07: bridge to Trezo's btn-outline-secondary/btn-primary/btn-danger
   look, driven by Bootstrap's own --bs-btn-* custom properties so a Trezo
   theme update (light/dark) is picked up automatically. */
.btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--bs-btn-padding-y, 0.5rem) var(--bs-btn-padding-x, 1rem);
    border: var(--bs-btn-border-width, 1px) solid var(--bs-secondary, var(--color-border));
    border-radius: var(--bs-btn-border-radius, var(--radius-sm));
    background: transparent;
    color: var(--bs-secondary, var(--color-text));
    font: inherit;
    font-size: var(--font-size-sm);
    cursor: pointer;
    text-decoration: none;
    transition: var(--bs-btn-transition, color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out);
}

.btn:hover {
    background: var(--bs-secondary, var(--color-neutral-bg));
    border-color: var(--bs-secondary, var(--color-border));
    color: var(--bs-btn-hover-color, #fff);
}

.btn--primary {
    background: var(--bs-primary, var(--color-accent));
    border-color: var(--bs-primary, var(--color-accent));
    color: var(--bs-btn-hover-color, var(--color-accent-contrast));
}

.btn--primary:hover {
    filter: brightness(0.92);
}

.btn--danger {
    background: rgba(var(--bs-danger-rgb), 0.1);
    border-color: var(--bs-danger, var(--color-error));
    color: var(--bs-danger, var(--color-error));
}

.btn--danger:hover {
    background: var(--bs-danger, var(--color-error));
    color: var(--bs-btn-hover-color, #fff);
}

.btn:disabled,
.btn[aria-disabled='true'] {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Minimum 44x44px touch target (WCAG 2.5.5/2.5.8), regardless of the glyph
   inside — BRAND-NEW-BRAND-54/58 (ConfirmActionTest asserts this size on
   app.css directly). BNB-GAP-W07 asked for Trezo's 30x30 icon-button look,
   but that would violate this existing accessibility requirement, so only
   its borderless look is adopted — size stays 44x44. Icon-only row-actions
   (edit, archive, ...) use `.actions` below for the >=8px gap between them. */
.btn--icon {
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: var(--space-2);
    line-height: 0;
    border: none;
    background: transparent;
}

.btn--icon:hover {
    background: rgba(var(--bs-secondary-rgb), 0.1);
}

/* BRAND-NEW-BRAND-111: confirm_action.html.twig's `show_label: true` variant
   — two of these can sit on the same row (e.g. Zakonicz/Anuluj) where an
   icon-only `.btn--icon` alone would be indistinguishable. Keeps the same
   >=44px minimum tap-target height as `.btn--icon` (WCAG 2.5.5/2.5.8,
   ConfirmActionTest asserts this on app.css directly) but grows
   horizontally to fit the icon + visible label instead of staying a fixed
   44x44 square. */
.btn--icon-text {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 44px;
    padding: var(--space-2) var(--space-3);
    border: none;
    background: transparent;
}

.btn--icon-text:hover {
    background: rgba(var(--bs-secondary-rgb), 0.1);
}

/* Wrap adjacent icon actions (e.g. edit + archive on one row) in this —
   `--space-2` is 8px, satisfying the >=8px gap acceptance criterion. */
.actions {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

/* /pracownicy's team/month filter form (BRAND-NEW-BRAND-86): a plain GET
   form, accelerated by Turbo Drive (turbo-core, eager) without a full page
   reload, with a fully working no-JS fallback. */
.filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    margin-block: var(--space-4);
}

.filters .field {
    margin-bottom: 0;
}

@media (max-width: 640px) {
    .filters {
        flex-direction: column;
        align-items: stretch;
    }
}

.field {
    display: block;
    margin-bottom: var(--space-4);
}

/* BNB-GAP-W10: bridge to Trezo's form-label/form-control look. */
.field__label {
    display: block;
    font-size: var(--bs-body-font-size, var(--font-size-sm));
    font-weight: 500;
    color: var(--color-text);
    margin-bottom: var(--space-2);
}

.field__input,
.field input,
.field select,
.field textarea {
    display: block;
    width: 100%;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--bs-border-color, var(--color-border));
    border-radius: var(--bs-border-radius, var(--radius-sm));
    background: var(--bs-body-bg, var(--color-bg));
    color: var(--color-text);
    font: inherit;
    font-size: 16px; /* prevents iOS Safari auto-zoom on focus */
    transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}

.field__input:focus,
.field input:focus,
.field select:focus,
.field textarea:focus {
    outline: 0;
    border-color: var(--bs-primary, var(--color-accent));
    box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.2);
}

.empty-state {
    padding: var(--space-6) var(--space-4);
    text-align: center;
    color: var(--color-text-muted);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius);
}

/* Hidden by default (BRAND-NEW-BRAND-56): only an ancestor's `.is-loading`
   class reveals it — see templates/_partials/skeleton.html.twig. */
.skeleton {
    display: none;
    border-radius: var(--radius-sm);
    background: linear-gradient(90deg, var(--color-neutral-bg) 25%, var(--color-bg-raised) 37%, var(--color-neutral-bg) 63%);
    background-size: 400% 100%;
    animation: skeleton-shimmer 1.4s ease infinite;
}

.is-loading .skeleton {
    display: block;
}

@keyframes skeleton-shimmer {
    0% {
        background-position: 100% 50%;
    }

    100% {
        background-position: 0 50%;
    }
}

/* --- Inline-edit pattern (reference implementation, BRAND-NEW-BRAND-78) ---
   Progressive enhancement: WITHOUT JS the view label is hidden and the form
   is always shown (plain functional form, no view/edit toggle needed).
   Stimulus's connect() sets data-inline-edit-mode-value on the frame, which
   is what flips these two sections into a collapsed view+pencil affordance —
   see assets/controllers/inline_edit_controller.js. */
.inline-edit__view {
    display: none;
    align-items: center;
    gap: var(--space-2);
}

.inline-edit__value {
    font-size: var(--font-size-lg);
}

.inline-edit__form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-2);
}

.inline-edit[data-inline-edit-mode-value='view'] .inline-edit__view {
    display: flex;
}

.inline-edit[data-inline-edit-mode-value='view'] .inline-edit__edit {
    display: none;
}

.inline-edit[data-inline-edit-mode-value='edit'] .inline-edit__view {
    display: none;
}

/* Hardening additions (BRAND-NEW-BRAND-56): action row spacing, the
   offline/5xx network banner (hidden by default via the `hidden` attribute
   in the markup — Stimulus toggles it), and skeleton sizing (visibility
   itself is the generic `.is-loading .skeleton` rule above). */
.inline-edit__actions {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.inline-edit__network-error {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-basis: 100%;
}

.inline-edit__skeleton {
    height: 2.5rem;
    max-width: 20rem;
}

/* --- Archive/confirm dialog pattern (D9, BRAND-NEW-BRAND-54) ---
   Native <dialog>: hidden by default without JS/`open`, so this markup is
   inert for no-JS visitors (they use the confirm_page.html.twig fallback
   page instead — see assets/controllers/confirm_controller.js).
   BNB-GAP-W40: visual wrapper restyled to Trezo's `.modal-content` look
   (Bootstrap's own --bs-modal-* custom properties, already defined
   app-wide) — the element stays a native <dialog>, class stays
   `confirm-dialog__form`/`confirm-dialog__*`, confirm_controller.js is
   untouched. */
.confirm-dialog {
    width: calc(100% - var(--space-6));
    max-width: 28rem;
    padding: 0;
    border: var(--bs-modal-border-width, 1px) solid var(--bs-modal-border-color, var(--color-border));
    border-radius: var(--bs-modal-border-radius, var(--radius));
    background: var(--bs-modal-bg, var(--color-bg-raised));
    color: var(--color-text);
    box-shadow: var(--box-shadow, 0 0 13px 0 rgba(100, 100, 111, 0.1));
}

.confirm-dialog::backdrop {
    background: rgb(0 0 0 / 45%);
}

.confirm-dialog__form {
    padding: var(--bs-modal-padding, var(--space-5));
}

.confirm-dialog__title {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-lg);
    font-weight: 600;
}

.confirm-dialog__description {
    margin: 0 0 var(--space-5);
    color: var(--color-text-muted);
}

.confirm-dialog__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-2);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
}

.confirm-page {
    max-width: 32rem;
}

/* --- Tiles --- */
.tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: var(--space-4);
    margin-top: var(--space-5);
}

.tile {
    padding: var(--space-5);
    text-decoration: none;
}

.tile h2 {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-lg);
    color: var(--color-text);
}

.tile p {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* --- Client card (BRAND-NEW-BRAND-1) ---
   Readable from 360px to 1440px: the header and its inline-edit rows wrap
   with flex-wrap instead of ever forcing a fixed width, and the overview
   grid below goes 1 column (<768px) -> 2 (768-1199px) -> 3 (>=1200px).
   `.field__input` (defined above) already sets font-size:16px, satisfying
   the >=16px input acceptance criterion for every field on this page. */
.client-card-header__top {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.client-card-header__top h1 {
    margin: 0;
    overflow-wrap: anywhere;
}

.client-card-header__legal {
    color: var(--color-text-muted);
    margin: 0 0 var(--space-4);
}

.client-card-header .inline-edit {
    margin-bottom: var(--space-4);
}

.client-card-header .inline-edit:last-child {
    margin-bottom: 0;
}

.client-card-header .inline-edit__value {
    overflow-wrap: anywhere;
}

/* --- Tabs --- */
.client-card-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: var(--space-5) 0 var(--space-4);
    border-bottom: 1px solid var(--color-border);
}

.client-card-tab {
    border: none;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    background: none;
    padding: var(--space-3) var(--space-2);
    min-height: 44px;
    color: var(--color-text-muted);
    font: inherit;
    font-size: var(--font-size-sm);
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
}

.client-card-tab.is-active {
    color: var(--color-text);
    border-bottom-color: var(--color-accent);
    font-weight: 700;
    cursor: default;
}

.client-card-tab[aria-disabled='true'] {
    cursor: not-allowed;
    opacity: 0.7;
}

.client-card-tab__hint {
    color: var(--color-text-muted);
    font-size: 0.75rem;
    font-weight: 400;
}

/* --- ClickUp tabs (BRAND-NEW-BRAND-31): same look as client-card-tab, but real <a> navigation between distinct routes, not a JS-only single-page tablist. --- */
.clickup-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: var(--space-5) 0 var(--space-4);
    border-bottom: 1px solid var(--color-border);
}

.clickup-tab {
    border-bottom: 2px solid transparent;
    padding: var(--space-3) var(--space-2);
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    text-decoration: none;
}

.clickup-tab.is-active {
    color: var(--color-text);
    border-bottom-color: var(--color-accent);
    font-weight: 700;
}

/* --- Overview grid ---
   Column order at 1 column matches the source order below: kompletność,
   usługi i specjaliści, cele KPI, budżet, DoD, ClickUp. */
.client-card-overview {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
}

/* Demo polish: sections stacked as full-width rows at every width (the
   2/3-column grid squeezed the engagement table and KPI rows). */

.client-card-overview turbo-frame {
    display: block;
}

.client-card-overview h2 {
    margin: 0 0 var(--space-3);
    font-size: var(--font-size-base);
}

/* --- /klienci list (BRAND-NEW-BRAND-3) --- */
.client-list-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: var(--space-4) 0;
    border-bottom: 1px solid var(--color-border);
}

.client-list-tab {
    display: inline-block;
    padding: var(--space-3) var(--space-2);
    min-height: 44px;
    border-bottom: 2px solid transparent;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    text-decoration: none;
}

.client-list-tab.is-active {
    color: var(--color-text);
    border-bottom-color: var(--color-accent);
    font-weight: 700;
}

.client-list-table {
    width: 100%;
    border-collapse: collapse;
    margin-block: var(--space-4);
}

.client-list-table th,
.client-list-table td {
    padding: var(--space-3) var(--space-2);
    text-align: left;
    border-bottom: 1px solid var(--color-border);
    vertical-align: top;
}

.client-list-table th {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-weight: 600;
}

/* BNB-GAP-W12: Trezo table look, applied generically to every table under
   <main> (not per screen-specific class) so 30+ existing templates pick it
   up unchanged — `.table-scroll` already gives `.table-responsive`-style
   horizontal scrolling, and `<details>` tables get the same rules. */
main table,
main details table {
    width: 100%;
    border-collapse: collapse;
    margin-block: var(--space-4);
}

main table thead th {
    background-color: var(--bs-tertiary-bg, var(--color-neutral-bg));
    color: var(--color-text-muted);
    font-weight: 500;
    font-size: 12px;
    text-align: left;
    padding: 0.9375rem;
    border: none;
    border-bottom: 1px solid var(--color-border);
}

main table thead th:first-child {
    border-radius: var(--bs-border-radius, 0.5rem) 0 0 0;
}

main table thead th:last-child {
    border-radius: 0 var(--bs-border-radius, 0.5rem) 0 0;
}

main table tbody td {
    padding: 0.9375rem;
    vertical-align: middle;
    border-bottom: 1px solid var(--color-border);
    color: var(--color-text);
}

.completeness-badge__missing {
    margin: var(--space-1) 0 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* --- Cele KPI (BRAND-NEW-BRAND-18) --- */
.kpi-section__header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

.kpi-group {
    margin-bottom: var(--space-5);
}

.kpi-group:last-child {
    margin-bottom: 0;
}

.kpi-group__title {
    margin: 0 0 var(--space-3);
    font-size: var(--font-size-sm);
    font-weight: 600;
}

.kpi-group__period {
    font-weight: 400;
    color: var(--color-text-muted);
}

.kpi-group__goals {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.kpi-group__add {
    margin-top: var(--space-3);
}

.kpi-goal {
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
}

.kpi-goal--unmeasured {
    border-style: dashed;
}

.kpi-goal__header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
}

.kpi-goal__type {
    font-weight: 600;
}

.kpi-goal__traffic-scope {
    font-weight: 400;
    color: var(--color-text-muted);
}

.kpi-goal__facts {
    display: grid;
    gap: var(--space-1);
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-sm);
}

.kpi-goal__facts dt {
    display: inline;
    color: var(--color-text-muted);
}

.kpi-goal__facts dt::after {
    content: ': ';
}

.kpi-goal__facts dd {
    display: inline;
    margin: 0;
}

.kpi-goal__flag {
    margin: 0 0 var(--space-2);
}

/* Progress bar + "oczekiwane na dziś" (BRAND-NEW-BRAND-133) — only rendered
   once a goal has a measurement; an UNMEASURED goal has no bar at all. */
.kpi-goal__progress {
    margin: 0 0 var(--space-2);
}

.kpi-goal__expected-today {
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

.kpi-goal__actions {
    flex-wrap: wrap;
}

/* KPI goals as full-width rows (demo polish): identity | metrics | actions
   on wide screens, stacked on narrow ones. */
.kpi-goal__layout {
    display: grid;
    gap: var(--space-3);
    grid-template-columns: 1fr;
}

.kpi-goal__header {
    justify-content: flex-start;
    margin-bottom: var(--space-1);
}

.kpi-goal__metrics .kpi-goal__facts {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-5, 2rem);
    margin: 0;
}

.kpi-goal__metrics .kpi-goal__progress {
    margin-bottom: var(--space-1);
}

@media (min-width: 992px) {
    .kpi-goal__layout {
        grid-template-columns: minmax(14rem, 1fr) minmax(20rem, 2.2fr) auto;
        align-items: center;
    }

    .kpi-goal__actions {
        justify-content: flex-end;
    }
}

/* --- Access-credential list/reveal (BRAND-NEW-BRAND-53) ---
   `.btn--icon` (defined above) already guarantees the >=44x44px tap target
   for every reveal/copy/edit/archive icon button on this screen. */
.credentials-tab__header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

/* Only tables/diagrams may be wider than the viewport — scroll inside this
   wrapper instead of the page ever gaining horizontal scroll. */
.table-scroll {
    overflow-x: auto;
}

.credentials-list {
    width: 100%;
    border-collapse: collapse;
}

.credentials-list th,
.credentials-list td {
    padding: var(--space-2) var(--space-3);
    text-align: left;
    vertical-align: middle;
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
}

.credentials-list__row--archived {
    opacity: 0.6;
}

.reveal {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.reveal__value {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.reveal__error {
    display: block;
    color: var(--color-error);
    font-size: var(--font-size-sm);
}

.reveal-value {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.reveal-value__text {
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    background: var(--color-neutral-bg);
    font-size: var(--font-size-sm);
    white-space: normal;
    word-break: break-all;
}

.reveal-value__timer {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.field--checkbox {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* --- Password step-up modal (BRAND-NEW-BRAND-53) ---
   Reuses .confirm-dialog (D9, BRAND-NEW-BRAND-54): same native <dialog>
   pattern, inert without JS/`.showModal()`. */
.step-up-modal__error {
    margin-bottom: var(--space-4);
}

/* --- Kryteria akceptacji / DoD (BRAND-NEW-BRAND-2) --- */
.acceptance-block {
    margin-bottom: var(--space-5);
}

.acceptance-block:last-child {
    margin-bottom: 0;
}

.acceptance-criteria {
    margin: 0 0 var(--space-3);
    padding-left: var(--space-5);
}

.acceptance-criteria__item {
    margin-bottom: var(--space-2);
}

.acceptance-criteria__statement {
    display: block;
}

.acceptance-criteria__meta {
    display: block;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.acceptance-note__text {
    white-space: pre-wrap;
    word-break: break-word;
}

/* Progressive enhancement only — without JS this stays empty/hidden; the
   real 2000-character limit is enforced server-side regardless (see
   assets/controllers/char_counter_controller.js). */
.char-counter {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.char-counter--over {
    color: var(--color-error);
}

/* --- Product publication impact preview (BRAND-NEW-BRAND-43) --- */
.version-diff-section {
    margin-top: var(--space-4);
}

.version-diff-section summary {
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.version-diff-table__item td {
    background: var(--color-neutral-bg);
    font-weight: 600;
}

.version-diff-table__field--changed td {
    background: var(--color-warning-bg);
}

/* --- Products (BRAND-NEW-BRAND-14) ---
   Reuses the exact table/tab token shapes client-list-table/client-card-tab
   already established, under this module's own class names. */
.product-list-table {
    width: 100%;
    border-collapse: collapse;
    margin-block: var(--space-4);
}

.product-list-table th,
.product-list-table td {
    padding: var(--space-3) var(--space-2);
    text-align: left;
    border-bottom: 1px solid var(--color-border);
    vertical-align: top;
}

.product-list-table th {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-weight: 600;
}

.product-card-header__top {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.product-card-header__top h1 {
    margin: 0;
    overflow-wrap: anywhere;
}

.product-card-header__meta {
    color: var(--color-text-muted);
    margin: 0 0 var(--space-4);
}

.product-completeness {
    margin: var(--space-4) 0;
}

/* 1 column below 768px, 2 from 768px, matching client-card-overview's own
   breakpoints — readable from 360px to 1440px. */
.product-detail-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
}

@media (min-width: 768px) {
    .product-detail-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

.product-detail-section h2 {
    margin: 0 0 var(--space-3);
    font-size: var(--font-size-base);
}

.product-detail-section__empty {
    color: var(--color-text-muted);
}

.product-detail-section__price {
    font-size: var(--font-size-lg);
    font-weight: 700;
}

.product-owners-list {
    list-style: none;
    margin: 0 0 var(--space-4);
    padding: 0;
}

.product-owners-list li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--color-border);
}

.product-owners-list__revoke {
    display: inline-flex;
}

.product-diff-row--changed {
    background: var(--color-warning-bg);
}

/* BRAND-NEW-BRAND-87: the draft section editor — same product-detail-grid
   layout the read-only card uses, each turbo-frame a .card of its own. */
.draft-editor {
    align-items: start;
}

.draft-section h2 {
    margin: 0 0 var(--space-3);
    font-size: var(--font-size-base);
}

.draft-collection__item {
    border: 1px solid var(--color-border);
    border-radius: var(--radius, 4px);
    padding: var(--space-3);
    margin-bottom: var(--space-3);
}

.draft-collection__item legend {
    padding: 0;
}

.draft-collection__sub-fields {
    display: flex;
    gap: var(--space-3);
}

.draft-completeness {
    display: block;
}

.draft-completeness__missing {
    color: var(--color-text-muted);
    margin-left: var(--space-2);
}

.draft-section--conflict {
    border-color: var(--color-error, #c0392b);
}

.is-hidden {
    display: none !important;
}

/* Visually hidden but still reachable by assistive tech (item fieldsets'
   own legends — each item's fields already carry visible labels, so
   repeating "Pozycja zakresu 2" etc. out loud is enough context without
   cluttering the visible layout). */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* =========================================================================
 * BNB-GAP-W36: Słowniki (dictionaries) — div-based "table" (real <table>
 * would break the <turbo-frame> row boundary, see _table.html.twig) gets
 * the same visual rhythm as Trezo's real `main table` bridge above
 * (thead-style header band, row separators, cell padding) via flexbox
 * instead of table layout. `.dict-table__cell` marks only the data cells so
 * action buttons/the confirm-dialog trigger inside `.inline-edit__view`
 * keep their natural (non-flexed) size.
 * ========================================================================= */
.dict-table {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    overflow: hidden;
}

.dict-table__head {
    background-color: var(--bs-tertiary-bg, var(--color-neutral-bg));
    color: var(--color-text-muted);
    font-weight: 500;
    font-size: 12px;
    padding: 0.9375rem;
    border-bottom: 1px solid var(--color-border);
}

.dict-table__row {
    display: block;
    border-bottom: 1px solid var(--color-border);
}

.dict-table__row:last-child {
    border-bottom: none;
}

.dict-table__row .inline-edit__view {
    padding: 0.9375rem;
}

.dict-table__row .inline-edit__edit {
    padding: 0 0.9375rem 0.9375rem;
}

.dict-table__cell {
    min-width: 0;
}

/* Header and every row share one grid template so columns line up even
   though rows carry extra action buttons: Kod | Etykieta | [Jednostka |
   Zakres ruchu] | Kolejność | Status | actions. */
.dict-table {
    --dict-columns: minmax(8rem, 1fr) minmax(10rem, 2fr) 7rem 7rem 7.5rem;
}

.dict-table--kpi {
    --dict-columns: minmax(8rem, 1fr) minmax(10rem, 2fr) 7rem 8rem 7rem 7rem 7.5rem;
}

/* Specificity must beat `.inline-edit[data-inline-edit-mode-value='view']
   .inline-edit__view { display: flex }` above, or rows fall back to flex. */
.dict-table .dict-table__head,
.dict-table .dict-table__row.inline-edit[data-inline-edit-mode-value] .inline-edit__view {
    display: grid;
    grid-template-columns: var(--dict-columns);
    align-items: center;
    column-gap: 1rem;
}

.dict-table .dict-table__row.inline-edit[data-inline-edit-mode-value='edit'] .inline-edit__view {
    display: none;
}

.dict-table .dict-table__cell.inline-edit__value {
    font-size: inherit;
    font-weight: 500;
    color: var(--bs-heading-color, inherit);
}

.dict-table__cell--code {
    font-family: var(--bs-font-monospace, monospace);
    font-size: 12px;
    color: var(--color-text-muted);
}

.dict-table .dict-table__cell--actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
}

.dict-table .dict-table__row:hover {
    background-color: var(--bs-tertiary-bg, rgba(0, 0, 0, 0.02));
}

/* =========================================================================
 * BNB-GAP-W38: ClickUp screens — the "Do potwierdzenia" queue cards
 * (_queue_section.html.twig) sit inside a shared `.card` now (Trezo look);
 * this just adds row separators between cards and lines up the bulk-confirm
 * form's fields, both previously fully unstyled.
 * ========================================================================= */
.clickup-list-mapping-queue-card {
    padding: var(--space-4) 0;
    border-bottom: 1px solid var(--color-border);
}

.clickup-list-mapping-queue-card:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.clickup-bulk-confirm-form {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

/* =========================================================================
 * BNB-GAP-W39: KPI import drop-zone LOOK ONLY — the <input type="file">
 * underneath is completely unchanged/unscripted (still a plain input, no
 * drag-and-drop JS), just wrapped in a dashed-border area matching Trezo's
 * file-upload visual language.
 * ========================================================================= */
.kpi-import-form__dropzone {
    border: 2px dashed var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-5);
    text-align: center;
    background-color: var(--bs-tertiary-bg, var(--color-neutral-bg));
}

.kpi-import-form__dropzone input[type='file'] {
    display: block;
    margin: var(--space-2) auto 0;
}

.kpi-import-form__hint {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    margin: var(--space-2) 0 0;
}

/* =========================================================================
 * BNB-GAP-W40: shared partials — empty_state's icon (new optional `icon`
 * param, default ri-inbox-line — see empty_state.html.twig) and the flash
 * partial's Bootstrap dismiss button (data-bs-dismiss="alert", handled by
 * Bootstrap's own already-imported JS, no controller of ours needed).
 * ========================================================================= */
.empty-state__icon {
    display: block;
    font-size: 2.5rem;
    line-height: 1;
    margin-bottom: var(--space-3);
    color: var(--color-text-muted);
    opacity: 0.5;
}

.flash.alert-dismissible {
    position: relative;
    padding-right: 3rem;
}

.flash .btn-close {
    position: absolute;
    top: 50%;
    right: var(--space-4);
    transform: translateY(-50%);
}

/* =========================================================================
 * BNB-GAP-W31/W32/W33/W34/W35: access-credential list icons/step-up modal,
 * product list/card/draft-editor/version-history Trezo restyle. Bootstrap
 * utilities (bg-*, col-lg-*, accordion-*, progress, list-group, …) already
 * come from theme/trezo/style.css — only the few things Bootstrap has no
 * utility for live here.
 * ========================================================================= */

/* W33: version-history timeline — Trezo's own `.timeline-item` only styles
   the dashed line/dot; the vertical rhythm between entries is ours. */
.product-versions__timeline .timeline-item {
    margin-bottom: var(--space-2);
}

.product-versions__timeline .timeline-item:last-child {
    margin-bottom: 0;
}

/* W33: draft/compare — accordion items and diff columns keep the same
   card-like separation `.product-detail-section` already established. */
.draft-section.accordion-item {
    border: 1px solid var(--color-border);
    border-radius: var(--radius, 4px);
    margin-bottom: var(--space-3);
    overflow: hidden;
}

.draft-section.accordion-item:last-child {
    margin-bottom: 0;
}

/* W35: compare screen — one padded, separated block per section inside each
   version column; the changed/unchanged background itself comes from the
   Bootstrap bg-success/bg-danger bg-opacity-10 utility classes in the
   template, not from here. */
.product-diff-row {
    padding: var(--space-3);
    border-radius: var(--radius-sm, 4px);
    margin-bottom: var(--space-2);
}

.product-diff-row:last-child {
    margin-bottom: 0;
}

.product-diff-row p {
    white-space: pre-wrap;
    word-break: break-word;
    margin: 0;
}

/* === K04 === */
/* Client monthly report (BNB-GAP-K04): every page's app shell chrome is
   irrelevant on paper — hide it globally on print rather than only on the
   report route, so any page printed by mistake (or on purpose) looks clean
   too. `.report-print-block` (K06) mirrors each draft textarea's current
   text for print, since a <textarea>'s value does not reliably render when
   printed across browser engines; it stays display:none on screen
   (`.d-none`) and only appears under print via `.d-print-block`. */
@media print {
    .sidebar-area,
    .header-area,
    .footer-area {
        display: none !important;
    }

    .main-content {
        margin: 0 !important;
        padding: 0 !important;
    }
}

.report-print-block {
    white-space: pre-wrap;
    word-break: break-word;
}

/* === Branding (rebrand to Brand new Brand) ===
 * The sidebar wordmark ships as two pre-rendered SVGs (assets/images/brand/)
 * rather than one image recolored by CSS, so no filter/mask hacks are
 * needed. Toggled by the same `:root[data-theme]` attribute BNB-GAP-W18
 * already pins color-scheme to (see top of this file) — no extra JS.
 *
 * Height is 20px, not the ~22-26px used elsewhere (login/error/report pages
 * have room to spare): `.sidebar-area .logo` (theme/trezo/style.css) has
 * 25px left/right padding on a 260px-wide sidebar, i.e. 210px available, and
 * the wordmark's own aspect ratio (361.66:34.92, ~10.4:1) only fits that
 * width at ~20px tall — anything taller overflows the sidebar itself, not
 * just its padding.
 */
.brand-wordmark {
    height: 20px;
    width: auto;
}

.brand-wordmark--dark {
    display: none;
}

:root[data-theme='dark'] .brand-wordmark--light {
    display: none;
}

:root[data-theme='dark'] .brand-wordmark--dark {
    display: inline-block;
}

/* Collapsed sidebar (BNB-GAP-W16, 80px wide, ~30px left for the logo slot
   once its own 25px+25px padding is subtracted): the full wordmark no
   longer fits, so swap to the mark-only red glyph instead of just hiding it
   outright, mirroring how `.logo-text` used to disappear here while the old
   icon stayed. Restored on hover, same as `.logo-text` above. */
.brand-mark {
    display: none;
    height: 18px;
    width: auto;
}

[sidebar-data-theme='sidebar-hide'] .sidebar-area:not(:hover) .brand-wordmark--light,
[sidebar-data-theme='sidebar-hide'] .sidebar-area:not(:hover) .brand-wordmark--dark {
    display: none;
}

[sidebar-data-theme='sidebar-hide'] .sidebar-area:not(:hover) .brand-mark {
    display: inline-block;
}

/* Brand primary color (#210D32), overriding Trezo's own --bs-primary and
 * everything Bootstrap derives from it (theme/trezo/style.css bakes literal
 * hex into these — a plain hue swap at :root is not enough by itself).
 *
 * `.text-primary`/`.bg-primary`/`.border-primary` and the plain `a` link
 * color already read `var(--bs-primary-rgb)`/`var(--bs-link-color-rgb)` at
 * runtime, so overriding those here is enough for them. `.btn-primary`
 * itself is NOT: Bootstrap's button component bakes its own literal
 * `--bs-btn-*` custom properties per class (not `var(--bs-primary)`), so its
 * base/hover/active/focus shades are restated below using the exact same
 * multipliers Trezo's own compiled `.btn-primary` uses on ITS primary
 * (verified against the vendored file: hover-bg 85%, hover-border 80%,
 * active-bg 80%, active-border 75%, focus-shadow-rgb tinted +20% white).
 *
 * Dark mode: #210D32 is a near-black violet — unreadable as a button/link
 * color on the dark theme's own near-black background, so [data-theme=dark]
 * gets a lighter tint of the SAME hue (~272°) instead of the literal brand
 * hex, following Bootstrap's own light-on-dark convention (its dead
 * [data-bs-theme=dark] block, never active here since this app toggles
 * [data-theme] not [data-bs-theme], does the same thing to ITS primary).
 * bg-subtle/border-subtle darken further (mixed toward black) rather than
 * lighten, matching that same dead block's own dark-mode direction — they
 * sit on a dark page background, not a light one.
 */
:root {
    --bs-primary: #210D32;
    --bs-primary-rgb: 33, 13, 50;
    --bs-link-color: #210D32;
    --bs-link-color-rgb: 33, 13, 50;
    --bs-link-hover-color: rgb(26.4, 10.4, 40);
    --bs-link-hover-color-rgb: 26, 10, 40;
    --bs-primary-text-emphasis: rgb(13.2, 5.2, 20);
    --bs-primary-bg-subtle: rgb(233, 231, 235);
    --bs-primary-border-subtle: rgb(188, 182, 194);
}

:root[data-theme='dark'] {
    --bs-primary: #9D61D1;
    --bs-primary-rgb: 157, 97, 209;
    --bs-link-color: #9D61D1;
    --bs-link-color-rgb: 157, 97, 209;
    --bs-link-hover-color: rgb(178.6, 137.7, 220.7);
    --bs-link-hover-color-rgb: 179, 138, 221;
    --bs-primary-text-emphasis: rgb(186, 144, 223);
    --bs-primary-bg-subtle: rgb(24, 15, 31);
    --bs-primary-border-subtle: rgb(55, 34, 73);
}

.btn-primary {
    --bs-btn-color: #fff;
    --bs-btn-bg: #210D32;
    --bs-btn-border-color: #210D32;
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: rgb(28.05, 11.05, 42.5);
    --bs-btn-hover-border-color: rgb(26.4, 10.4, 40);
    --bs-btn-focus-shadow-rgb: 76.4, 61.4, 91;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: rgb(26.4, 10.4, 40);
    --bs-btn-active-border-color: rgb(24.75, 9.75, 37.5);
    --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: #210D32;
    --bs-btn-disabled-border-color: #210D32;
}

:root[data-theme='dark'] .btn-primary {
    --bs-btn-color: #fff;
    --bs-btn-bg: #9D61D1;
    --bs-btn-border-color: #9D61D1;
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: rgb(133.45, 82.45, 177.65);
    --bs-btn-hover-border-color: rgb(125.6, 77.6, 167.2);
    --bs-btn-focus-shadow-rgb: 173.4, 122.4, 219;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: rgb(125.6, 77.6, 167.2);
    --bs-btn-active-border-color: rgb(117.75, 72.75, 156.75);
    --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: #9D61D1;
    --bs-btn-disabled-border-color: #9D61D1;
}

/* === grid === */
/*
 * Shared "AG Grid-like" list chrome (BNB-GAP grid enhancement): sortable
 * column headers, per-column filter popovers (native <details>) and the
 * bottom pagination bar, reused by every list this rollout touches
 * (/produkty, /klienci, …) via templates/_partials/grid/_macros.html.twig
 * and assets/controllers/grid_controller.js. Bootstrap/Trezo primitives
 * (.table, .badge, .pagination, .form-select …) stay untouched — this block
 * only styles the new grid-specific pieces layered on top of them.
 */
.grid-toolbar__search {
    max-width: 20rem;
}

.grid-sort-link {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    color: inherit;
    text-decoration: none;
    font-weight: 600;
    white-space: nowrap;
}

.grid-sort-link:hover,
.grid-sort-link:focus-visible {
    color: var(--bs-primary);
}

.grid-sort-link--active {
    color: var(--bs-primary);
}

.grid-sort-link__idle-icon {
    opacity: 0.35;
}

.grid-table th {
    vertical-align: middle;
}

.grid-th {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

/* Native <details>/<summary> disclosure — the filter panel works with zero
 * JS (a click toggles `open`); grid_controller.js only enforces "one open at
 * a time" and lets the page-size select auto-submit for JS-capable browsers. */
.grid-filter {
    position: relative;
    display: inline-block;
}

.grid-filter__trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 0.25rem;
    cursor: pointer;
    color: var(--bs-secondary-color, #6c757d);
    list-style: none;
}

.grid-filter__trigger::-webkit-details-marker {
    display: none;
}

.grid-filter[open] > .grid-filter__trigger,
.grid-filter--active > .grid-filter__trigger {
    color: var(--bs-primary);
    background: var(--bs-primary-bg-subtle);
}

.grid-filter__panel {
    position: absolute;
    z-index: 20;
    top: calc(100% + 0.25rem);
    left: 0;
    min-width: 12rem;
    padding: 0.75rem;
    background: var(--bs-body-bg, #fff);
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.5rem;
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
    font-weight: normal;
}

.grid-pagination__range {
    white-space: nowrap;
}

.grid-pagination__page {
    font-weight: 600;
}

/* Rozpis "Rozdzielenie pionów Marketing/Software" (D9/D10/U1/U3): topbar
   pion pill switcher + division badges on cards/rows. Brand primary
   (#210D32) marks the active pill, matching the wordmark/logo color. */
.division-switch__pill {
    border: 1px solid var(--bs-border-color, #dee2e6);
    color: var(--bs-body-color, #212529);
    background-color: transparent;
    text-decoration: none;
}

.division-switch__pill.active {
    background-color: #210D32;
    border-color: #210D32;
    color: #fff;
}

.division-badge--marketing {
    background-color: rgba(13, 110, 253, 0.1);
    color: #0d6efd;
}

.division-badge--software {
    background-color: rgba(111, 66, 193, 0.12);
    color: #6f42c1;
}

.division-badge--none {
    background-color: rgba(var(--bs-secondary-rgb), 0.1);
    color: var(--bs-secondary, var(--color-text));
}

/* === PANEL-GEAR (BRAND-NEW-BRAND panel personalization) ===
   These two containers previously stacked their children with plain
   `display: block` (the default) — flex + column keeps the EXACT same
   visual top-to-bottom stacking, it only additionally makes each child's
   inline `order` (panel_section_attrs()) actually take effect. Every other
   panel this feature touches (client_card_overview's CSS grid, the
   Bootstrap `.row`-based home/settings tile grids) already supports
   `order` without any CSS change. */
.product-card-sections {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.engagement-page-grid {
    display: flex;
    flex-direction: column;
}

/* === bnb-products-list === */
/* /produkty (user request): the table used to sit under a standalone
   search/filter toolbar and had no side gutter of its own beyond
   `.main-content`'s fixed 12px right padding — this class replaces that
   toolbar's real estate with a plain, consistent side gutter instead, no
   card/column-limiting container, so the grid genuinely spans the
   available content width instead of sitting in a narrower column. Side
   padding only (not top/bottom): `h1`/`.page-header`-style spacing already
   comes from existing rules. */
.products-page-content {
    padding-inline: 1.5rem;
}

@media (max-width: 640px) {
    .products-page-content {
        padding-inline: 1rem;
    }
}

/* === software-dashboard-panel === */
/* /software "Projekty" tab panel gear (docs/panel-layouts.md, step 3): a
   plain block container does not support CSS `order`, needed for the panel
   editor's drag live-preview to take effect — same pattern as
   .product-card-sections/.engagement-page-grid above. */
.software-dashboard-sections {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* === UX restyle (client style) ===
 * Audyt UX/UI 2026-09-17 (docs onepager/analiza-kart context): "budujemy
 * UX tak, jak mieli [klienta prototyp], ale z naszym menu i naszymi
 * kolorami" — this whole block is purely ADDITIVE (BNB-GAP-W05: never
 * replaces a class protected by docs/ui/trezo-mapping.md, only extends it
 * with new classes alongside).
 */

/* Stream A1: "label-above-value" rhythm — the client prototype's single most
 * recognizable pattern (small grey uppercase label above a large bold
 * value). Reused wherever a screen wants an immediate "at a glance" number:
 * client/product card headers, risk board, dashboard tiles. */
.stat-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5) var(--space-6);
    margin: 0 0 var(--space-4);
}

.stat-row__item {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 6rem;
}

.stat-row__label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.stat-row__value {
    font-size: var(--font-size-lg);
    font-weight: 700;
    color: var(--color-text);
    overflow-wrap: anywhere;
}

.stat-row__value--muted {
    color: var(--color-text-muted);
    font-weight: 600;
}

/* Compact variant for table cells (client/product list rows): same rhythm,
 * smaller type so it fits inside a `<td>` without inflating Trezo's own
 * table row height. */
.stat-row--compact .stat-row__value {
    font-size: var(--font-size-base);
}

.stat-row--compact .stat-row__label {
    font-size: 10px;
}

.stat-row__pills {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

@media (max-width: 480px) {
    .stat-row {
        gap: var(--space-4);
    }
}

/* Stream A2: left accent bar on a KPI goal card, colored by status — the
 * client prototype's other signature accent (a colored vertical bar on an
 * otherwise neutral nested card). Additive modifiers beside the existing,
 * test-protected `.kpi-goal`/`.kpi-goal--unmeasured` — never replaces them,
 * a goal keeps both classes at once (see _kpi_goal.html.twig). Uses the same
 * `--bs-success/warning/danger` tokens `.badge--*` already reads, so this
 * follows the same light/dark theming for free. */
.kpi-goal--success {
    border-left: 4px solid var(--bs-success, var(--color-success));
}

.kpi-goal--warning {
    border-left: 4px solid var(--bs-warning, var(--color-warning));
}

.kpi-goal--error {
    border-left: 4px solid var(--bs-danger, var(--color-error));
}

/* Stream A3: neutral "card-in-card" background for nested lists (services,
 * resources, budget history rows) — the client prototype separates a nested
 * card from its parent with a filled neutral tile, not just a border. */
.inset-panel {
    background: var(--color-neutral-bg);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
}
