:root {
    color-scheme: dark;
    --bg: #0f1115;
    --surface: #171a21;
    --border: #262b36;
    --text: #e6e8eb;
    --muted: #9aa3b2;
    --primary: #23d887;
    --link: #3898ec;
    --on-primary: #04130c;
    --danger: #f7546a;
    /* Červený štítek („rozbitý", „vypnuto") — pozadí + text jako pár. Samotný --danger
       na chip nestačí a dvojice hexů rozesetá po šablonách se rozejde. Záměrně stejná
       v obou režimech: tohle je sjednocení zápisu, ne předělávka tmavého motivu. */
    --danger-bg: #fee2e2;
    --danger-fg: #991b1b;
}

:root[data-theme="light"] {
    color-scheme: light;
    --bg: #f4f6f9;
    --surface: #ffffff;
    --border: #e2e6ec;
    --text: #1a1d23;
    --muted: #5c6573;
    --primary: #16a368;
    --link: #2563eb;
    --on-primary: #ffffff;
    --danger: #d83452;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.5;
}

a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ── App shell: fixed left sidebar + scrollable content column ───────── */
.app-shell { display: flex; min-height: 100vh; }

.sidebar {
    position: sticky;
    top: 0;
    align-self: flex-start;
    flex: 0 0 240px;
    height: 100vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    padding: 1.25rem 0.85rem;
    background: var(--surface);
    border-right: 1px solid var(--border);
}

.sidebar .brand {
    font-weight: 700;
    color: var(--primary);
    font-size: 1.1rem;
    padding: 0.25rem 0.65rem;
}
.sidebar .brand:hover { text-decoration: none; }

.sidebar-nav { display: flex; flex-direction: column; gap: 1.25rem; }
.nav-group { display: flex; flex-direction: column; gap: 0.15rem; }
.nav-group-label {
    color: var(--muted);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    padding: 0 0.65rem 0.25rem;
}

.nav-link {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.5rem 0.65rem;
    border-radius: 8px;
    color: var(--text);
    font-size: 0.92rem;
    font-weight: 500;
    border-left: 3px solid transparent;
}
.nav-link:hover { background: var(--bg); text-decoration: none; }
.nav-link.is-active {
    background: var(--bg);
    color: var(--primary);
    border-left-color: var(--primary);
}
/* Počet čekajících položek u odkazu v navigaci (fronta vad ceníku, plán 0053). */
.nav-badge {
    margin-left: auto;
    padding: 0.05rem 0.4rem;
    border-radius: 999px;
    background: #d97706;
    color: #fff;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.4;
}
.nav-icon { flex: 0 0 auto; opacity: 0.85; }
.nav-link.is-active .nav-icon { opacity: 1; }

/* Collapsible nav section — native <details>, no JavaScript. */
.nav-collapsible { display: flex; flex-direction: column; gap: 0.15rem; }
.nav-collapsible > summary { cursor: pointer; list-style: none; }
.nav-collapsible > summary::-webkit-details-marker { display: none; }
.nav-collapsible-summary::after {
    content: '';
    margin-left: auto;
    width: 0.45rem;
    height: 0.45rem;
    border-right: 2px solid var(--muted);
    border-bottom: 2px solid var(--muted);
    transform: rotate(-45deg);
    transition: transform 0.15s ease;
}
.nav-collapsible[open] .nav-collapsible-summary::after { transform: rotate(45deg); }
.nav-subgroup { display: flex; flex-direction: column; gap: 0.15rem; padding-left: 1.4rem; margin-top: 0.15rem; }

/* ── Content column: sticky topbar + scrolling main ──────────────────── */
.app-content { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.75rem 1.5rem;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}
.topbar-title { margin: 0; font-size: 1.15rem; font-weight: 600; }
.topbar-actions { margin-left: auto; display: flex; align-items: center; gap: 0.85rem; }

/* ── Breadcrumbs (drobečková navigace) ───────────────────────────────── */
.breadcrumbs { min-width: 0; }
.breadcrumbs__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    font-size: 1.05rem;
}
.breadcrumbs__item { display: inline-flex; align-items: center; gap: 0.4rem; min-width: 0; }
.breadcrumbs__item:not(:first-child)::before { content: "/"; color: var(--muted); opacity: 0.55; }
.breadcrumbs__link { color: var(--muted); text-decoration: none; white-space: nowrap; }
.breadcrumbs__link:hover { color: var(--link); text-decoration: underline; }
.breadcrumbs__current {
    color: var(--text);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Theme switch lives in the user dropdown — a menu item that flips the label
   + icon by theme (sun → switch to light, moon → switch to dark). */
button.user-menu-item { width: 100%; background: none; border: 0; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.theme-switch__dark, .theme-switch__light { display: inline-flex; align-items: center; gap: 0.55rem; }
.theme-switch__light { display: none; }
:root[data-theme="light"] .theme-switch__dark { display: none; }
:root[data-theme="light"] .theme-switch__light { display: inline-flex; }

/* AI Agent health indicator — dot + hover tooltip. */
.agent-health { position: relative; display: inline-flex; align-items: center; gap: 0.4rem; cursor: default; }
.agent-health__dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.agent-health__dot.is-ok { background: var(--primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 22%, transparent); }
.agent-health__dot.is-down { background: var(--danger); box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 22%, transparent); }
.agent-health__label { font-size: 0.82rem; color: var(--muted); }
.agent-health__pop {
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    z-index: 50;
    min-width: 15rem;
    display: none;
    flex-direction: column;
    gap: 0.3rem;
    padding: 0.7rem 0.85rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
}
/* Transparent bridge across the gap so the cursor can travel from the badge
   into the tooltip without un-hovering and hiding it. */
.agent-health__pop::before { content: ""; position: absolute; top: -0.5rem; left: 0; right: 0; height: 0.5rem; }
.agent-health:hover .agent-health__pop,
.agent-health:focus-within .agent-health__pop { display: flex; }
.agent-health__pop-head { font-weight: 600; margin-bottom: 0.15rem; }
.agent-health__row { display: flex; justify-content: space-between; gap: 1rem; font-size: 0.82rem; color: var(--muted); }
.agent-health__row-note { color: var(--text); }
.agent-health__row.is-bad .agent-health__row-note { color: var(--danger); font-weight: 600; }
.agent-health__link { display: inline-flex; align-items: center; gap: 0.4rem; color: inherit; }
.agent-health__link:hover { text-decoration: none; }

/* AI diagnostics page. */
/* Karty diagnostiky stojí ve sloupci s jednotnou mezerou — stejná 1.5rem jako
   u ostatních skládaných karet v aplikaci (AI prompty, reporting). */
.ai-stack { display: flex; flex-direction: column; gap: 1.5rem; }
.ai-card-title { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 0.9rem; font-size: 1.05rem; }
.ai-checks, .ai-config, .ai-tools, .ai-runs { width: 100%; border-collapse: collapse; }
.ai-checks td, .ai-config td { padding: 0.35rem 0; border-bottom: 1px solid var(--border); }
.ai-checks__label, .ai-config td:first-child { color: var(--muted); width: 40%; }
.ai-checks tr.is-bad .ai-checks__note { color: var(--danger); font-weight: 600; }
.ai-tools td { padding: 0.45rem 0; border-bottom: 1px solid var(--border); vertical-align: top; }
.ai-tools__name { width: 30%; white-space: nowrap; }
.ai-tools__desc { color: var(--muted); }
.ai-runs th { text-align: left; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); padding: 0.35rem 0.6rem 0.35rem 0; border-bottom: 1px solid var(--border); }
.ai-runs td { padding: 0.45rem 0.6rem 0.45rem 0; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
.ai-runs__text { color: var(--muted); }
.ai-status { font-size: 0.78rem; padding: 0.1rem 0.45rem; border-radius: 999px; background: var(--bg); border: 1px solid var(--border); }
.ai-status--failed { color: var(--danger); }
.ai-status--completed { color: var(--primary); }

/* AI connection test. */
.agent-test__bar { display: flex; align-items: center; gap: 0.85rem; flex-wrap: wrap; }
.agent-test__warn { color: var(--muted); font-size: 0.82rem; }
.agent-test__loading { color: var(--muted); font-size: 0.85rem; }
.agent-test__result { margin-top: 0.9rem; padding: 0.7rem 0.85rem; border-radius: 8px; border: 1px solid var(--border); display: flex; flex-direction: column; gap: 0.35rem; }
.agent-test__result.is-ok { border-color: color-mix(in srgb, var(--primary) 50%, var(--border)); }
.agent-test__result.is-bad { border-color: color-mix(in srgb, var(--danger) 50%, var(--border)); }
.agent-test__result small { color: var(--muted); }

/* User menu — native <details> dropdown, no JS. */
.user-menu { position: relative; }
.user-menu > summary {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.3rem 0.5rem 0.3rem 0.35rem;
    border-radius: 8px;
    cursor: pointer;
    list-style: none;
    color: var(--text);
    font-size: 0.9rem;
}
.user-menu > summary::-webkit-details-marker { display: none; }
.user-menu > summary:hover { background: var(--bg); }
.user-menu[open] > summary { background: var(--bg); }
.avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--primary);
    color: var(--on-primary);
    font-weight: 700;
    font-size: 0.8rem;
}
.user-name { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-menu[open] > summary .nav-icon { transform: rotate(180deg); }

.user-menu-pop {
    position: absolute;
    right: 0;
    top: calc(100% + 0.4rem);
    min-width: 200px;
    display: flex;
    flex-direction: column;
    padding: 0.35rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
}
.user-menu-head {
    padding: 0.4rem 0.6rem;
    color: var(--muted);
    font-size: 0.8rem;
    border-bottom: 1px solid var(--border);
    margin-bottom: 0.25rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.user-menu-item {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.5rem 0.6rem;
    border-radius: 7px;
    color: var(--text);
    font-size: 0.9rem;
}
.user-menu-item:hover { background: var(--bg); text-decoration: none; }

.app-main { flex: 1 1 auto; min-width: 0; width: 100%; padding: 2rem 1.5rem; }

/* ── Mobile: sidebar collapses to a top strip ────────────────────────── */
@media (max-width: 768px) {
    .app-shell { flex-direction: column; }
    .sidebar {
        position: static;
        flex-basis: auto;
        height: auto;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        gap: 0.5rem 1rem;
        border-right: none;
        border-bottom: 1px solid var(--border);
    }
    .sidebar-nav { flex-direction: row; flex-wrap: wrap; gap: 0.25rem 0.75rem; }
    .nav-group { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 0.25rem; }
    .nav-group-label { display: none; }
    .nav-link { border-left: none; padding: 0.4rem 0.6rem; }
    .nav-link.is-active { border-left: none; }
    .user-name { display: none; }
}

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1.25rem 1.5rem;
}

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 0.6rem 0.5rem; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-weight: 600; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.03em; }

.btn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: var(--primary);
    color: var(--on-primary);
    font-weight: 600;
    border: none;
    border-radius: 8px;
    padding: 0.5rem 0.9rem;
    cursor: pointer;
}
.btn.ghost { background: transparent; color: var(--text); border: 1px solid var(--border); }
/* Tlačítko destruktivní akce s popiskem — kaskádové smazání na detailu, kde ikona sama
   nese příliš málo informace („smaže i zakázku, nabídky a přílohy"). */
.btn.is-danger { background: transparent; color: var(--danger); border: 1px solid var(--danger); }

/* JEDINÁ podoba akce bez popisku v řádku seznamu — tužka, ozubené kolo, popelnice.
   `.btn-icon.is-danger` je jediná podoba MAZÁNÍ v aplikaci: popelnice `ic.icon('trash')`
   v barvě `--danger`. Nikdy emoji 🗑, nikdy „×", nikdy vlastní inline SVG a nikdy hex
   natvrdo — ten nepřežije tmavý režim. Konvence: .claude/skills/frontend-twig-ux/SKILL.md
   → „Ikony a mazání". */
.btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: none;
    border: 0;
    color: var(--muted);
    cursor: pointer;
}
.btn-icon:hover { color: var(--text); }
.btn-icon.is-danger { color: var(--danger); }
.btn-icon.is-danger:hover { color: var(--danger); filter: brightness(1.15); }

/* Drobná ikonová akce u textu (kopírování čísla případu). Bez rámečku a šedá, aby
   nesoupeřila s hlavními tlačítky — zvýrazní se až pod kurzorem. Po kliknutí se
   ikona přepne na fajfku; potvrzení patří na tlačítko, ne do flash zprávy. */
.icon-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    background: none;
    border: 0;
    border-radius: 6px;
    color: var(--muted);
    cursor: pointer;
}
.icon-action:hover { background: var(--surface); color: var(--text); }
.icon-action:focus-visible { outline: 2px solid var(--link); outline-offset: 1px; }
.icon-action .icon-action-idle,
.icon-action[data-copied] .icon-action-done { display: inline-flex; }
.icon-action .icon-action-done,
.icon-action[data-copied] .icon-action-idle { display: none; }
.icon-action[data-copied] { color: var(--primary); }

/* A button that reads as a text link — for inline actions inside a table row or a
   toolbar. `.danger` marks a destructive one (smazat, vyčistit): the markup asked for
   it in several places while the rule was missing, so those actions read in the brand
   colour, which is exactly the wrong signal. */
.link-button {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: var(--primary);
    cursor: pointer;
    text-decoration: none;
}
.link-button:hover { text-decoration: underline; }
.link-button.danger { color: var(--danger); }

/* Segmented control — a labelled radio group styled as a row of pill buttons.
   Discrete choices (length, tone) the AI prompt maps to; the hidden radio drives
   state so :has(:checked) highlights the active segment with no JS. */
.segmented {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
}
.segmented__opt {
    position: relative;
    display: inline-flex;
    /* The option is a <label>; kill the global `label` bottom margin, which
       otherwise paints a stripe under the pills inside the bordered group. */
    margin: 0;
}
.segmented__opt + .segmented__opt {
    border-left: 1px solid var(--border);
}
.segmented__opt input[type="radio"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}
.segmented__opt span {
    padding: 0.45rem 0.9rem;
    font-size: 0.9rem;
    color: var(--text);
    user-select: none;
    white-space: nowrap;
}
.segmented__opt:has(input:checked) span {
    background: var(--primary);
    color: var(--on-primary);
    font-weight: 600;
}
.segmented__opt:has(input:focus-visible) span {
    outline: 2px solid var(--primary);
    outline-offset: -2px;
}

/* Modal dialog — backdrop fades in, dialog pops up (Bootstrap/Metronic style). */
.modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: rgba(0, 0, 0, 0.55);
    animation: modal-backdrop-in 0.18s ease-out;
}
.modal-dialog {
    width: 100%;
    max-width: 440px;
    animation: modal-dialog-in 0.22s cubic-bezier(0.2, 0.8, 0.25, 1);
}
.modal-dialog--wide { max-width: 720px; }

/* AI preview: one selectable card per generated block. Whole card is a <label>,
   so a click anywhere toggles its checkbox; :has() reflects the state live. */
.ai-block {
    display: block;
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.7rem 0.85rem;
    margin-bottom: 0.6rem;
    transition: border-color 0.15s ease, opacity 0.15s ease;
}
.ai-block:has(input) { cursor: pointer; }
.ai-block:has(input:checked) { border-color: var(--primary); }
.ai-block:has(input):not(:has(input:checked)) { opacity: 0.5; }
.ai-block__title { font-weight: 600; }
.ai-block input[type="checkbox"] { width: auto; margin-right: 0.5rem; vertical-align: middle; }
.ai-block p { margin: 0.35rem 0 0; }
.ai-block ul { margin: 0.35rem 0 0; }
@keyframes modal-backdrop-in {
    from { opacity: 0; }
    to { opacity: 1; }
}
@keyframes modal-dialog-in {
    from { opacity: 0; transform: translateY(-14px) scale(0.96); }
    to { opacity: 1; transform: translateY(0) scale(1); }
}
/* Zavírání — modal_controller přidá .modal-backdrop--closing, dohraje exit
   animaci a teprve pak spustí odebrání z DOM (LiveComponent akci). */
.modal-backdrop--closing { animation: modal-backdrop-out 0.16s ease-in forwards; }
.modal-backdrop--closing .modal-dialog { animation: modal-dialog-out 0.18s ease-in forwards; }
@keyframes modal-backdrop-out {
    from { opacity: 1; }
    to { opacity: 0; }
}
@keyframes modal-dialog-out {
    from { opacity: 1; transform: translateY(0) scale(1); }
    to { opacity: 0; transform: translateY(-14px) scale(0.96); }
}
@media (prefers-reduced-motion: reduce) {
    .modal-backdrop, .modal-dialog,
    .modal-backdrop--closing, .modal-backdrop--closing .modal-dialog { animation: none; }
}

input, textarea, .field {
    width: 100%;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.55rem 0.7rem;
    color: var(--text);
}

/* Zaškrtávátko ani rádio není textové pole — globální `width: 100 %` výše je
   roztahovalo přes celý řádek a rozhodilo každý seznam s výběrem (proto si to
   jednotlivé komponenty přebíjely dokola). Normalizace patří sem, jednou.
   Výjimku má .segmented, kde je rádio vědomě neviditelná plocha přes celý pill —
   ta si to bere zpět vyšší specificitou (`.segmented__opt input[type="radio"]`). */
input[type="checkbox"], input[type="radio"] {
    width: auto;
    padding: 0;
    accent-color: var(--primary);
    cursor: pointer;
}

/* All multi-line text areas share one height; only vertical resize allowed. */
textarea, textarea.field {
    min-height: 11rem;
    font: inherit;
    line-height: 1.5;
    resize: vertical;
}

label { display: block; margin-bottom: 0.35rem; color: var(--muted); font-size: 0.9rem; }
/* Zaškrtávátko a nápověda z bootstrapového form themu (`form_row` u CheckboxType,
   volba `help`). Theme kreslí `<div class="form-check"><input><label>` a
   `<div class="form-text">`, ale bootstrapové CSS v projektu **není** — bez těchto
   pravidel spadne popisek POD čtvereček (globální `label{display:block}`) a nápověda
   vyjde větší a výraznější než popisek, ke kterému patří. Platí pro všechny formuláře
   (schránka, kontakt, služba, středisko, import textilu), ne jen pro jednu obrazovku. */
.form-check { display: flex; align-items: center; gap: 0.45rem; margin-bottom: 0.35rem; }
.form-check-input { flex: none; margin: 0; }
.form-check-label { display: inline; margin: 0; color: var(--text); font-size: inherit; cursor: pointer; }
.form-text { font-size: 0.8rem; color: var(--muted); }

/* Symfony tags required fields' labels with .required — mark them with an asterisk. */
label.required::after { content: " *"; content: " *" / ""; color: var(--danger); font-weight: 600; }
.form-row { margin-bottom: 1rem; }
/* Vysvětlivka hvězdičky nad dlouhým formulářem (poptávka). Bydlela v <style> uvnitř
   šablony spolu s tehdejší lokální opravou hlášek — ta se přestěhovala do form themu,
   tohle sem. */
.form-legend { color: var(--muted); font-size: 0.85rem; margin: 0 0 1.25rem; }
.form-legend .req { color: var(--danger); font-weight: 700; }
.search { max-width: 320px; margin-bottom: 1rem; }

/* ── Chyby formuláře ──────────────────────────────────────────────────────
   Vzhled hlášek je JEDEN pro celou aplikaci; kreslí je form theme
   (templates/form/westprint_layout.html.twig), ne jednotlivé obrazovky. Dřív
   měl červenou hlášku jen formulář poptávky, který si ji doma přebil vlastním
   <style> — všude jinde vyšla chyba jako obyčejný text pod polem, k nerozeznání
   od nápovědy. */
.field-errors { list-style: none; margin: 0.3rem 0 0; padding: 0; }
.field-error {
    display: flex;
    align-items: baseline;
    gap: 0.35rem;
    color: var(--danger);
    font-size: 0.82rem;
    line-height: 1.35;
}
.field-error + .field-error { margin-top: 0.15rem; }
/* Nápověda stojí až za hláškou (viz pořadí v form themu) — ať se jí nelepí na patu. */
.field-errors + .form-text { margin-top: 0.25rem; }
/* Vykřičník kreslí CSS, ne šablona: patří ke vzhledu a do textu hlášky (a tím
   do čtečky obrazovky) nemá co plést. */
.field-error::before { content: "!"; font-weight: 700; }

/* Chybné pole se pozná i bez čtení hlášky. Třídu .is-invalid dává widgetu
   bootstrapí theme, ze kterého ten náš dědí. */
.field.is-invalid, input.is-invalid, select.is-invalid, textarea.is-invalid {
    border-color: var(--danger);
}
.field.is-invalid:focus, input.is-invalid:focus, select.is-invalid:focus, textarea.is-invalid:focus {
    outline: 2px solid color-mix(in srgb, var(--danger) 45%, transparent);
    outline-offset: 1px;
}
/* Tom Select má vlastní obal — červený rámeček se mu dává až v jeho vlastní sekci
   níže, kde na něj dosáhne specificitou. */

/* Souhrn nad formulářem: co všechno je špatně, na jednom místě a proklikem
   na pole. Bez něj je na dlouhém formuláři třetí chyba pod přehybem. */
.form-alert {
    margin: 0 0 1.25rem;
    padding: 0.85rem 1rem;
    border: 1px solid color-mix(in srgb, var(--danger) 45%, var(--border));
    border-left: 3px solid var(--danger);
    border-radius: 8px;
    background: color-mix(in srgb, var(--danger) 8%, var(--surface));
}
.form-alert__title { margin: 0; font-size: 0.9rem; font-weight: 600; color: var(--text); }
.form-alert__list { margin: 0.5rem 0 0; padding-left: 1.15rem; font-size: 0.85rem; color: var(--muted); }
.form-alert__list li + li { margin-top: 0.2rem; }
.form-alert__list a { color: var(--danger); font-weight: 600; }

/* Cíl odkazu ze souhrnu (`href="#id_pole"`) musí skončit POD lepivým topbarem.
   Bez odsazení doroluje prohlížeč pole přesně na horní hranu viewportu, topbar
   ho zakryje i s popiskem a vypadá to, že odkaz vede někam do prostředka stránky.
   Odsazení = topbar (~4 rem) + popisek a mezera, ať je vidět, ke kterému poli
   hláška patří.

   Pozor, `:target { scroll-margin-top }` (jinak obvyklé řešení) tady NEFUNGUJE:
   odkaz v rámci stránky obslouží Turbo přes history.pushState a při tom prohlížeč
   `:target` nepřepočítá — pravidlo by chytlo jen při přímém otevření adresy
   s fragmentem, ne při kliknutí v souhrnu. Proto odsazení nepodmíněně na polích;
   platí i pro doskrolování odjinud, topbar je lepivý pořád. */
input, select, textarea, .field { scroll-margin-top: 6rem; }

/* Two-column responsive field grid. Short fields sit side by side; fields that
   need the full width opt in with .span-2. Collapses to one column on narrow
   viewports. */
.form-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 1.5rem;
}
.form-grid .form-row { margin-bottom: 1.1rem; }
.form-grid .span-2 { grid-column: 1 / -1; }

.form-section {
    grid-column: 1 / -1;
    margin: 0.5rem 0 0.25rem;
    padding-top: 0.85rem;
    border-top: 1px solid var(--border);
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.form-section:first-child { margin-top: 0; padding-top: 0; border-top: none; }

@media (max-width: 560px) {
    .form-grid { grid-template-columns: 1fr; }
}

/* ---- Data grid: total count, per-page selector, pager ---- */
.datagrid-toolbar {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    margin-bottom: 0.6rem;
    color: var(--muted);
    font-size: 0.85rem;
}

.datagrid-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 1rem;
    color: var(--muted);
    font-size: 0.85rem;
}
.datagrid-footer .datagrid-info { display: flex; align-items: center; gap: 0.6rem; }

/* Narrow, auto-width version of the .field select — sits inline in the footer. */
.datagrid-perpage {
    width: auto;
    padding: 0.3rem 1.6rem 0.3rem 0.6rem;
    font-size: 0.85rem;
    cursor: pointer;
}

.datagrid-pager { display: inline-flex; gap: 0.3rem; }
.btn-page {
    min-width: 2rem;
    height: 2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 0.5rem;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 0.9rem;
    line-height: 1;
    cursor: pointer;
    transition: border-color 0.12s ease, background 0.12s ease, color 0.12s ease;
}
.btn-page:hover:not(:disabled):not(.is-active) {
    border-color: var(--primary);
    color: var(--primary);
}
.btn-page.is-active {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
    font-weight: 600;
    cursor: default;
}
.btn-page:disabled { opacity: 0.4; cursor: not-allowed; }
.datagrid-ellipsis { padding: 0 0.15rem; color: var(--muted); align-self: center; }

/* ---- Dense data grid (Excel-style): scroll, sticky head, filters, sort, resize, columns ----
   The compact list the client asked for (meeting 22.7.2026): many rows on screen,
   filters in the column headers, click-to-sort, drag-to-resize and show/hide columns. */
.datagrid-toolbar {
    justify-content: flex-start;
    gap: 0.75rem;
}
.datagrid-count { margin-left: auto; white-space: nowrap; }
.datagrid-search { width: auto; flex: 0 1 18rem; margin: 0; font-size: 0.82rem; padding: 0.3rem 0.55rem; }

/* Uložená zobrazení (plán 0042, Z5): roletka pojmenovaných kombinací sloupců, šířek,
   filtrů a řazení — vlevo v panelu, protože se z ní vybírá jako první. */
.datagrid-views { display: flex; align-items: center; gap: 0.35rem; }
.datagrid-views-select { width: auto; margin: 0; font-size: 0.82rem; padding: 0.3rem 0.55rem; max-width: 12rem; }
.datagrid-views-btn {
    padding: 0.3rem 0.55rem;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 0.82rem;
    cursor: pointer;
    white-space: nowrap;
}
.datagrid-views-btn:hover { border-color: var(--primary); color: var(--primary); }
.datagrid-views-save { display: inline-flex; align-items: center; gap: 0.35rem; }
.datagrid-views-save[hidden] { display: none; }
.datagrid-views-save .field { width: auto; margin: 0; font-size: 0.82rem; padding: 0.3rem 0.55rem; max-width: 11rem; }

/* Column picker: a button that drops a checkbox menu built client-side. */
.datagrid-columns { position: relative; }
.datagrid-columns-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.6rem;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 0.85rem;
    cursor: pointer;
}
.datagrid-columns-btn:hover { border-color: var(--primary); color: var(--primary); }
.datagrid-columns-menu {
    position: absolute;
    top: calc(100% + 0.3rem);
    left: 0;
    z-index: 20;
    min-width: 12rem;
    max-height: 60vh;
    overflow-y: auto;
    padding: 0.35rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.datagrid-columns-menu label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.35rem 0.5rem;
    border-radius: 6px;
    font-size: 0.85rem;
    cursor: pointer;
    white-space: nowrap;
}
.datagrid-columns-menu label:hover { background: var(--bg); }
/* The global form styling stretches inputs to full width; keep the checkbox at
   its natural size so the label sits right next to it (not pushed to the right). */
.datagrid-columns-menu input { width: auto; flex: 0 0 auto; margin: 0; cursor: pointer; }

/* Scroll container — keeps the header (and filter row) pinned while the body scrolls. */
.datagrid-scroll {
    overflow: auto;
    max-height: 72vh;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface);
}

table.datagrid {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    table-layout: auto; /* controller switches to fixed once column widths are measured */
    font-size: 0.85rem;
}
table.datagrid th,
table.datagrid td {
    padding: 0.28rem 0.55rem;
    text-align: left;
    vertical-align: middle;
    border-bottom: 1px solid var(--border);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* The header labels stay pinned to the top of the scroll box; the filter row
   pins just below them. --dg-head-h is measured and set by the resize controller. */
table.datagrid thead .datagrid-head th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--surface);
    font-weight: 600;
    color: var(--muted);
    user-select: none;
}
/* Header cell inner layout: the sortable label grows, the filter funnel sits at
   the end. min-width:0 lets the label ellipsize when the column is dragged narrow. */
.datagrid-th {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
    width: 100%;
}
.datagrid-th > .datagrid-sort-label { flex: 1 1 auto; }

/* Filter funnel + popover (Excel-style per-column filtering, plan 0034 v2). */
.datagrid-filter { position: relative; flex: none; display: inline-flex; align-items: center; gap: 0.1rem; }
.datagrid-filter-btn,
.datagrid-filter-clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.15rem;
    height: 1.15rem;
    padding: 0;
    background: none;
    border: 0;
    color: var(--muted);
    cursor: pointer;
    border-radius: 4px;
}
.datagrid-filter-btn:hover,
.datagrid-filter-clear:hover { color: var(--primary); background: var(--bg); }
.datagrid-filter-btn.is-active { color: var(--primary); }
.datagrid-filter-clear { font-size: 1rem; line-height: 1; }

/* position:fixed so the popover escapes the grid's scroll container rather than
   being clipped by it; the controller sets top/left from the funnel's rect. */
.datagrid-filter-pop {
    position: fixed;
    z-index: 60;
    min-width: 12rem;
    max-width: 90vw;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    padding: 0.5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);
    font-weight: 400;
    color: var(--text);
    white-space: normal;
}
/* The class sets display:flex, which would otherwise beat the UA [hidden] rule
   and leave the popover permanently visible at 0,0 intercepting clicks. */
.datagrid-filter-pop[hidden] { display: none; }
.datagrid-filter-pop .field { margin: 0; width: 100%; font-size: 0.82rem; padding: 0.25rem 0.4rem; }
.datagrid-filter-enum { display: flex; flex-direction: column; gap: 0.15rem; max-height: 14rem; overflow: auto; }
.datagrid-filter-check { display: flex; align-items: center; gap: 0.4rem; font-size: 0.82rem; cursor: pointer; }
.datagrid-filter-check input { width: auto; flex: 0 0 auto; margin: 0; }
.datagrid-filter-actions { display: flex; gap: 0.4rem; justify-content: flex-end; }
.datagrid-filter-apply,
.datagrid-filter-cancel {
    padding: 0.25rem 0.6rem;
    font-size: 0.8rem;
    border-radius: 6px;
    cursor: pointer;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
}
.datagrid-filter-apply { background: var(--primary); border-color: var(--primary); color: var(--on-primary); font-weight: 600; }
.datagrid-filter-apply:hover { opacity: 0.9; }
.datagrid-filter-cancel:hover { border-color: var(--primary); color: var(--primary); }

/* Sortable header button — fills the cell, arrow shows the active direction. */
.datagrid-sort {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    flex: 1 1 auto;
    background: none;
    border: 0;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    font-weight: 600;
    cursor: pointer;
    text-align: left;
}
.datagrid-sort:hover { color: var(--primary); }
.datagrid-sort { min-width: 0; overflow: hidden; }
/* Let the label shrink and ellipsize when the column is dragged narrower than
   the word; the sort arrow keeps its size. */
.datagrid-sort-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.datagrid-sort-arrow { flex: none; font-size: 0.7rem; opacity: 0.4; }
.datagrid-sort.is-active { color: var(--text); }
.datagrid-sort.is-active .datagrid-sort-arrow { opacity: 1; color: var(--primary); }

/* Body rows: hover highlight, tighter alternating feel via hover only. */
table.datagrid tbody .datagrid-row:hover > td { background: var(--bg); }
table.datagrid tbody td a { color: var(--link); }
.datagrid-empty { padding: 0.6rem 0.55rem; color: var(--muted); white-space: normal; }

/* Resize handle: a grabbable strip on the right edge of each header cell.
   The header cells are position:sticky (above), which also anchors these. */
.datagrid-resizer {
    position: absolute;
    top: 0;
    right: 0;
    width: 7px;
    height: 100%;
    cursor: col-resize;
    user-select: none;
    touch-action: none;
}
.datagrid-resizer::after {
    content: '';
    position: absolute;
    top: 20%;
    right: 3px;
    width: 1px;
    height: 60%;
    background: var(--border);
}
.datagrid-head th:hover .datagrid-resizer::after { background: var(--primary); }
table.datagrid.is-resizing { user-select: none; cursor: col-resize; }

/* Expand chevron + subrow (nested detail, e.g. offers under an opportunity). */
.datagrid-expand-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.3rem;
    height: 1.3rem;
    padding: 0;
    background: none;
    border: 0;
    color: var(--muted);
    cursor: pointer;
    transition: transform 0.12s ease;
}
.datagrid-expand-btn.is-open { transform: rotate(90deg); color: var(--text); }
.datagrid-subrow > td { padding: 0; background: var(--bg); white-space: normal; }
.datagrid-subrow .datagrid-subrow-inner { padding: 0.35rem 0.55rem 0.5rem 2rem; }
.datagrid-col-expand { width: 2.2rem; padding-left: 0.2rem; padding-right: 0.2rem; }
/* Zarovnání buňky musí přebít `table.datagrid th, table.datagrid td { text-align: left }`
   výše — samotná třída má nižší specificitu než ta dvojice, takže peněžní sloupce zůstávaly
   vlevo pod hlavičkou zarovnanou vpravo (bylo vidět na Hodnotě na zakázkách). */
table.datagrid th.datagrid-col-expand,
table.datagrid td.datagrid-col-expand { text-align: center; }
table.datagrid th.datagrid-col-right,
table.datagrid td.datagrid-col-right { text-align: right; }
.datagrid-col-right .datagrid-th { justify-content: flex-end; }
.datagrid-col-right .datagrid-sort { flex: 0 1 auto; }
/* ---- Lišta filtrů inboxu poptávek (plán 0044, P1-29) ----
   Inbox není excelový grid (filtry nejsou v hlavičkách), takže roletky stojí nad tabulkou:
   dvě řádky, které se na úzkém okně zlomí. Vzhled polí je sdílený (.field), tady se jen
   zúží a doplní odsazení. */
.inbox-filters { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; }
.inbox-filters-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.inbox-filters-search { flex: 1 1 18rem; min-width: 0; margin: 0; }
.inbox-filters-select { width: auto; margin: 0; flex: 0 0 auto; }
.inbox-filters-date { width: auto; margin: 0; flex: 0 0 auto; }
.inbox-filters-label { color: var(--muted); font-size: 0.85rem; }
.inbox-filters-count { margin-left: auto; color: var(--muted); font-size: 0.85rem; white-space: nowrap; }
.inbox-filters-reset {
    padding: 0.3rem 0.6rem;
    background: var(--surface);
    color: var(--muted);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 0.82rem;
    cursor: pointer;
}
.inbox-filters-reset:hover { border-color: var(--primary); color: var(--primary); }

/* ---- Položky v rozbaleném řádku zakázky (plán 0042, Z6) ----
   Pokračování tabulky, ne vložená karta: stejná velikost písma i vlasové linky jako grid,
   čísla vpravo, inputy bez rámečku, dokud na ně obchodník nejede myší. Strukturu rozpisu
   (kalkulátor, varianty, přidávání řádků) tady vědomě nenajdeš — ta je na detailu. */
/* Táž velikost písma jako řádky zakázek (table.datagrid) — rozbalení má být pokračování
   tabulky, ne menší text uvnitř ní. */
.opportunity-lines { font-size: 0.85rem; }
.opportunity-lines-table { width: 100%; border-collapse: collapse; }
.opportunity-lines-table th {
    padding: 0.1rem 0.4rem;
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--muted);
    text-align: left;
}
.opportunity-lines-table td {
    padding: 0.05rem 0.4rem;
    border-top: 1px solid var(--border);
    vertical-align: middle;
}
.opportunity-lines-table tbody tr:hover > td { background: var(--surface); }
.opportunity-lines-num { text-align: right; white-space: nowrap; }
.opportunity-lines-num th { text-align: right; }
.opportunity-lines-total { font-weight: 600; }
.opportunity-lines-unit { color: var(--muted); margin-left: 0.2rem; }
.opportunity-lines-sum td { color: var(--muted); }

/* Buňka se edituje na místě: input nese hodnotu, ale nekreslí se, dokud na něj nejde myš —
   proto seznam čte jako text a přesto se do něj dá psát bez otvírání čehokoli. */
.opportunity-lines-input {
    width: 100%;
    margin: 0;
    padding: 0.05rem 0.25rem;
    font: inherit;
    color: inherit;
    background: none;
    border: 1px solid transparent;
    border-radius: 4px;
}
.opportunity-lines-input:hover { border-color: var(--border); }
.opportunity-lines-input:focus {
    border-color: var(--primary);
    background: var(--bg);
    outline: none;
}
.opportunity-lines-input-num { width: 6rem; text-align: right; }
.opportunity-lines-note,
.opportunity-lines-msg { margin: 0.15rem 0.4rem; color: var(--muted); font-size: 0.74rem; }
.opportunity-lines-msg.is-error { color: var(--danger); }
.opportunity-lines-msg[hidden] { display: none; }

/* ---- Tom Select (ux-autocomplete) theming ----
   The vendor tom-select.default.css is a light theme; on this dark UI it clashes.
   These overrides drive Tom Select off the same CSS variables as .field so the
   widget matches the native inputs and follows light/dark automatically.
   The select keeps its `field` class, which Tom Select copies onto .ts-wrapper —
   we neutralise that outer box and style the inner .ts-control instead. */
.ts-wrapper.field {
    padding: 0;
    border: 0;
    background: none;
    border-radius: 0;
    width: 100%;
}
/* Doubled .ts-wrapper raises specificity above vendor's .ts-wrapper.single
   .ts-control; background-image:none kills the vendor white gradient. */
.ts-wrapper.ts-wrapper.field .ts-control {
    background: var(--bg);
    background-image: none;
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.55rem 2.2rem 0.55rem 0.7rem;
    color: var(--text);
    box-shadow: none;
    min-height: 0;
    font-size: inherit;
    line-height: 1.4;
}
.ts-wrapper.ts-wrapper.field .ts-control input,
.ts-wrapper.ts-wrapper.field .ts-control .item { color: var(--text); }
.ts-wrapper.ts-wrapper.field .ts-control input::placeholder { color: var(--muted); }
/* Open / focused: primary ring like a focused field, keep all corners rounded.
   `.input-active` is added when a single-select opens; the vendor default theme
   forces a white .ts-control there, so we re-assert the dark background (and win
   on specificity via the doubled .ts-wrapper + the state class). */
.ts-wrapper.ts-wrapper.field.focus .ts-control,
.ts-wrapper.ts-wrapper.field.input-active .ts-control,
.ts-wrapper.ts-wrapper.field.dropdown-active .ts-control {
    background: var(--bg);
    background-image: none;
    border-color: var(--primary);
    border-radius: 8px;
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 25%, transparent);
}
/* Chybný výběr se pozná stejně jako chybné pole. Musí stát AŽ ZA pravidly výše —
   se stejnou specificitou rozhoduje pořadí a `.ts-wrapper.ts-wrapper.field` by
   jinak vrátilo obyčejný rámeček. Třídu `is-invalid` kopíruje Tom Select na obal
   z původního <select>u, který ji dostal od form themu. */
.ts-wrapper.ts-wrapper.is-invalid .ts-control { border-color: var(--danger); }
/* Caret + clear button. */
.ts-wrapper .ts-control:after { border-color: var(--muted) transparent transparent; }
.ts-wrapper .clear-button { color: var(--muted); }
.ts-wrapper .clear-button:hover { color: var(--text); }
/* Dropdown panel. Doubled class (.ts-dropdown.ts-dropdown) raises specificity
   above vendor tom-select.default.css, which loads after app.css. The panel is
   appended to <body>, not inside .ts-wrapper, so descendant selectors can't reach it. */
.ts-dropdown.ts-dropdown {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-top: 0.3rem;
    color: var(--text);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.ts-dropdown.ts-dropdown .option { color: var(--text); padding: 0.45rem 0.7rem; background: none; }
.ts-dropdown.ts-dropdown .option.active,
.ts-dropdown.ts-dropdown .option:hover {
    background: color-mix(in srgb, var(--primary) 22%, transparent);
    color: var(--text);
}
.ts-dropdown.ts-dropdown .option[aria-selected="true"] { color: var(--primary); }
.ts-dropdown.ts-dropdown .no-results,
.ts-dropdown.ts-dropdown .optgroup-header { color: var(--muted); background: none; }

/* Flash toasts — top-right, auto-dismissing notifications. */
.toast-container {
    position: fixed;
    top: 1rem;
    right: 1rem;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-width: min(360px, calc(100vw - 2rem));
}

.toast {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-left: 4px solid var(--primary);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
    animation: toast-in 0.2s ease-out;
    transition: opacity 0.2s ease, transform 0.2s ease;
}

.toast.is-hiding {
    opacity: 0;
    transform: translateX(0.5rem);
}

.toast--success { border-left-color: var(--primary); }
.toast--error { border-left-color: var(--danger); }
.toast--warning { border-left-color: #d97706; }
.toast--info { border-left-color: #3b82f6; }

.toast__message { flex: 1; line-height: 1.4; }

.toast__close {
    flex-shrink: 0;
    padding: 0;
    background: none;
    border: 0;
    color: var(--muted);
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
}
.toast__close:hover { color: var(--text); }

@keyframes toast-in {
    from { opacity: 0; transform: translateX(1rem); }
    to { opacity: 1; transform: translateX(0); }
}

/* Coloured category label. Background is set inline (per category); the text
   colour is chosen for contrast via the modifier class. */
.category-badge {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-size: 0.78rem;
    line-height: 1.4;
    white-space: nowrap;
    vertical-align: middle;
}
.category-badge--light { color: #ffffff; }
.category-badge--dark { color: #111111; }
.category-badge.is-archived { opacity: 0.55; }

.category-badges {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    vertical-align: middle;
}

/* Štítky na jeden řádek v buňce DataGridu: kolik se jich vejde, řeší až
   badge-overflow controller podle skutečné šířky sloupce, zbytek sečte do „+N".
   `max-width` je tu proto, že tabulka se poprvé rozměřuje podle obsahu — bez něj by
   firma s deseti štítky nadiktovala sloupec na půl obrazovky. */
.category-badges--single-line {
    flex-wrap: nowrap;
    max-width: 22rem;
}
.category-badges-more {
    flex: none;
    font-size: 0.78rem;
    line-height: 1.4;
    color: var(--muted);
    white-space: nowrap;
}
/* Autorské pravidlo je potřeba: `display:inline-block` na štítku by přebilo
   `[hidden] { display: none }` z prohlížeče a schovaný štítek by zůstal vidět. */
.category-badge[hidden],
.category-badges-more[hidden] {
    display: none;
}

/* Soft pill badge for lifecycle states (inquiry status, opportunity stage).
   The hue arrives inline via the --badge-color custom property, so a single
   class serves every state; text is the colour, fill/border are tinted mixes. */
.status-badge {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
    color: var(--badge-color, var(--muted));
    background: color-mix(in srgb, var(--badge-color, var(--muted)) 14%, transparent);
    border: 1px solid color-mix(in srgb, var(--badge-color, var(--muted)) 35%, transparent);
}

/* ---- AI chat: typing indicator (agent přemýšlí…) ---- */
.typing-dots {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-right: .4rem;
    vertical-align: middle;
}
.typing-dots span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--muted);
    animation: typing-bounce 1.2s infinite ease-in-out;
}
.typing-dots span:nth-child(2) { animation-delay: .15s; }
.typing-dots span:nth-child(3) { animation-delay: .3s; }
@keyframes typing-bounce {
    0%, 60%, 100% { transform: translateY(0); opacity: .4; }
    30% { transform: translateY(-4px); opacity: 1; }
}

/* Blok čerstvě přepsaný agentem — jemný nájezd při přepisování obsahu. */
.blk-fresh {
    animation: blk-fresh-in .5s ease;
}
@keyframes blk-fresh-in {
    from { opacity: .25; }
    to { opacity: 1; }
}

/* Chat nad úkolem (plán 0030) — panel se při otevření plynule vysune. Tlačítko
   „💬 Chat" je přepínač; opětovný stisk panel zase zasune. Výšku nejde animovat
   z 0 na auto, proto grid-rows trik: řádek gridu jede 0fr → 1fr, tj. animuje se
   SKUTEČNÁ výška obsahu (nic se nedeformuje, obsah pod se odsune plynule). Vnitřek
   má overflow:hidden + min-height:0, aby ho řádek mohl při 0fr sbalit. */
.task-chat-panel {
    display: grid;
    grid-template-rows: 1fr;
    margin-top: .6rem;
    animation: task-chat-expand .24s ease-out;
}
.task-chat-panel__inner {
    overflow: hidden;
    min-height: 0;
    border-top: 1px solid var(--border);
    padding-top: .6rem;
}
@keyframes task-chat-expand {
    from { grid-template-rows: 0fr; opacity: .3; }
    to { grid-template-rows: 1fr; opacity: 1; }
}
/* Zavírání: Stimulus (chat-toggle) přidá tuto třídu, počká na animationend a teprve
   pak spustí živou akci, která panel odstraní — takže se plynule zasune místo skoku. */
.task-chat-panel--closing {
    animation: task-chat-collapse .2s ease-in forwards;
}
@keyframes task-chat-collapse {
    from { grid-template-rows: 1fr; opacity: 1; }
    to { grid-template-rows: 0fr; opacity: .2; }
}
@media (prefers-reduced-motion: reduce) {
    .task-chat-panel, .task-chat-panel--closing { animation: none; }
}

/* Kalkulátor — cenové hladiny jako karty (plán 0029). Ve výběrovém režimu
   (modal) je karta klikatelný <label> a zvýraznění řídí ryze CSS přes
   :has(input:checked) — okamžité, bez čekání na server. Nativní radio je skryté
   (výběr ukazuje karta), ale zůstává kvůli data-model a přístupnosti. */
.calc-tiers {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: .75rem;
}
.calc-tier {
    position: relative;
    display: block;
    border: 2px solid var(--border, #ddd);
    border-radius: 10px;
    padding: .75rem;
}
.calc-tier--select { cursor: pointer; }
.calc-tier--select input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.calc-tier__label {
    color: var(--muted);
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .03em;
}
.calc-tier__price { font-size: 1.25rem; font-weight: 700; margin: .15rem 0; }
.calc-tier__total { color: var(--muted); font-size: .8rem; }
/* Zvýraznění: vybraná karta (modal) nebo doporučená kotva (stránka). */
.calc-tier--anchor,
.calc-tier--select:has(input:checked) {
    border-color: var(--primary);
    background: color-mix(in srgb, var(--primary) 8%, transparent);
}
.calc-tier--anchor .calc-tier__price,
.calc-tier--select:has(input:checked) .calc-tier__price { color: var(--primary); }
.calc-tier--select:has(input:focus-visible) {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   Rozpis položek na zakázce — JEDNA tabulka (ADR 0016 amendment bod 14).
   Sekce (Sdílené položky, Varianty) jsou `<tbody>` s oddělovacím řádkem, takže
   plochý a variantní rozpis mají stejné sloupce i stejné písmo. Rámečky sekcí
   dělá vlasová linka nad hlavičkou, ne karta — jinak by to zase byla tři různá
   zobrazení pod sebou.
   --------------------------------------------------------------------------- */
.breakdown-section > td {
    padding: 0.5rem 0.4rem 0.35rem;
    border-top: 2px solid var(--border);
    background: var(--bg);
}
.breakdown-variant--chosen > .breakdown-section > td { border-top-color: var(--primary); }
.breakdown-section-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.breakdown-section-hint {
    color: var(--muted);
    font-size: 0.78rem;
    margin-left: 0.4rem;
}
.breakdown-section-tools {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
}
.breakdown-section-tools .btn {
    padding: 0.15rem 0.45rem;
    font-size: 0.8rem;
}
.breakdown-section-sum { font-size: 0.82rem; color: var(--muted); white-space: nowrap; }
.breakdown-badge {
    font-size: 0.72rem;
    padding: 0.1rem 0.4rem;
    border: 1px solid var(--primary);
    border-radius: 999px;
}
.breakdown-badge--chosen { background: var(--primary); color: #111; }
.breakdown-empty {
    padding: 0.5rem 0.4rem;
    color: var(--muted);
    font-size: 0.82rem;
    font-style: italic;
}
.breakdown-empty--warn { color: var(--danger); font-style: normal; }

/* Pruh hromadných akcí: viditelnost řídí CSS podle skutečně zaškrtnutých řádků
   (`:has`), ne JavaScript — po re-renderu Live komponenty se tak stav pruhu
   nemůže rozejít s tím, co je v DOM opravdu zaškrtnuté. */
.breakdown-bulk {
    display: none;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-bottom: 0.6rem;
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--primary);
    border-radius: 8px;
    background: color-mix(in srgb, var(--primary) 8%, transparent);
    font-size: 0.85rem;
}
.breakdown:has([data-line-select-target="box"]:checked) .breakdown-bulk { display: flex; }

/* ── Kompaktní řádek rozpisu (P1-19): jedna položka = jeden řádek ─────────────
   Výška řádku je informace. Dokud každá položka nesla tři meta-linky pod názvem
   a osmdesátipixelovou textareu, zabralo osm položek celou obrazovku a rozpis se
   nedal přečíst jako tabulka. Proto:
   - pole se nekreslí, dokud na ně obchodník nenajede (týž vzor jako
     `.opportunity-lines-input` v rozbaleném řádku seznamu — buňka čte jako text
     a přesto se do ní dá psát bez otvírání čehokoli),
   - čísla mají pevné sloupce a `tabular-nums`, aby se dala srovnávat svisle,
   - co bylo linkou POD hodnotou (návrh z kalkulátoru, „vlastní sazba",
     „přepsáno", náhled pro Vario), je podtržení nebo pruh plus tooltip.
   Skrývání sloupců dělá `table-columns` z DataGridu: `data-grid-key` na tabulce,
   `data-col` na buňkách, a pravidlo `display:none` si controller píše do
   <style> v <head> — proto přežije re-render Live komponenty. */
/* Souhrn rozpisu drží velikost písma tabulky, ke které patří: dokud byl na
   základní velikosti karty (1 rem) a součet na 1,05 rem, přebíjel kompaktní řádky
   (0,82 rem) a čtení šlo od tabulky ke souhrnu, ne naopak. Čísla mají `tabular-nums`
   jako v tabulce, aby se základ, DPH a součet srovnaly pod sebe. */
.breakdown-sum {
    margin: 0.8rem 0 0 auto;
    max-width: 22rem;
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
}
.breakdown-sum-hint {
    color: var(--muted);
    font-size: 0.74rem;
    text-align: right;
    margin-bottom: 0.25rem;
}
.breakdown-sum-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.15rem 0;
}
.breakdown-sum-row > span:last-child,
.breakdown-sum-row > strong:last-child { white-space: nowrap; }
/* Rekapitulace po sazbách je podklad k závaznému součtu, ne rovnocenný řádek. */
.breakdown-sum-row--recap { font-size: 0.78rem; padding: 0.1rem 0; }
.breakdown-sum-row--recap.is-last { padding-bottom: 0.25rem; }
.breakdown-sum-total {
    padding: 0.3rem 0;
    border-top: 2px solid var(--text);
    font-size: 0.95rem;
}
.breakdown-sum-default { font-size: 0.74rem; color: var(--muted); padding: 0.3rem 0 0; }
.breakdown-sum-select { width: auto; margin: 0; padding: 0.1rem 0.3rem; font-size: inherit; }

/* Picker sloupců sedí nad tabulkou rozpisu, ne v hlavičce karty: patří k tabulce,
   kterou ovládá, a `.datagrid-columns` už nese `position:relative` pro roletku. */
.breakdown-columns { margin-bottom: 0.4rem; }
.breakdown-table {
    width: 100%;
    border-collapse: collapse;
    /* Pevné rozvržení, ne auto: ellipsis v Popisu potřebuje znát šířku sloupce,
       a čísla nesmí měnit šířku podle toho, kolik mají řádů. */
    table-layout: fixed;
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
}
.breakdown-table th,
.breakdown-table td {
    padding: 0.1rem 0.3rem;
    vertical-align: middle;
    overflow: hidden;
    white-space: nowrap;
    border-right: 1px solid color-mix(in srgb, var(--border) 45%, transparent);
}
.breakdown-table th:last-child,
.breakdown-table td:last-child { border-right: 0; }
.breakdown-head th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--surface);
    text-align: left;
    font-weight: 600;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--muted);
    box-shadow: inset 0 -1px 0 var(--border);
}
.breakdown-row > td { border-top: 1px solid var(--border); }
.breakdown-row:hover > td { background: var(--surface); }
/* Pruh vlevo = cena na řádku je obchodníkova, ne z ceníku (ADR 0017). Dřív to
   byl celý druhý `<tr>`, který se navíc musel přetahovat spolu s řádkem. */
.breakdown-row.is-overridden > td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
/* Přetahovaný řádek: controller přeskládává DOM už při `dragover`, takže cílem
   není nakreslit mezeru, ale říct, který řádek obchodník drží. */
.breakdown-row.is-dragging > td {
    background: color-mix(in srgb, var(--primary) 12%, transparent);
    border-top-color: var(--primary);
}

/* Šířky sloupců. Čísla dostanou pevné místo, volný prostor spadne do Popisu —
   ten je jediný sloupec bez šířky. */
.breakdown-col-pick { width: 1.5rem; }
.breakdown-col-grip { width: 1.7rem; }
.breakdown-col-name { width: 14%; }
.breakdown-col-vario { width: 7rem; }
.breakdown-col-qty { width: 4.6rem; }
.breakdown-col-unit { width: 3.2rem; }
.breakdown-col-price { width: 6rem; }
.breakdown-col-total { width: 7rem; }
.breakdown-col-rate { width: 4.4rem; }
.breakdown-col-vat { width: 5.6rem; }
.breakdown-col-gross { width: 7rem; }
/* Čtyři ikony (upravit, přepočítat, vrátit na kalkulaci, smazat) — u přepsaného řádku
   jsou tam všechny a mazání se nesmí schovat za hranu sloupce. */
.breakdown-col-actions { width: 6rem; }

.breakdown-num, .breakdown-num .field { text-align: right; }
.breakdown-muted { color: var(--muted); }
.breakdown-danger { color: var(--danger); }
.breakdown-strong { font-weight: 700; }
.breakdown-cell-text { display: block; overflow: hidden; text-overflow: ellipsis; }

.breakdown-table .field {
    width: 100%;
    height: 1.55rem;
    min-height: 1.55rem;
    margin: 0;
    padding: 0.05rem 0.25rem;
    font: inherit;
    color: inherit;
    background: none;
    border: 1px solid transparent;
    border-radius: 4px;
}
.breakdown-table .field:hover { border-color: var(--border); }
.breakdown-table .field:focus {
    border-color: var(--primary);
    background: var(--bg);
    outline: none;
}
.breakdown-table select.field { padding: 0.05rem 0 0.05rem 0.25rem; }
.breakdown-check { margin: 0; width: auto; }

/* Podtržení místo linky pod hodnotou: `box-shadow`, ne `border-bottom` — hover
   přebarvuje rámeček a červenou by tím smazal. Červená = návrh z kalkulátoru
   (hodnota je přepsaná), modrá = vlastní sazba řádku, což přepis NENÍ
   (ADR 0017 amendment bod 13) — engine sazbu nepočítá. Čísla jsou v `title`. */
.breakdown-table [data-proposed] { box-shadow: inset 0 -2px 0 var(--danger); }
.breakdown-table [data-own] { box-shadow: inset 0 -2px 0 var(--link); }

.breakdown-name { display: flex; align-items: center; gap: 0.25rem; min-width: 0; }
.breakdown-name .field,
.breakdown-name .breakdown-cell-text { flex: 1 1 auto; min-width: 0; }
.breakdown-name .field { font-weight: 600; }
.breakdown-tag {
    flex: 0 0 auto;
    font-size: 0.64rem;
    color: var(--muted);
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 0 0.2rem;
    cursor: help;
}
.breakdown-warn, .breakdown-mark { flex: 0 0 auto; color: var(--danger); cursor: help; }
.breakdown-mark { font-size: 0.78rem; }

/* Popis: jednořádkový, na focus naroste. Textarea neumí `text-overflow`, takže
   odtékající text fáduje maskou — bez ní se text řeže v půlce slova a nedá se
   poznat, že pokračuje. Celý text je v `title` (hover) a po kliknutí v poli. */
.breakdown-desc {
    height: 1.55rem;
    min-height: 1.55rem;
    line-height: 1.35;
    overflow: hidden;
    white-space: pre;
    resize: none;
    mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent);
}
.breakdown-desc:focus {
    position: relative;
    z-index: 3;
    height: 5rem;
    min-height: 5rem;
    overflow: auto;
    white-space: pre-wrap;
    resize: vertical;
    mask-image: none;
}

.breakdown-vario { display: flex; align-items: center; gap: 0.25rem; min-width: 0; }
.breakdown-vario .field { flex: 1 1 auto; min-width: 0; font-size: 0.76rem; }
/* Chybějící kód varuje jen tam, kde chybí neoprávněně (ADR 0015 amendment).
   Za pravidlem s `:hover` výše, aby ho přebilo i při najetí myší. */
.breakdown-vario .field.is-missing { border-color: var(--danger); }

/* Úchop je na kompaktním řádku hlavní plocha, kterou jde chytit — inputy si
   gesto berou pro označování textu. Proto celá buňka, ne dva znaky. */
.breakdown-grip {
    color: var(--muted);
    cursor: grab;
    user-select: none;
    text-align: center;
    letter-spacing: -0.08em;
}
.breakdown-actions { text-align: right; white-space: nowrap; }
.breakdown-icon {
    background: none;
    border: 0;
    padding: 0 0.1rem;
    color: var(--link);
    cursor: pointer;
    font-size: 0.9rem;
}
.breakdown-icon.is-revert { color: var(--danger); font-size: 1rem; }

/* ── Reporting: grafy (P1-07) ─────────────────────────────────────────────────
   Grafy jsou serverem vykreslené HTML (AssetMapper, žádný build → žádná grafová
   knihovna): pruh je <span> se šířkou/výškou v procentech. Barvy nesou práci, ne
   dekoraci — akcent = letos / jediná série, šedá = loňský kontext, ordinální rampa
   = kroky tunelu (pořadí je součástí významu). Tmavý režim má vlastní kroky, ne
   převrácené světlé. */
:root {
    --chart-accent: var(--primary);
    --chart-context: #6b7686;
    /* Druhý rovnocenný slot kategorické palety (spotřeba tokenů: vstup × výstup).
       Šedá `--chart-context` je vyhrazená pro KONTEXT (loňský rok) — jako peer série
       neprojde CVD kontrolou proti akcentu, proto vlastní odstín. Validováno skillem
       dataviz proti oběma podkladům. */
    --chart-series-2: #6366f1;
    --chart-grid: var(--border);
    --funnel-1: #1d7954;
    --funnel-2: #1f9764;
    --funnel-3: #21b876;
    --funnel-4: #23d887;
}

:root[data-theme="light"] {
    --chart-context: #7f8a98;
    --chart-series-2: #4f46e5;
    --funnel-1: #70c6a2;
    --funnel-2: #47b688;
    --funnel-3: #1aa56b;
    --funnel-4: #138f5c;
}

/* Jeden filtrační řádek nad všemi grafy — ne per graf, aby nemohly ukazovat
   různé výseky týchž dat. */
.report-filters {
    display: flex;
    gap: 0.6rem;
    align-items: center;
    flex-wrap: wrap;
}
/* Odsazení řeší sourozenecké pravidlo uvnitř boardu, ne globální `.card + .card`
   (to by přesouvalo karty i na ostatních stránkách). */
.report-board > * + * { margin-top: 1rem; }
.report-filters__label { color: var(--muted); font-size: 0.85rem; }
.report-filters__hint { color: var(--muted); font-size: 0.78rem; flex: 1 1 14rem; min-width: 12rem; }

.report-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr));
    gap: 1rem;
}
.report-grid > .card { min-width: 0; }

.chart-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 0.9rem;
}
.chart-title { margin: 0; font-size: 1rem; }
.chart-note { margin: 0.2rem 0 0; color: var(--muted); font-size: 0.8rem; line-height: 1.45; }
/* Proporcionální číslice: tabular-nums dělá z velkého čísla rozsypaný čaj. */
.chart-figure { font-size: 1.75rem; font-weight: 600; line-height: 1.1; }
.chart-delta { font-weight: 600; }
.chart-delta--up { color: var(--primary); }
.chart-delta--down { color: var(--danger); }

.chart-legend {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 0.75rem;
    font-size: 0.78rem;
    color: var(--muted);
}
.chart-legend__item { display: inline-flex; align-items: center; gap: 0.35rem; }
.chart-key { width: 0.7rem; height: 0.7rem; border-radius: 2px; }
.chart-key--accent { background: var(--chart-accent); }
.chart-key--context { background: var(--chart-context); }
.chart-key--series2 { background: var(--chart-series-2); }

/* Široký obsah roluje sám v sobě; stránka vodorovně nikdy. */
.table-scroll { overflow-x: auto; }
.chart-table { margin-top: 0.9rem; font-size: 0.85rem; }
.chart-table > summary { cursor: pointer; color: var(--muted); font-size: 0.8rem; }
.chart-table table { margin-top: 0.5rem; font-variant-numeric: tabular-nums; }
.chart-table th, .chart-table td { padding: 0.3rem 0.4rem; }

/* Plocha grafu obratu: osa vlevo, mřížka pod sloupci, popisky měsíců pod plochou
   (kontejner roste s obsahem — pevná výška by popisky odřízla). */
.plot { display: grid; grid-template-columns: max-content 1fr; gap: 0.6rem; }
.plot__ticks {
    position: relative;
    height: 11rem;
    align-self: start;
    font-size: 0.7rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.plot__ticks span { position: absolute; right: 0; transform: translateY(-50%); }
.plot__ticks span:nth-child(1) { top: 0; }
.plot__ticks span:nth-child(2) { top: 50%; }
.plot__ticks span:nth-child(3) { top: 100%; }
.plot__area { position: relative; min-width: 0; }
.plot__grid {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 11rem;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    pointer-events: none;
}
/* Vlasová plná linka, o odstín od plochy — mřížka není data. */
.plot__grid span { border-top: 1px solid var(--chart-grid); }

/* Mřížka patří ZA značky, ne přes ně. */
.cols { position: relative; z-index: 1; display: flex; align-items: flex-end; gap: 0.25rem; }
.cols__group { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; }
/* Celý měsíční pruh je cíl pro hover (title), ne 12px sloupeček. */
.cols__pair {
    height: 11rem;
    width: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: 2px; /* mezera v barvě plochy odděluje sousední sloupce, ne obrys */
}
.cols__label { font-size: 0.68rem; color: var(--muted); padding-top: 0.3rem; }
.cols__group:hover .cols__label { color: var(--text); }

/* Pruh: 4px zakulacený konec dat, hranatý u základní linky. */
.bar {
    display: block;
    flex: 1 1 0;
    max-width: 14px;
    min-height: 0;
    border-radius: 4px 4px 0 0;
    align-self: flex-end;
}
.bar--accent { background: var(--chart-accent); }
.bar--context { background: var(--chart-context); }
.bar--h { border-radius: 0 4px 4px 0; height: 100%; max-width: none; }

/* Konverze obchodníků: jméno · pruh · číslo. Hodnota je vpravo v koloně,
   proto tabular-nums. */
.bars { display: flex; flex-direction: column; gap: 0.55rem; }
.bars__row {
    display: grid;
    grid-template-columns: minmax(7rem, 11rem) 1fr 3.4rem;
    gap: 0.6rem;
    align-items: center;
    min-height: 1.5rem; /* cíl pro hover je řádek, ne pruh */
}
.bars__label { font-size: 0.85rem; min-width: 0; }
.bars__sample { display: block; color: var(--muted); font-size: 0.7rem; }
.bars__track { position: relative; height: 0.8rem; background: color-mix(in srgb, var(--muted) 14%, transparent); border-radius: 0 4px 4px 0; }
.bars__track > .bar--h { position: absolute; left: 0; top: 0; }
/* Průměr týmu jako svislá linka — čárkovaná by se pletla s mřížkou. */
.bars__mark { position: absolute; top: -0.2rem; bottom: -0.2rem; width: 1px; background: var(--text); opacity: 0.55; }
.bars__value { text-align: right; font-size: 0.85rem; font-variant-numeric: tabular-nums; }

/* Tunel: krok = pruh přes celou kohortu, mezi kroky řádek s úbytkem. */
.funnel { display: flex; flex-direction: column; gap: 0.35rem; }
.funnel__row { display: grid; grid-template-columns: minmax(7rem, 9rem) 1fr; gap: 0.6rem; align-items: center; min-height: 1.6rem; }
.funnel__label { font-size: 0.85rem; }
.funnel__hint { display: block; color: var(--muted); font-size: 0.7rem; }
.funnel__track { position: relative; display: flex; align-items: center; gap: 0.5rem; min-height: 1.4rem; }
.funnel__bar { height: 1.4rem; border-radius: 0 4px 4px 0; min-width: 2px; flex: 0 0 auto; }
.funnel__bar--1 { background: var(--funnel-1); }
.funnel__bar--2 { background: var(--funnel-2); }
.funnel__bar--3 { background: var(--funnel-3); }
.funnel__bar--4 { background: var(--funnel-4); }
/* Číslo za pruhem, ne v něm: do krátkého pruhu se nevejde a odřezávat se nesmí. */
.funnel__count { font-size: 0.85rem; font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; }
.funnel__share { color: var(--muted); font-weight: 400; font-size: 0.78rem; }
.funnel__drop { padding-left: calc(7rem + 0.6rem); color: var(--muted); font-size: 0.75rem; }

@media (max-width: 640px) {
    .funnel__drop { padding-left: 0; }
    .bars__row, .funnel__row { grid-template-columns: 1fr; }
    .bars__value { text-align: left; }
}

/* ── Spotřeba tokenů agenta (/admin/ai) ───────────────────────────────────────
   Spojnice je inline SVG vykreslené serverem (žádná grafová knihovna): linka 2px,
   mřížka vlasová a plná, koncový bod s prstencem v barvě plochy, aby byl čitelný
   i v místě křížení. Osa X je HTML pod plochou — v SVG s nerovnoměrným škálováním
   by se text roztáhl. */
.linechart { display: block; width: 100%; height: 11rem; overflow: visible; }
.linechart__grid { stroke: var(--chart-grid); stroke-width: 1; vector-effect: non-scaling-stroke; }
.linechart__line {
    fill: none;
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke; /* jinak preserveAspectRatio="none" linku rozmázne */
}
.linechart__line--completion { stroke: var(--chart-accent); }
.linechart__line--prompt { stroke: var(--chart-series-2); }
.linechart__dot { stroke: var(--surface); stroke-width: 2; vector-effect: non-scaling-stroke; }
.linechart__dot--completion { fill: var(--chart-accent); }
.linechart__dot--prompt { fill: var(--chart-series-2); }
.linechart__crosshair { stroke: var(--text); stroke-width: 1; opacity: 0.45; vector-effect: non-scaling-stroke; }
/* Zóna dne je cíl hoveru/focusu — průhledná, ale klikatelná (fill: transparent
   ano, `none` by ji pro pointer zneviditelnilo). */
.linechart__zone { fill: transparent; outline: none; }
.linechart__zone:focus-visible { fill: color-mix(in srgb, var(--text) 8%, transparent); }

.linechart__labels { position: relative; height: 1rem; margin-top: 0.15rem; }
.linechart__labels span {
    position: absolute;
    transform: translateX(-50%);
    font-size: 0.68rem;
    color: var(--muted);
    white-space: nowrap;
}

.linechart__tooltip {
    position: absolute;
    top: 0.25rem;
    transform: translateX(0.5rem);
    max-width: 16rem;
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    box-shadow: 0 6px 20px rgb(0 0 0 / 25%);
    font-size: 0.78rem;
    line-height: 1.45;
    white-space: pre-line;
    pointer-events: none;
    z-index: 2;
}
/* U pravého okraje se tooltip překlopí, aby nevyčuhoval z karty. */
.linechart__tooltip.is-flipped { transform: translateX(-100%) translateX(-0.5rem); }

/* Dlaždice souhrnu: velké číslo je proporcionální (tabular-nums by ho rozsypalo),
   drobný popisek pod ním nese jednotku a podíl. */
.token-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: 0.75rem 1.25rem;
}
.token-tile { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.token-tile__label { color: var(--muted); font-size: 0.78rem; }
.token-tile__value { font-size: 1.15rem; font-weight: 600; }
.token-tile__note { color: var(--muted); font-size: 0.72rem; }

/* Nápověda „❓ Jak to funguje" — rozbalovací <details> vysvětlující obrazovku
   nebo sekci (cenový dokument, úvodky katalogu a profilu). Původně žila
   v pricing/_detail_styles.html.twig, používá ji víc stránek. */
.pfe-help { margin: 0 0 0.6rem; }
.pfe-help > summary { cursor: pointer; font-size: 0.78rem; color: var(--accent, #2563eb); user-select: none; }
.pfe-help-body { font-size: 0.8rem; color: var(--muted); border-left: 2px solid var(--border, #e5e7eb); padding: 0.35rem 0 0.35rem 0.7rem; margin-top: 0.4rem; }
.pfe-help-body p { margin: 0.25rem 0; }
.pfe-help-h { font-weight: 600; margin: 0.55rem 0 0.2rem; }
.pfe-help-note { font-style: italic; }
.pfe-help-formula { font-family: ui-monospace, monospace; overflow-wrap: anywhere; }
.pfe-help-dl { display: grid; grid-template-columns: auto 1fr; gap: 0.2rem 0.7rem; margin: 0.3rem 0; }
.pfe-help-dl dt { font-weight: 600; }
.pfe-help-dl dd { margin: 0; }

/* ── Pravidla obchodníků (P2-04, plán 0030) ───────────────────────────────────
   Seznam koučovacích pravidel jednoho obchodníka (/admin/coaching/{id}).
   Řádek je mřížka „výběr | text | ovládání“: text je jediný pružný sloupec, takže
   dlouhé pravidlo teče do šířky karty a přepínač s akcemi zůstává zarovnaný pod
   sebou přes všechny řádky. Stav zapnuto/vypnuto nese přepínač (switch), ne druhé
   zaškrtávátko — vedle sebe dvě čtverečky s různým významem se pletly. */
.sg-msg {
    margin: 0 0 0.8rem;
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 0.87rem;
}
.sg-msg.is-error {
    color: var(--danger);
    border-color: color-mix(in srgb, var(--danger) 45%, var(--border));
    background: color-mix(in srgb, var(--danger) 8%, transparent);
}
.sg-msg.is-notice {
    color: var(--primary);
    border-color: color-mix(in srgb, var(--primary) 45%, var(--border));
    background: color-mix(in srgb, var(--primary) 8%, transparent);
}

.sg-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.55rem 0.85rem;
    padding-bottom: 0.7rem;
    margin-bottom: 0.75rem;
    border-bottom: 1px solid var(--border);
    font-size: 0.85rem;
}
.sg-toolbar-fill { margin-left: auto; }
.sg-count { color: var(--muted); white-space: nowrap; }
.sg-selected { color: var(--primary); font-weight: 600; white-space: nowrap; }

/* Zaškrtávátko s popiskem na jednom řádku — ruší globální blokový <label>. */
.sg-check {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    margin: 0;
    color: var(--text);
    font-size: inherit;
    cursor: pointer;
    user-select: none;
}
.sg-check input { flex: none; margin: 0; }

.sg-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.26rem 0.6rem;
    font: inherit;
    font-size: 0.82rem;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    cursor: pointer;
}
.sg-btn:hover { border-color: var(--primary); color: var(--primary); }
.sg-btn.is-danger:hover { border-color: var(--danger); color: var(--danger); }
.sg-btn:disabled { opacity: 0.45; cursor: default; }

.sg-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.sg-item {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: start;
    gap: 0.7rem;
    padding: 0.55rem 0.7rem;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    transition: border-color 0.12s ease, background 0.12s ease;
}
.sg-item:hover { border-color: color-mix(in srgb, var(--primary) 35%, var(--border)); }
.sg-item.is-selected {
    border-color: var(--primary);
    background: color-mix(in srgb, var(--primary) 7%, var(--bg));
}
/* Vypnuté pravidlo zůstává čitelné (dá se upravit), jen ustoupí do pozadí —
   celořádkové opacity by zneviditelnilo i přepínač, kterým se zapíná zpět. */
.sg-item.is-off .sg-text { color: var(--muted); }
.sg-item-select { padding-top: 0.2rem; }
.sg-body { min-width: 0; }
.sg-text { line-height: 1.4; overflow-wrap: anywhere; }
.sg-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.3rem;
    font-size: 0.74rem;
    color: var(--muted);
}
.sg-meta-sep { opacity: 0.45; }

.sg-badge {
    display: inline-flex;
    align-items: center;
    padding: 0.05rem 0.4rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 0.67rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
}
.sg-badge--learned { color: var(--primary); border-color: color-mix(in srgb, var(--primary) 45%, var(--border)); }
.sg-badge--copied { color: var(--link); border-color: color-mix(in srgb, var(--link) 45%, var(--border)); }

.sg-actions { display: inline-flex; align-items: center; gap: 0.2rem; }
.sg-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    background: none;
    border: 0;
    border-radius: 6px;
    color: var(--muted);
    cursor: pointer;
}
.sg-icon:hover { background: var(--surface); color: var(--text); }
/* Mazání je červené v klidu, ne až pod kurzorem — jako všude jinde (viz .btn-icon.is-danger). */
.sg-icon.is-danger { color: var(--danger); }
.sg-icon.is-danger:hover { color: var(--danger); }

/* Přepínač zapnuto/vypnuto. Je to <button role="switch">, ne checkbox: stav drží
   server (Live akce) a takhle se nepere s globálním stylem formulářových polí. */
.sg-switch {
    display: inline-flex;
    align-items: center;
    flex: none;
    width: 34px;
    height: 20px;
    margin-right: 0.3rem;
    padding: 2px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease;
}
.sg-switch::after {
    content: "";
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--muted);
    transition: transform 0.12s ease, background 0.12s ease;
}
.sg-switch[aria-checked="true"] {
    background: color-mix(in srgb, var(--primary) 28%, transparent);
    border-color: var(--primary);
}
.sg-switch[aria-checked="true"]::after { transform: translateX(14px); background: var(--primary); }
.sg-switch:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.sg-edit { display: flex; align-items: center; gap: 0.4rem; }
.sg-edit .field { flex: 1 1 auto; min-width: 0; margin: 0; }
/* Tlačítka vedle pružného pole se nesmí smrsknout — jinak se popisek zalomí. */
.sg-edit .btn, .sg-edit .sg-btn, .sg-add .btn { flex: none; white-space: nowrap; }

.sg-empty {
    margin: 0;
    padding: 1.15rem 1rem;
    text-align: center;
    color: var(--muted);
    font-size: 0.9rem;
    border: 1px dashed var(--border);
    border-radius: 8px;
}

.sg-add { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.9rem; }
.sg-add .field { flex: 1 1 auto; min-width: 0; margin: 0; }
.sg-hint { margin: 0.55rem 0 0; font-size: 0.8rem; color: var(--muted); }

/* Hromadné zkopírování vybraných pravidel jiným obchodníkům. Panel, ne vnořená
   karta — karta v kartě se opticky tluče s rámečkem obrazovky. */
.sg-copy {
    margin: 0 0 0.75rem;
    padding: 0.55rem 0.7rem;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
}
.sg-copy > summary { cursor: pointer; font-size: 0.85rem; font-weight: 600; user-select: none; }
.sg-copy[open] > summary { margin-bottom: 0.65rem; }
.sg-people {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: 0.35rem;
}
.sg-person {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    padding: 0.3rem 0.5rem;
    font-size: 0.85rem;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    cursor: pointer;
}
.sg-person input { flex: none; margin: 0; }
.sg-person:has(input:checked) { border-color: var(--primary); color: var(--primary); }
.sg-copy-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-top: 0.7rem;
    font-size: 0.8rem;
    color: var(--muted);
}
.sg-copy-actions .btn:disabled { opacity: 0.45; cursor: default; }

/* Úzké okno: ovládání spadne pod text, výběr zůstane vlevo. */
@media (max-width: 640px) {
    .sg-item { grid-template-columns: auto minmax(0, 1fr); }
    .sg-actions { grid-column: 2; justify-content: flex-end; }
}

/* ── Katalog textilu (P1-28, plán 0058) ───────────────────────────────────────
   Obrazovka je „tupá tabulka“ plněná jen importem: nahrávací karta, filtr, seznam.
   Odsazení a vlasové linky tabulky dává globální `th, td` — tady jsou navíc jen
   sloupce, které se chovají jinak, protože v ceníku znamenají něco jiného:
   čísla drží kolonu vpravo a nákupní cena je interní pomůcka, ne cena k práci. */

/* Sbalená karta nahrání bez značky je nerozeznatelná od mrtvého nadpisu — a je to
   jediná cesta, jak se sortiment do CRM dostane. */
.tx-upload > summary {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    cursor: pointer;
    font-weight: 600;
    list-style: none;
    user-select: none;
}
.tx-upload > summary::-webkit-details-marker { display: none; }
.tx-upload > summary::before {
    content: "▸";
    color: var(--muted);
    font-size: 0.85em;
    transition: transform 0.12s ease;
}
.tx-upload[open] > summary::before { transform: rotate(90deg); }
.tx-upload-hint { font-weight: normal; color: var(--muted); font-size: 0.85rem; }

/* Soubor, přepínač a tlačítko na jedné ose a hned u sebe. Pole roztažené přes
   celou kartu odstrčí tlačítko o půl obrazovky dál a rozváže úkon na dva. */
.tx-upload-form {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
    margin: 0.9rem 0 0;
}
.tx-upload-form input[type="file"] { flex: 1 1 20rem; max-width: 30rem; margin: 0; }
/* Řádek formuláře kolem zaškrtávátka nesmí přidávat svislé odsazení — na jedné ose
   s polem a tlačítkem by ho posunulo o třetinu výšky. */
.tx-dry-run { margin: 0; }
.tx-dry-run .form-check { margin: 0; }
.tx-note { margin: 0.8rem 0 0; font-size: 0.85rem; color: var(--muted); max-width: 100ch; }

/* Výsledek importu: druh výsledku nese pruh vlevo, ne text. */
.tx-result { border-left: 3px solid var(--border); }
.tx-result.is-ok { border-left-color: var(--success, #15803d); }
.tx-result.is-warn { border-left-color: var(--warning, #b45309); }
.tx-result-head { margin: 0 0 0.5rem; font-weight: 600; }
.tx-counts { display: flex; gap: 1.25rem; flex-wrap: wrap; font-size: 0.9rem; }
.tx-count-label { color: var(--muted); }
/* Nula znamená „nic z toho“, ne výsledek: ustoupí celá, aby čísla, o kterých
   import opravdu je, šla poznat bez čtení. */
.tx-count.is-zero, .tx-count.is-zero strong, .tx-count.is-zero .tx-count-label {
    color: var(--muted);
    font-weight: 400;
}
.tx-warning { margin: 0.6rem 0 0; font-size: 0.88rem; }
.tx-errors { margin: 0.6rem 0 0; }
.tx-errors > summary { cursor: pointer; font-size: 0.88rem; }
.tx-errors ul { margin: 0.5rem 0 0; padding-left: 1.2rem; font-size: 0.85rem; color: var(--muted); }

/* Seznam sortimentu jede na sdíleném .datagrid (plán 0034), takže tabulka, filtry
   ani stránkování tu vlastní styly nemají. Zůstává prázdný stav a text pod ním. */
.tx-muted { color: var(--muted); }
.tx-blank { text-align: center; padding: 2.5rem 1.5rem; }
.tx-blank p { margin: 0; font-weight: 600; }
.tx-blank p + p { margin-top: 0.35rem; color: var(--muted); font-weight: 400; }

/* ── AI prompty (/admin/prompts) ───────────────────────────────────────────
   Tři textarey nejsou tři sekce k rozbalování — vejdou se vedle sebe. Na velkém
   monitoru tedy tři sloupce, pak klasicky 2 → 1. Karta je flex sloupec a
   textarea v ní roste, takže tlačítka „Uložit" leží ve všech sloupcích na jedné
   lince i při různě dlouhých popiskách. */
.prompt-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
}
@media (max-width: 1200px) {
    .prompt-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
    .prompt-grid { grid-template-columns: 1fr; }
}

.prompt-card { display: flex; flex-direction: column; min-width: 0; }
.prompt-card__title { margin: 0 0 0.4rem; font-size: 1.05rem; font-weight: 600; }
.prompt-card__desc { color: var(--muted); font-size: 0.85rem; margin: 0 0 0.9rem; }
.prompt-card__body { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.prompt-card__body .form-row { display: flex; flex-direction: column; flex: 1; margin-bottom: 0; }
.prompt-card__body textarea { flex: 1; min-height: 9rem; resize: vertical; }
.prompt-card__actions {
    display: flex;
    gap: 0.75rem;
    align-items: center;
    flex-wrap: wrap;
    margin-top: 0.9rem;
}
