/* =========================================================================
   Fullcom NextFIS - redesigned identity module prototype
   Light-theme ERP UI with clear hierarchy, status visibility and
   modern interaction patterns. Stays close to the original palette
   (Fullcom blue) but cleans up density and information architecture.
   ========================================================================= */

:root{
  /* =======================================================================
     TIER 1 — PRIMITIVES (tonal scales). Raw colour values, named by hue+shade.
     Nothing in the UI should reference these directly — only the semantic
     tokens below (TIER 2) map onto them. Adding a theme = remap semantics,
     not invent new hexes. (Scales are the Tailwind-ish ramp the UI already used.)
     ======================================================================= */
  --white:#ffffff;
  /* Complete Tailwind v3 palette — all 22 hues × 11 shades (50–950). Single
     source of raw colour; the UI references these ONLY via the semantic tokens
     below. Many hues are unused today but available for future work. */
  /* slate */
  --slate-50:#f8fafc; --slate-100:#f1f5f9; --slate-200:#e2e8f0; --slate-300:#cbd5e1; --slate-400:#94a3b8; --slate-500:#64748b; --slate-600:#475569; --slate-700:#334155; --slate-800:#1e293b; --slate-900:#0f172a; --slate-950:#020617;
  /* gray */
  --gray-50:#f9fafb; --gray-100:#f3f4f6; --gray-200:#e5e7eb; --gray-300:#d1d5db; --gray-400:#9ca3af; --gray-500:#6b7280; --gray-600:#4b5563; --gray-700:#374151; --gray-800:#1f2937; --gray-900:#111827; --gray-950:#030712;
  /* zinc */
  --zinc-50:#fafafa; --zinc-100:#f4f4f5; --zinc-200:#e4e4e7; --zinc-300:#d4d4d8; --zinc-400:#a1a1aa; --zinc-500:#71717a; --zinc-600:#52525b; --zinc-700:#3f3f46; --zinc-800:#27272a; --zinc-900:#18181b; --zinc-950:#09090b;
  /* neutral */
  --neutral-50:#fafafa; --neutral-100:#f5f5f5; --neutral-200:#e5e5e5; --neutral-300:#d4d4d4; --neutral-400:#a3a3a3; --neutral-500:#737373; --neutral-600:#525252; --neutral-700:#404040; --neutral-800:#262626; --neutral-900:#171717; --neutral-950:#0a0a0a;
  /* stone */
  --stone-50:#fafaf9; --stone-100:#f5f5f4; --stone-200:#e7e5e4; --stone-300:#d6d3d1; --stone-400:#a8a29e; --stone-500:#78716c; --stone-600:#57534e; --stone-700:#44403c; --stone-800:#292524; --stone-900:#1c1917; --stone-950:#0c0a09;
  /* red */
  --red-50:#fef2f2; --red-100:#fee2e2; --red-200:#fecaca; --red-300:#fca5a5; --red-400:#f87171; --red-500:#ef4444; --red-600:#dc2626; --red-700:#b91c1c; --red-800:#991b1b; --red-900:#7f1d1d; --red-950:#450a0a;
  /* orange */
  --orange-50:#fff7ed; --orange-100:#ffedd5; --orange-200:#fed7aa; --orange-300:#fdba74; --orange-400:#fb923c; --orange-500:#f97316; --orange-600:#ea580c; --orange-700:#c2410c; --orange-800:#9a3412; --orange-900:#7c2d12; --orange-950:#431407;
  /* amber */
  --amber-50:#fffbeb; --amber-100:#fef3c7; --amber-200:#fde68a; --amber-300:#fcd34d; --amber-400:#fbbf24; --amber-500:#f59e0b; --amber-600:#d97706; --amber-700:#b45309; --amber-800:#92400e; --amber-900:#78350f; --amber-950:#451a03;
  /* yellow */
  --yellow-50:#fefce8; --yellow-100:#fef9c3; --yellow-200:#fef08a; --yellow-300:#fde047; --yellow-400:#facc15; --yellow-500:#eab308; --yellow-600:#ca8a04; --yellow-700:#a16207; --yellow-800:#854d0e; --yellow-900:#713f12; --yellow-950:#422006;
  /* lime */
  --lime-50:#f7fee7; --lime-100:#ecfccb; --lime-200:#d9f99d; --lime-300:#bef264; --lime-400:#a3e635; --lime-500:#84cc16; --lime-600:#65a30d; --lime-700:#4d7c0f; --lime-800:#3f6212; --lime-900:#365314; --lime-950:#1a2e05;
  /* green */
  --green-50:#f0fdf4; --green-100:#dcfce7; --green-200:#bbf7d0; --green-300:#86efac; --green-400:#4ade80; --green-500:#22c55e; --green-600:#16a34a; --green-700:#15803d; --green-800:#166534; --green-900:#14532d; --green-950:#052e16;
  /* emerald */
  --emerald-50:#ecfdf5; --emerald-100:#d1fae5; --emerald-200:#a7f3d0; --emerald-300:#6ee7b7; --emerald-400:#34d399; --emerald-500:#10b981; --emerald-600:#059669; --emerald-700:#047857; --emerald-800:#065f46; --emerald-900:#064e3b; --emerald-950:#022c22;
  /* teal */
  --teal-50:#f0fdfa; --teal-100:#ccfbf1; --teal-200:#99f6e4; --teal-300:#5eead4; --teal-400:#2dd4bf; --teal-500:#14b8a6; --teal-600:#0d9488; --teal-700:#0f766e; --teal-800:#115e59; --teal-900:#134e4a; --teal-950:#042f2e;
  /* cyan */
  --cyan-50:#ecfeff; --cyan-100:#cffafe; --cyan-200:#a5f3fc; --cyan-300:#67e8f9; --cyan-400:#22d3ee; --cyan-500:#06b6d4; --cyan-600:#0891b2; --cyan-700:#0e7490; --cyan-800:#155e75; --cyan-900:#164e63; --cyan-950:#083344;
  /* sky */
  --sky-50:#f0f9ff; --sky-100:#e0f2fe; --sky-200:#bae6fd; --sky-300:#7dd3fc; --sky-400:#38bdf8; --sky-500:#0ea5e9; --sky-600:#0284c7; --sky-700:#0369a1; --sky-800:#075985; --sky-900:#0c4a6e; --sky-950:#082f49;
  /* blue */
  --blue-50:#eff6ff; --blue-100:#dbeafe; --blue-200:#bfdbfe; --blue-300:#93c5fd; --blue-400:#60a5fa; --blue-500:#3b82f6; --blue-600:#2563eb; --blue-700:#1d4ed8; --blue-800:#1e40af; --blue-900:#1e3a8a; --blue-950:#172554;
  /* indigo */
  --indigo-50:#eef2ff; --indigo-100:#e0e7ff; --indigo-200:#c7d2fe; --indigo-300:#a5b4fc; --indigo-400:#818cf8; --indigo-500:#6366f1; --indigo-600:#4f46e5; --indigo-700:#4338ca; --indigo-800:#3730a3; --indigo-900:#312e81; --indigo-950:#1e1b4b;
  /* violet */
  --violet-50:#f5f3ff; --violet-100:#ede9fe; --violet-200:#ddd6fe; --violet-300:#c4b5fd; --violet-400:#a78bfa; --violet-500:#8b5cf6; --violet-600:#7c3aed; --violet-700:#6d28d9; --violet-800:#5b21b6; --violet-900:#4c1d95; --violet-950:#2e1065;
  /* purple */
  --purple-50:#faf5ff; --purple-100:#f3e8ff; --purple-200:#e9d5ff; --purple-300:#d8b4fe; --purple-400:#c084fc; --purple-500:#a855f7; --purple-600:#9333ea; --purple-700:#7e22ce; --purple-800:#6b21a8; --purple-900:#581c87; --purple-950:#3b0764;
  /* fuchsia */
  --fuchsia-50:#fdf4ff; --fuchsia-100:#fae8ff; --fuchsia-200:#f5d0fe; --fuchsia-300:#f0abfc; --fuchsia-400:#e879f9; --fuchsia-500:#d946ef; --fuchsia-600:#c026d3; --fuchsia-700:#a21caf; --fuchsia-800:#86198f; --fuchsia-900:#701a75; --fuchsia-950:#4a044e;
  /* pink */
  --pink-50:#fdf2f8; --pink-100:#fce7f3; --pink-200:#fbcfe8; --pink-300:#f9a8d4; --pink-400:#f472b6; --pink-500:#ec4899; --pink-600:#db2777; --pink-700:#be185d; --pink-800:#9d174d; --pink-900:#831843; --pink-950:#500724;
  /* rose */
  --rose-50:#fff1f2; --rose-100:#ffe4e6; --rose-200:#fecdd3; --rose-300:#fda4af; --rose-400:#fb7185; --rose-500:#f43f5e; --rose-600:#e11d48; --rose-700:#be123c; --rose-800:#9f1239; --rose-900:#881337; --rose-950:#4c0519;
  /* brand-tinted active-row surface (between blue-50 and blue-100) */
  --blue-tint:#e8f1fb;

  /* Dark-theme neutral ramp — tuned blue-grey surfaces/borders/text for the
     dark theme. These are NOT in the Tailwind palette (Tailwind has no cool
     mid-tone surfaces between slate-900 and gray-900 that read well as ERP
     panels), so they live here as named primitives: single source of the raw
     dark values, referenced ONLY via the semantic tokens in html[data-theme].
     Ordered light→dark like a Tailwind ramp (1 = deepest page bg). */
  --dark-bg:#0b1220;        /* page background (below content) */
  --dark-surface:#111827;   /* content surface (= gray-900) */
  --dark-surface-alt:#0f1626;  /* zebra / subtle blocks */
  --dark-surface-muted:#161f31;/* tinted panels (sidebar, toolbar) */
  --dark-raised:#1c2638;    /* floating surfaces (modal, dropdown, toast) */
  --dark-hover:#1f2a3d;     /* hover state (neutral lift) */
  --dark-active:#21385c;    /* brand-tinted active — bluer + brighter than hover so the two states read apart */
  --dark-border:#243049;    /* primary border */
  --dark-border-strong:#33415c;/* emphasised border / toast border */
  --dark-divider:#1b2333;   /* in-panel divider */
  --dark-text:#e5e9f0;      /* primary text */
  --dark-text-muted:#a9b4c6;/* secondary text (AA on dark) */
  --dark-text-faint:#7e8aa0;/* labels / placeholders */
  /* Dark soft status backgrounds (deep tints behind status pills/text). */
  --dark-brand-soft:#16304d;
  --dark-success-soft:#0f2e1d;
  --dark-warning-soft:#33270a;
  --dark-danger-soft:#3a1a1d;
  --dark-loading-soft:#2a1f47;  /* violet-tinted (Doprava loading stage) */

  /* =======================================================================
     TIER 2 — SEMANTICS. Reference primitives; this is what the UI uses.
     ======================================================================= */
  /* Brand */
  --brand:var(--blue-500);
  --brand-dark:var(--blue-700);
  --brand-soft:var(--blue-50);

  /* Surfaces — 4-tier neutral scale (slate 50 / 100 / 200, plus white).
     Every "subtle gray" in the UI should pick one of these — no ad-hoc
     mid-tones, no per-component variants. */
  --bg:var(--slate-100);            /* body fallback; .shell covers viewport */
  --surface:var(--white);           /* content surface, table */
  --surface-raised:var(--white);    /* floating surfaces: modals, dropdowns, popovers */
  --surface-alt:var(--slate-50);    /* off-white (zebra, subtle blocks) */
  --surface-muted:var(--slate-100); /* tinted panels (sidebar, toolbar) */
  --surface-hover:var(--slate-200); /* hover state on any surface */
  --surface-active:var(--blue-tint);/* brand-tinted active state */

  /* Borders — 2 tiers. Divider equals surface-muted so 1px lines drawn
     across a tinted background stay invisible by default. */
  --border:var(--slate-200);        /* primary border */
  --border-strong:var(--slate-300); /* emphasised border */
  --divider:var(--slate-100);       /* in-panel divider line */

  /* Text */
  --text:var(--slate-800);
  --text-muted:var(--slate-600);    /* AA on white (7.6:1); secondary text */
  --text-faint:var(--slate-500);    /* AA on white (4.76:1); placeholders, labels */
  --text-subtle:var(--slate-400);   /* tichý label skupiny (field-group) — pod AA, jen dekorativní */
  --barcode-bg:var(--white);        /* čárový kód: vždy světlý podklad + tmavé čáry (skenovatelnost) */
  --barcode-ink:var(--slate-900);   /* — nepřepisuje se v dark režimu (kód musí zůstat čitelný čtečkou) */

  /* Sidebar tokens — alias the shared neutral scale so the sidebar and
     other tinted panels (toolbar) stay perfectly in sync. */
  --sidebar-bg:var(--surface-muted);
  --sidebar-border:var(--border);
  --sidebar-text:var(--text);
  --sidebar-text-muted:var(--text-muted);
  --sidebar-text-faint:var(--text-faint);
  --sidebar-hover:var(--surface-hover);
  --sidebar-active-bg:var(--white);
  --sidebar-active-text:var(--brand);   /* same blue as active tabs */

  /* Semantic */
  --success:var(--green-500);
  --success-soft:var(--green-100);
  --success-border:var(--green-200); /* gentle frame for soft-bg surfaces (banner) */
  --success-dark:var(--green-700);  /* AA with white text (5:1); solid success badges/buttons */
  --success-fg:var(--green-700);    /* success text on soft bg (pairs with --warning-fg/--danger-fg) */
  --warning:var(--amber-500);
  --warning-soft:var(--amber-100);
  --warning-border:var(--amber-200);
  --warning-fg:var(--amber-900);    /* dark amber text on warning-soft pills/icons */
  --danger:var(--red-500);
  --danger-soft:var(--red-100);
  --danger-border:var(--red-200);
  --danger-fg:var(--red-700);       /* dark red text on danger-soft */
  /* Info — semantic blue tied to the SKY ramp, NOT --brand (which is the
     swappable accent). Keeps "info" meaning fixed even when the accent changes.
     Base --info je nepoužitá; konzumují se jen odvozené --info-soft/-fg/-border. */
  --info-soft:var(--sky-50);
  --info-border:var(--sky-200);
  --info-fg:var(--sky-800);         /* AA blue text on info-soft */

  /* Chart series — a categorical palette for pie/bar segments. Distinct hues
     from across the ramps, ordered for max separation between neighbours. Tone
     variants (success/warning/danger) stay separate for semantic charts. */
  --chart-1:var(--blue-500);
  --chart-2:var(--violet-500);
  --chart-3:var(--teal-500);
  --chart-4:var(--amber-500);
  --chart-5:var(--rose-500);
  --chart-6:var(--sky-400);
  --chart-track:var(--surface-muted);  /* empty/remainder track for arc + bar */
  --chart-bar-radius:var(--radius-xs); /* 4px — one rounding language across all charts (bar corners; arc/ring use round caps on a slim stroke to match) */
  --chart-stroke:3;                    /* arc/ring stroke width — slim, so round caps stay gentle and read like the bar radius */
  --chart-dot:10px;                    /* legend swatch size (pie + line legends) */

  /* Tagy (uživatelské štítky) — GLOBÁLNÍ kategoriální paleta pro .tag pill.
     Tagy nejsou vázané na modul; tahle sada je k dispozici všude. Každá barva
     = trojice soft pozadí (-100) / text (-700, AA na soft) / tečka (-500).
     Vlastní sada (ne chart série), aby se dala ladit nezávisle na grafech.
     Rozšířená matějka (16 barev) ve stylu YouTracku — víc volné ruky při
     zakládání tagu. Pořadí drží odlišnost sousedů (cyklí přes data-tag-color). */
  /* OKLCH-vyrovnané: fixní L a C, mění se jen hue (spočítaný z Tailwind primitiv) →
     všech 16 barev má stejnou percepční sílu, žádná neřve (#27). bg L=0.955 C=0.04,
     text L=0.45 C=0.08, dot L=0.62 C=0.11; slate je neutrální (nízká C). C zvolené tak,
     aby VŠECHNY hue zůstaly v sRGB gamutu (limituje teal/cyan) — bez ořezu = reálně vyrovnané. */
  --tag-slate-bg:oklch(0.955 0.008 257.4); --tag-slate-fg:oklch(0.45 0.015 257.4); --tag-slate-dot:oklch(0.62 0.02 257.4);
  --tag-red-bg:oklch(0.955 0.04 25.3); --tag-red-fg:oklch(0.45 0.08 25.3); --tag-red-dot:oklch(0.62 0.11 25.3);
  --tag-orange-bg:oklch(0.955 0.04 47.6); --tag-orange-fg:oklch(0.45 0.08 47.6); --tag-orange-dot:oklch(0.62 0.11 47.6);
  --tag-amber-bg:oklch(0.955 0.04 70.1); --tag-amber-fg:oklch(0.45 0.08 70.1); --tag-amber-dot:oklch(0.62 0.11 70.1);
  --tag-lime-bg:oklch(0.955 0.04 130.8); --tag-lime-fg:oklch(0.45 0.08 130.8); --tag-lime-dot:oklch(0.62 0.11 130.8);
  --tag-green-bg:oklch(0.955 0.04 149.6); --tag-green-fg:oklch(0.45 0.08 149.6); --tag-green-dot:oklch(0.62 0.11 149.6);
  --tag-emerald-bg:oklch(0.955 0.04 162.5); --tag-emerald-fg:oklch(0.45 0.08 162.5); --tag-emerald-dot:oklch(0.62 0.11 162.5);
  --tag-teal-bg:oklch(0.955 0.04 182.5); --tag-teal-fg:oklch(0.45 0.08 182.5); --tag-teal-dot:oklch(0.62 0.11 182.5);
  --tag-cyan-bg:oklch(0.955 0.04 215.2); --tag-cyan-fg:oklch(0.45 0.08 215.2); --tag-cyan-dot:oklch(0.62 0.11 215.2);
  --tag-sky-bg:oklch(0.955 0.04 237.3); --tag-sky-fg:oklch(0.45 0.08 237.3); --tag-sky-dot:oklch(0.62 0.11 237.3);
  --tag-blue-bg:oklch(0.955 0.04 259.8); --tag-blue-fg:oklch(0.45 0.08 259.8); --tag-blue-dot:oklch(0.62 0.11 259.8);
  --tag-indigo-bg:oklch(0.955 0.04 277.1); --tag-indigo-fg:oklch(0.45 0.08 277.1); --tag-indigo-dot:oklch(0.62 0.11 277.1);
  --tag-violet-bg:oklch(0.955 0.04 292.7); --tag-violet-fg:oklch(0.45 0.08 292.7); --tag-violet-dot:oklch(0.62 0.11 292.7);
  --tag-purple-bg:oklch(0.955 0.04 303.9); --tag-purple-fg:oklch(0.45 0.08 303.9); --tag-purple-dot:oklch(0.62 0.11 303.9);
  --tag-fuchsia-bg:oklch(0.955 0.04 322.1); --tag-fuchsia-fg:oklch(0.45 0.08 322.1); --tag-fuchsia-dot:oklch(0.62 0.11 322.1);
  --tag-pink-bg:oklch(0.955 0.04 354.3); --tag-pink-fg:oklch(0.45 0.08 354.3); --tag-pink-dot:oklch(0.62 0.11 354.3);
  --tag-rose-bg:oklch(0.955 0.04 16.4); --tag-rose-fg:oklch(0.45 0.08 16.4); --tag-rose-dot:oklch(0.62 0.11 16.4);
  /* Danger BUTTON text — tuned per surface brightness for AA. On the LIGHT
     theme the button sits on a white surface, so it needs the deeper red
     (red-500 on white is only 3.8:1). Hover deepens further. */
  --btn-danger-fg:var(--red-600);       /* 4.8:1 on white */
  --btn-danger-fg-hover:var(--red-700); /* darker lift on light surface */

  /* On-brand text (white on coloured fills) — tokenised so dark can adjust. */
  --on-accent:var(--white);

  /* Doprava workflow stage colours — each: soft bg / text / dot.
     ramp/done/departed reuse the semantic tokens; arrived/loading are sky/violet. */
  --stage-arrived-bg:var(--sky-100);   --stage-arrived-fg:var(--sky-800);   --stage-arrived-dot:var(--sky-600);
  --stage-loading-bg:var(--violet-100); --stage-loading-fg:var(--violet-800); --stage-loading-dot:var(--violet-500);
  --stage-ramp-bg:var(--warning-soft); --stage-ramp-fg:var(--amber-900); --stage-ramp-dot:var(--warning);
  --stage-done-bg:var(--success-soft); --stage-done-fg:var(--success-dark); --stage-done-dot:var(--success);
  --stage-departed-bg:var(--teal-50); --stage-departed-fg:var(--teal-800); --stage-departed-dot:var(--teal-600);

  /* Focus ring tints — coloured per variant, low alpha. */
  --brand-ring:rgba(59,130,246,.16);
  --brand-ring-strong:rgba(59,130,246,.32);
  --danger-ring:rgba(239,68,68,.30);  /* red-500 — focus ring on destructive buttons */
  --warning-ring:rgba(245,158,11,.22);  /* amber-500 — pulzující tečka „ukládá se" (status footer) */
  /* Schéma linky: sbíhání toku (join). Teal — odlišené od brand modré (odkazy/taby/
     tlačítka) i od amber splitu. Split zůstává --warning (amber). */
  --line-join:var(--teal-600); --line-join-soft:var(--teal-50); --line-join-fg:var(--teal-800);

  /* Test-environment accent */
  --env-test:var(--amber-800);

  /* Sticky page footer — translucent surface over scrolling content.
     Tokenised so dark theme can flip it (otherwise it stays white on dark). */
  --page-footer-bg:rgba(255,255,255,.92);

  /* Backdrop dims behind floating surfaces (modal/drawer/launcher overlays).
     Same slate-900 tint in both themes (overlay convention). */
  --backdrop:rgba(15,23,42,.50);
  --backdrop-soft:rgba(15,23,42,.32);

  /* Toast / bulk action bar — high-contrast snackbar. LIGHT theme: dark surface,
     white text (pops on the light page). DARK theme: inverts to a light surface
     with dark text (see the dark block) so it pops there too. fg/subtle are
     tokenised so labels, icons and hovers flip with the surface. */
  --toast-bg:var(--slate-900);
  --toast-fg:var(--white);              /* text/icons on the bar */
  --toast-subtle:rgba(255,255,255,.7);  /* dimmed icons */
  --toast-hover:rgba(255,255,255,.14);  /* ghost-button rest fill */
  /* Tooltip — always a dark chip with light text, in both themes (a classic
     tooltip; the prior --text/--on-accent pair went light-on-light in dark). */
  --tooltip-bg:var(--slate-900);
  --tooltip-fg:var(--white);
  --toast-border:transparent;           /* light: dark surface contrasts the page, no border */
  --toast-accent:var(--blue-300);       /* undo link + timer bar */
  /* Buttons on the bar = modal buttons from the OPPOSITE theme (the bar's surface
     is inverted). LIGHT bar (dark surface) → modal-DARK buttons. */
  --barbtn-bg:var(--gray-900);          /* = dark --surface (#111827) */
  --barbtn-border:var(--dark-border-strong);
  --barbtn-fg:var(--dark-text);
  --barbtn-hover:var(--dark-hover);             /* = dark --surface-hover */
  --barbtn-hover-border:var(--dark-text-muted); /* = dark --text-muted */
  --barbtn-danger-border:var(--dark-danger-soft);
  --barbtn-danger-fg:var(--red-400);                 /* resting: AA on gray-900 (6.4:1) */
  --barbtn-danger-hover-bg:var(--dark-danger-soft);  /* = dark --danger-soft */
  --barbtn-danger-hover:var(--red-300);              /* lift = lighter on dark surface */
  /* Focus ring on the bar's buttons. The bar is on a DARK surface here, so the
     ring needs a lighter/stronger tint to stay visible (the theme's own rings
     are tuned for a light surface and vanish here). */
  --barbtn-ring:rgba(147,197,253,.55);        /* blue-300 @ .55 — pops on dark */
  --barbtn-danger-ring:rgba(252,165,165,.55); /* red-300 @ .55 — pops on dark */

  /* Module category accent text (bg stays an alpha tint; only text flips for dark) */
  --cat-identity-fg:var(--violet-600);
  --cat-warehouse-fg:var(--blue-800);
  --cat-transport-fg:var(--amber-800);
  --cat-production-fg:var(--rose-800);
  --cat-reporting-fg:var(--indigo-700);   /* indigo — odlišeno od modré Sklady / nebeské */
  --cat-traceability-fg:var(--teal-700);
  --cat-assets-fg:var(--green-700);   /* green — odlišeno od amber Dopravy (dříve yellow) */
  --cat-print-fg:var(--slate-600);
  --cat-design-fg:var(--purple-700);   /* Design systém — purple, odlišeno od violet Uživatelů */

  /* Module category DOT — živý mid-tone pro malé barevné tečky (notifikace).
     Záměrně světlejší než -fg (laděné na text): amber-800 jako 7px tečka
     působí zablácene, proto -500. */
  --cat-identity-dot:var(--violet-500);
  --cat-transport-dot:var(--amber-500);
  --cat-assets-dot:var(--green-500);

  /* Avatar colours (decorative) — solid 600-shade fills; component tokens so
     the UI never references primitives directly. White initials sit on top. */
  --avatar-blue:var(--blue-600);
  --avatar-violet:var(--violet-600);
  --avatar-pink:var(--pink-600);
  --avatar-green:var(--green-600);
  --avatar-amber:var(--amber-600);
  --avatar-rose:var(--rose-600);
  --avatar-usermenu:var(--violet-600);

  /* Type scale */
  --font-xs:11px;
  --font-sm:12px;
  --font-body:13px;
  --font-md:14px;
  --font-lg:16px;
  --font-xl:20px;
  --font-xl2:22px;   /* between xl and 2xl — detail-panel title (snug context) */
  --font-2xl:26px;   /* top level — page title + dashboard greeting */

  /* Layout */
  --sidebar-w:280px;
  /* Radius scale. Tiny ornaments stay tight; cards/buttons use the default; the
     big floating containers (sidebar, drawers, footer, bulk-bar, launcher, modal)
     use the large step so a panel reads softer than the cards nested inside it. */
  --radius-xs:4px;    /* ornamental: checkbox, kbd, skeleton, code, swatches */
  --radius-sm:6px;    /* inputs, small chips, menu items */
  --radius:8px;       /* default — cards, buttons */
  --radius-lg:14px;   /* large floating containers (bars, panels, overlays) */
  --radius-pill:999px;

  /* Sdílený drag úchyt (6-tečková mřížka) — viz .drag-grip. */
  --drag-grip-svg:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="15" cy="18" r="1"/></svg>');

  /* Spacing scale — 2px grid (the system was built on it: 10px & 14px are the
     two most-used values). Token number = the pixel value. Used for padding &
     gap & margin. Values above 24px stay literal (layout-scale, not rhythm). */
  --space-2:2px;
  --space-4:4px;
  --space-6:6px;
  --space-8:8px;
  --space-10:10px;
  --space-12:12px;
  --space-14:14px;
  --space-16:16px;
  --space-18:18px;
  --space-20:20px;
  --space-24:24px;

  /* Motion — one easing + a small duration scale. fast = hover/colour micro-
     interactions, base = the common control transition, slow = larger panel /
     overlay moves. The sidebar collapse keeps its own --sb-* below (it animates
     width + a label fade with a tuned curve). Honour prefers-reduced-motion. */
  --ease:cubic-bezier(.4,0,.2,1);
  --dur-base:.16s;    /* default control transition (buttons, inputs, rows) — jediná používaná; fast/slow byly nepoužité */

  /* Table density — comfortable by default; [data-density="compact"] on <html>
     (toggled from the toolbar kebab, persisted in localStorage) tightens the row
     padding so more rows fit. Only the table reacts; the rest of the UI is fixed. */
  --row-pad-th-y:var(--space-12);
  --row-pad-td-y:var(--space-14);
  --row-pad-x:var(--space-16);
  /* Kompaktní hustota řádků — sdílí ji „compact“ density i simple-list (rozpad
     v panelu, vždy užší). Jeden zdroj místo hardcoded space-8/space-12. */
  --row-pad-compact-y:var(--space-8);
  --row-pad-compact-x:var(--space-12);

  /* Detail view (drawer | fullscreen) */
  --detail-drawer-w:540px;   /* holds a full edit form comfortably (one column) */
  --detail-inset:12px;       /* = shell padding, keeps the "float" language */

  /* Floating bottom bars (save footer, bulk action bar) — inset from every edge
     so they read as detached cards. Bigger than the shell gap for more "float". */
  --floatbar-inset:32px;

  /* Shadows / elevation (TIER 2, sémantická) — čtyři úrovně vzestupné výšky:
     sm = jemné oddělení (karty, tlačítka), md = zvednutý blok, pop = plovoucí
     překryv (dropdown, popover, tooltip), lg = modální vrstva (modal, drawer).
     Komponenty MUSÍ používat tyto tokeny, ne hardcoded rgba (#09). */
  --shadow-sm:0 1px 2px rgba(15,23,42,.06);
  --shadow-pop:0 8px 24px -4px rgba(15,23,42,.14);
  --shadow-lg:0 24px 60px -10px rgba(15,23,42,.30);
  /* Bespoke elevace tokenizované (dřív hardcoded rgba, #09): */
  --shadow-hairline:0 1px 2px rgba(15,23,42,.04);      /* sidebar panel — sotva znatelný okraj */
  --shadow-raised:0 2px 6px rgba(15,23,42,.12);        /* zvednutý knoflík (sidebar collapse) */
  --shadow-menu:0 6px 24px rgba(15,23,42,.12);         /* uživatelské menu (user-menu-pop) */
  --shadow-knob:0 1px 2px rgba(0,0,0,.3);              /* posuvník switche (knob) */
  --shadow-tooltip:0 4px 14px rgba(15,23,42,.18);      /* tooltipy (sidebar + ui) */
  --shadow-tile-hover:0 4px 16px rgba(15,23,42,.07);   /* dlaždice rozcestníku na hoveru */
  --shadow-drawer:0 8px 30px rgba(15,23,42,.18);       /* mobilní off-canvas sidebar */
  --shadow-block-hover:0 4px 12px rgba(15,23,42,.16);  /* blok časové osy na hoveru */

  /* ---- TIER 3: komponentní tokeny ----------------------------------------
     Aliasy sémantické vrstvy pojmenované podle KOMPONENTY, ne vzhledu. Dark
     mode i white-label = přemapovat jen tuto vrstvu (nebo sémantickou pod ní),
     komponentní CSS se nesahá. Dokončuje trojvrstvou architekturu (#09):
     primitive (--blue-500) → semantic (--brand) → component (--btn-primary-bg).
     Nová hodnota se mění ZDE, ne v pravidle komponenty. */
  --btn-primary-bg:var(--brand);            --btn-primary-fg:var(--on-accent);        --btn-primary-bg-hover:var(--brand-dark);
  --btn-secondary-bg:var(--surface);        --btn-secondary-fg:var(--text);           --btn-secondary-border:var(--border-strong);
  --btn-secondary-bg-hover:var(--surface-hover); --btn-secondary-border-hover:var(--text-muted);
  --btn-ghost-fg:var(--text-muted);         --btn-ghost-bg-hover:var(--surface-hover); --btn-ghost-fg-hover:var(--text);
  --card-bg:var(--surface);                 --card-border:var(--border);              --card-radius:var(--radius);
  --input-bg:var(--surface);                --input-border:var(--border);             --input-fg:var(--text);
  --input-border-focus:var(--brand);        --input-placeholder:var(--text-faint);
  --modal-bg:var(--surface-raised);         --modal-border:var(--border);             --modal-shadow:var(--shadow-lg);
  --drawer-bg:var(--surface-raised);        --drawer-border:var(--border);            --drawer-shadow:var(--shadow-pop);
  --dropdown-bg:var(--surface-raised);      --dropdown-border:var(--border);          --dropdown-shadow:var(--shadow-pop);
}

/* Compact table density — tighter row padding (set on <html> from the toolbar
   kebab; orthogonal to the light/dark theme). */
html[data-density="compact"]{
  --row-pad-th-y:var(--row-pad-compact-y);
  --row-pad-td-y:var(--row-pad-compact-y);
  --row-pad-x:var(--row-pad-compact-x);
}

/* -------------------------------------------------------------------------
   Dark theme — set `data-theme="dark"` on <html> (toggled via toggleTheme()
   in launcher.js, persisted in localStorage). Only neutral surfaces/text/
   borders flip; brand + status hues keep their identity (just slightly
   adjusted soft pairs for contrast on dark). Sidebar/toolbar follow because
   their tokens alias the neutral scale. */
html[data-theme="dark"]{
  /* Neutrals remap onto the --dark-* primitive ramp (TIER 1). */
  --bg:var(--dark-bg);
  --surface:var(--dark-surface);        /* content surface */
  --surface-raised:var(--dark-raised);  /* floating surfaces sit ABOVE surface so they read */
  --surface-alt:var(--dark-surface-alt);/* zebra / subtle blocks */
  --surface-muted:var(--dark-surface-muted); /* tinted panels (sidebar, toolbar) */
  --surface-hover:var(--dark-hover);    /* hover */
  --surface-active:var(--dark-active);  /* brand-tinted active */

  --border:var(--dark-border);
  --border-strong:var(--dark-border-strong);
  --divider:var(--dark-divider);

  --text:var(--dark-text);              /* primary text on dark */
  --text-muted:var(--dark-text-muted);  /* AA on dark surfaces */
  --text-faint:var(--dark-text-faint);  /* labels/placeholders */
  --text-subtle:var(--dark-text-faint); /* tichý label skupiny — na dark stejné jako faint */

  --sidebar-active-bg:var(--dark-hover); /* active nav item bg (was #fff) */
  --sidebar-active-text:var(--brand);    /* same blue as active tabs */

  /* Soft status backgrounds: tone down for dark so pills stay readable. */
  --brand-soft:var(--dark-brand-soft);
  --success-soft:var(--dark-success-soft);
  --warning-soft:var(--dark-warning-soft);
  --danger-soft:var(--dark-danger-soft);
  --info-soft:#0f2740;              /* dark sky tint for info banner */
  --info-fg:var(--sky-300);         /* light blue text/icon on dark */

  /* Chart series — lift one step (400) so segments stay vivid on the dark card. */
  --chart-1:var(--blue-400);
  --chart-2:var(--violet-400);
  --chart-3:var(--teal-400);
  --chart-4:var(--amber-400);
  --chart-5:var(--rose-400);
  --chart-6:var(--sky-300);

  /* Tagy na dark: OKLCH-vyrovnané (stejný recept jako light, jen posunuté L pro
     tmavý povrch): bg L=0.29 C=0.045, text L=0.82 C=0.09, dot L=0.68 C=0.12;
     slate neutrální. Fixní L/C napříč hue → žádná barva nevyčnívá (#27). */
  --tag-slate-bg:oklch(0.29 0.012 257.4); --tag-slate-fg:oklch(0.82 0.02 257.4); --tag-slate-dot:oklch(0.68 0.025 257.4);
  --tag-red-bg:oklch(0.29 0.045 25.3); --tag-red-fg:oklch(0.82 0.09 25.3); --tag-red-dot:oklch(0.68 0.12 25.3);
  --tag-orange-bg:oklch(0.29 0.045 47.6); --tag-orange-fg:oklch(0.82 0.09 47.6); --tag-orange-dot:oklch(0.68 0.12 47.6);
  --tag-amber-bg:oklch(0.29 0.045 70.1); --tag-amber-fg:oklch(0.82 0.09 70.1); --tag-amber-dot:oklch(0.68 0.12 70.1);
  --tag-lime-bg:oklch(0.29 0.045 130.8); --tag-lime-fg:oklch(0.82 0.09 130.8); --tag-lime-dot:oklch(0.68 0.12 130.8);
  --tag-green-bg:oklch(0.29 0.045 149.6); --tag-green-fg:oklch(0.82 0.09 149.6); --tag-green-dot:oklch(0.68 0.12 149.6);
  --tag-emerald-bg:oklch(0.29 0.045 162.5); --tag-emerald-fg:oklch(0.82 0.09 162.5); --tag-emerald-dot:oklch(0.68 0.12 162.5);
  --tag-teal-bg:oklch(0.29 0.045 182.5); --tag-teal-fg:oklch(0.82 0.09 182.5); --tag-teal-dot:oklch(0.68 0.12 182.5);
  --tag-cyan-bg:oklch(0.29 0.045 215.2); --tag-cyan-fg:oklch(0.82 0.09 215.2); --tag-cyan-dot:oklch(0.68 0.12 215.2);
  --tag-sky-bg:oklch(0.29 0.045 237.3); --tag-sky-fg:oklch(0.82 0.09 237.3); --tag-sky-dot:oklch(0.68 0.12 237.3);
  --tag-blue-bg:oklch(0.29 0.045 259.8); --tag-blue-fg:oklch(0.82 0.09 259.8); --tag-blue-dot:oklch(0.68 0.12 259.8);
  --tag-indigo-bg:oklch(0.29 0.045 277.1); --tag-indigo-fg:oklch(0.82 0.09 277.1); --tag-indigo-dot:oklch(0.68 0.12 277.1);
  --tag-violet-bg:oklch(0.29 0.045 292.7); --tag-violet-fg:oklch(0.82 0.09 292.7); --tag-violet-dot:oklch(0.68 0.12 292.7);
  --tag-purple-bg:oklch(0.29 0.045 303.9); --tag-purple-fg:oklch(0.82 0.09 303.9); --tag-purple-dot:oklch(0.68 0.12 303.9);
  --tag-fuchsia-bg:oklch(0.29 0.045 322.1); --tag-fuchsia-fg:oklch(0.82 0.09 322.1); --tag-fuchsia-dot:oklch(0.68 0.12 322.1);
  --tag-pink-bg:oklch(0.29 0.045 354.3); --tag-pink-fg:oklch(0.82 0.09 354.3); --tag-pink-dot:oklch(0.68 0.12 354.3);
  --tag-rose-bg:oklch(0.29 0.045 16.4); --tag-rose-fg:oklch(0.82 0.09 16.4); --tag-rose-dot:oklch(0.68 0.12 16.4);

  /* Soft-bg borders (banner): the light -200 shades glow on dark; use the 800
     step — a quiet tone frame that reads as an edge, not a highlight. */
  --success-border:var(--green-800);
  --warning-border:var(--amber-800);
  --danger-border:var(--red-800);
  --info-border:var(--sky-800);

  /* Hover/emphasis variants used as TEXT or border lighten on dark — the
     light-theme blue-700/red-600 are far below AA on a dark surface (2.6:1 /
     3.7:1). Bump to the 400 shade (AA with headroom: ~7:1 / 6.4:1). */
  --brand-dark:var(--blue-400);
  /* Danger BUTTON text on the DARK theme sits on a dark surface, so a lighter
     red reads best (red-400 = 6.4:1 on the dark card). Hover lightens further. */
  --btn-danger-fg:var(--red-400);
  --btn-danger-fg-hover:var(--red-300);

  /* Stage pills — arrived/loading get dark-tinted bg + light text.
     ramp/done/departed reference semantic tokens above, so they flip on their own. */
  --stage-arrived-bg:var(--dark-brand-soft);  --stage-arrived-fg:var(--blue-300);
  --stage-loading-bg:var(--dark-loading-soft);--stage-loading-fg:var(--violet-300);
  --stage-ramp-fg:var(--amber-300);
  --stage-done-fg:var(--green-400);
  --stage-departed-bg:var(--teal-950); --stage-departed-fg:var(--teal-300); --stage-departed-dot:var(--teal-400);
  --line-join:var(--teal-400); --line-join-soft:var(--teal-950); --line-join-fg:var(--teal-300);

  /* Status text on soft backgrounds — light variants for dark. */
  --success-fg:var(--green-400);
  --warning-fg:var(--amber-300);
  --danger-fg:var(--red-400);

  /* Category accents — lighter text tints for dark. */
  --cat-identity-fg:var(--violet-300);
  --cat-warehouse-fg:var(--blue-300);
  --cat-transport-fg:var(--amber-300);
  --cat-production-fg:var(--rose-300);
  --cat-reporting-fg:var(--indigo-300);
  --cat-traceability-fg:var(--teal-300);
  --cat-assets-fg:var(--green-300);
  --cat-print-fg:var(--slate-300);
  --cat-design-fg:var(--purple-300);

  /* Category dots on dark — o stupeň světlejší (-400), ať svítí na tmavém panelu. */
  --cat-identity-dot:var(--violet-400);
  --cat-transport-dot:var(--amber-400);
  --cat-assets-dot:var(--green-400);

  /* Test-environment accent — lighter on dark. */
  --env-test:var(--amber-300);

  /* Sticky footer flips to a dark translucent surface (was stuck white). */
  --page-footer-bg:rgba(17,24,39,.92);   /* --dark-surface @ 92% */

  /* Toast / bulk bar — INVERT on dark: a light surface with dark text pops on the
     dark page just like the dark surface pops on the light page. */
  --toast-bg:var(--slate-100);
  --toast-fg:var(--slate-900);
  --toast-subtle:rgba(15,23,42,.55);    /* dimmed icons (slate-900 @ alpha) */
  /* Tooltip on dark: slate-900 would vanish against the dark surface, so lift it
     to a lighter slate that still reads as a dark chip with light text. */
  --tooltip-bg:var(--slate-700);
  --tooltip-fg:var(--white);
  --toast-hover:rgba(15,23,42,.08);     /* ghost-button rest fill */
  --toast-border:transparent;
  --toast-accent:var(--blue-700);       /* readable link on the light surface */
  /* DARK bar (light surface) → modal-LIGHT buttons (white surface, light tokens). */
  --barbtn-bg:var(--white);
  --barbtn-border:var(--slate-300);
  --barbtn-fg:var(--slate-800);
  --barbtn-hover:var(--slate-200);              /* = light --surface-hover */
  --barbtn-hover-border:var(--slate-600);       /* = light --text-muted */
  --barbtn-danger-border:var(--red-100);
  --barbtn-danger-fg:var(--red-600);            /* resting: AA on white (4.8:1) */
  --barbtn-danger-hover-bg:var(--red-100);      /* = light --danger-soft */
  --barbtn-danger-hover:var(--red-700);         /* lift = darker on light surface */
  /* Bar sits on a LIGHT surface in the dark theme, so the ring uses the deeper
     hues that read against white. */
  --barbtn-ring:rgba(37,99,235,.45);            /* blue-600 @ .45 — pops on white */
  --barbtn-danger-ring:rgba(220,38,38,.40);     /* red-600 @ .40 — pops on white */

  /* Brand focus ring — slightly stronger on dark for visibility. */
  --brand-ring:rgba(125,180,240,.18);
  --brand-ring-strong:rgba(125,180,240,.40);

  /* Shadows: deeper on dark. */
  --shadow-sm:0 1px 2px rgba(0,0,0,.4);
  --shadow-pop:0 8px 24px -4px rgba(0,0,0,.55);
  --shadow-lg:0 24px 60px -10px rgba(0,0,0,.65);
}

/* =======================================================================
   ACCENT THEMES — set `data-accent="<hue>"` on <html> (chosen in Nastavení →
   Vzhled, persisted via launcher.js). Overrides ONLY the brand token set, so
   active states / primary buttons / focus rings / links pick up the new hue.
   Neutrals/surfaces/panels/borders are intentionally LEFT ALONE — tinting them
   cascaded into mismatched borders, glaring dividers and contrast risks, so the
   accent stays brand-only (cleanest, safe in light + dark). No attribute =
   default blue. Each block mirrors the :root brand sada.
   Every value is a palette token via var(), EXCEPT --brand-ring(-strong): the
   focus ring needs ALPHA, which the palette (solid hex only) can't express as a
   token. The rgba() literals are the matching *-500 colour with .18 / .38 alpha
   (e.g. rgba(34,197,94,…) == --green-500 #22c55e) — same convention as the
   default blue ring. rgba is used (not color-mix) for max browser support. */
html[data-accent="green"]{
  --brand:var(--green-600); --brand-dark:var(--green-700); --brand-soft:var(--green-50);
  --surface-active:var(--green-50); --sidebar-active-text:var(--green-600);
  --brand-ring:rgba(34,197,94,.18); --brand-ring-strong:rgba(34,197,94,.38);
}
html[data-accent="violet"]{
  --brand:var(--violet-500); --brand-dark:var(--violet-700); --brand-soft:var(--violet-50);
  --surface-active:var(--violet-50); --sidebar-active-text:var(--violet-600);
  --brand-ring:rgba(139,92,246,.18); --brand-ring-strong:rgba(139,92,246,.38);
}
html[data-accent="teal"]{
  --brand:var(--teal-600); --brand-dark:var(--teal-700); --brand-soft:var(--teal-50);
  --surface-active:var(--teal-50); --sidebar-active-text:var(--teal-600);
  --brand-ring:rgba(20,184,166,.18); --brand-ring-strong:rgba(20,184,166,.38);
}
html[data-accent="indigo"]{
  --brand:var(--indigo-500); --brand-dark:var(--indigo-700); --brand-soft:var(--indigo-50);
  --surface-active:var(--indigo-50); --sidebar-active-text:var(--indigo-600);
  --brand-ring:rgba(99,102,241,.18); --brand-ring-strong:rgba(99,102,241,.38);
}
html[data-accent="rose"]{
  --brand:var(--rose-500); --brand-dark:var(--rose-700); --brand-soft:var(--rose-50);
  --surface-active:var(--rose-50); --sidebar-active-text:var(--rose-600);
  --brand-ring:rgba(244,63,94,.18); --brand-ring-strong:rgba(244,63,94,.38);
}
/* In dark, brand-dark LIGHTENS (legible hover/solid on dark) and the soft /
   active tints go DARK (light *-50 would glare on dark surfaces — e.g. the
   radio-row checked bg). Accent stays brand-only: neutrals/panels/borders are
   left untouched so contrast & layout never break. */
html[data-theme="dark"][data-accent="green"]{  --brand-dark:var(--green-400);  --brand-soft:var(--green-950);  --surface-active:var(--green-950); }
html[data-theme="dark"][data-accent="violet"]{ --brand-dark:var(--violet-400); --brand-soft:var(--violet-950); --surface-active:var(--violet-950); }
html[data-theme="dark"][data-accent="teal"]{   --brand-dark:var(--teal-400);   --brand-soft:var(--teal-950);   --surface-active:var(--teal-950); }
html[data-theme="dark"][data-accent="indigo"]{ --brand-dark:var(--indigo-400); --brand-soft:var(--indigo-950); --surface-active:var(--indigo-950); }
html[data-theme="dark"][data-accent="rose"]{   --brand-dark:var(--rose-400);   --brand-soft:var(--rose-950);   --surface-active:var(--rose-950); }

/* Accent swatch picker (Nastavení → Vzhled) — a row of round colour dots. */
.accent-swatches{ display:flex; gap:var(--space-12); flex-wrap:wrap; }
.accent-swatch{
  width:34px; height:34px; border-radius:50%;
  border:2px solid transparent; cursor:pointer; padding:0;
  background:var(--sw); position:relative;
  transition:transform .12s ease, box-shadow .12s ease;
}
.accent-swatch:hover{ transform:translateY(-1px); }
.accent-swatch.is-active{ box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--sw); }
.accent-swatch.is-active::after{
  content:""; position:absolute; inset:0; margin:auto;
  width:12px; height:12px;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='white'%3E%3Cpath d='M13.485 4.515a1 1 0 0 1 0 1.414l-6.364 6.364a1 1 0 0 1-1.414 0L2.515 8.95a1 1 0 1 1 1.414-1.414l2.485 2.485 5.657-5.657a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E") center/contain no-repeat;
}

*{ box-sizing:border-box; margin:0; padding:0 }
html,body{ height:100% }
body{
  font-family:-apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", system-ui, sans-serif;
  font-size:var(--font-body);
  color:var(--text);
  background:var(--bg);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
a{ color:inherit; text-decoration:none }
button{ font-family:inherit; cursor:pointer; border:0; background:none; color:inherit }
input,select{ font-family:inherit }


/* -------------------------------------------------------------------------
   Layout shell
   ------------------------------------------------------------------------- */
.shell{
  display:grid;
  grid-template-columns:var(--sidebar-w) 1fr;
  height:100vh;
  grid-template-areas: "sidebar main";
  padding:var(--space-12);
  gap:var(--space-12);
  background:var(--surface);
}
.shell.sidebar-collapsed{
  grid-template-columns:64px 1fr;
}

/* -------------------------------------------------------------------------
   Sidebar
   ------------------------------------------------------------------------- */
.sidebar{
  grid-area:sidebar;
  background:var(--sidebar-bg);
  border:1px solid var(--sidebar-border);
  border-radius:var(--radius-lg);
  padding:var(--space-16) var(--space-12);
  display:flex;
  flex-direction:column;
  gap:var(--space-2);
  overflow:visible;
  /* Stay within the grid row (100vh shell) instead of growing with content,
     so the head/foot pin and only .sidebar-body scrolls. */
  min-height:0;
  box-shadow:var(--shadow-hairline);
  color:var(--sidebar-text);
}
/* Logo (head) and profile (foot) are fixed; only the nav body scrolls. */
.sidebar-head,
.sidebar-foot{ flex:none; }
.sidebar .nav-section{
  font-size:var(--font-xs);
  font-weight:700;
  color:var(--sidebar-text-faint);
  letter-spacing:.08em;
  text-transform:uppercase;
  padding:var(--space-14) var(--space-12) var(--space-6);
}
.sidebar .nav-item{
  display:flex;
  align-items:center;
  gap:var(--space-10);
  padding:var(--space-8) var(--space-12);
  border-radius:var(--radius-sm);
  color:var(--sidebar-text-muted);
  font-size:var(--font-md);
  font-weight:500;
  transition:.16s ease;
  cursor:pointer;
}
.sidebar .nav-item:hover{
  background:var(--sidebar-hover);
  color:var(--sidebar-text);
}
.sidebar .nav-item.active{
  background:var(--sidebar-active-bg);
  color:var(--sidebar-active-text);
  font-weight:600;
}
/* Nav icons are 20px. Sized in CSS (overriding the width/height="18" baked
   into each inline SVG) so it's one place to tweak. `:not(.chev)` keeps the
   accordion/dropdown chevrons at their own smaller size. */
.sidebar .nav-item svg:not(.chev){ flex:0 0 20px; width:20px; height:20px; opacity:.85 }
.sidebar .nav-item.active svg{ opacity:1 }
.sidebar .nav-item .chev{
  margin-left:auto;
  opacity:.6;
}
/* Status dot indicator: marks sidebar entries that lead to a real page
   (data-real="1" set by sidebar.js when href is not a placeholder "#").
   Amber = stránka existuje, ale ještě se na ní pracuje (rozpracováno).
   Zelená (data-done="1") = uživatel potvrdil, že je část modulu hotová.
   Skipped on the active item — its filled brand background is signal enough. */
.sidebar a.nav-item[data-real]:not(.active)::after{
  content:"";
  width:8px;
  height:8px;
  border-radius:50%;
  background:var(--warning);
  margin-left:auto;
  flex-shrink:0;
}
.sidebar a.nav-item[data-done]:not(.active)::after{ background:var(--success) }
/* Design systém = katalog, ne produkční modul → bez stavových kuliček. */
.sidebar[data-module="design"] a.nav-item[data-real]::after{ display:none }

/* Accordion sub-navigation: a .nav-group wraps a parent .nav-item plus
   a .nav-sub list. The chevron in the parent rotates when open and the
   sub list slides in. The group's header item is the toggle (button-like)
   and never carries an href. */
.sidebar .nav-group > .nav-item{ position:relative }
.sidebar .nav-group > .nav-item .chev{
  margin-left:auto;
  opacity:.6;
  transition:transform .16s ease;
}
.sidebar .nav-group.open > .nav-item .chev{ transform:rotate(90deg) }
.sidebar .nav-sub{
  display:none;
  flex-direction:column;
  gap:var(--space-2);
  margin:var(--space-2) 0 var(--space-4) 28px;
}
.sidebar .nav-group.open .nav-sub{ display:flex }
.sidebar .nav-sub .nav-item{
  padding:var(--space-8) var(--space-12);
  font-size:var(--font-body);
  color:var(--sidebar-text-muted);
}
.sidebar .nav-sub .nav-item.active{
  color:var(--sidebar-active-text);
  background:var(--sidebar-active-bg);
  font-weight:600;
}
/* In collapsed mode there is no room for the sub list. The whole group
   header behaves like a plain nav-item — sub items are hidden. */
.shell.sidebar-collapsed .sidebar .nav-group > .nav-item .chev,
.shell.sidebar-collapsed .sidebar .nav-sub{ display:none }
/* -------------------------------------------------------------------------
   Sidebar — head (brand + env) / body (nav) / foot (user menu)
   Rendered by sidebar.js from a <aside class="sidebar" data-module="…" data-active="…">.
   ------------------------------------------------------------------------- */
.sidebar{ padding:0; gap:0 }
.sidebar-head{
  position:relative;
  /* padding-left matches the collapsed override (14px 13px) so the logo
     stays at the exact same x-position when the panel collapses — the
     collapsed value is constrained by 64px outer width and can't change,
     so expanded follows it instead. */
  padding:var(--space-14) var(--space-12);
  display:flex;
  align-items:center;
  gap:var(--space-10);
}
.sidebar-head .brand{
  flex:1;
  min-width:0;
  display:flex;
  align-items:center;
  gap:var(--space-10);
  font-weight:700;
  letter-spacing:-.01em;
  text-decoration:none;
  color:var(--sidebar-text);
}
.sidebar-head .brand .logo{
  width:36px; height:36px;
  border-radius:var(--radius);
  display:grid;
  place-items:center;
  font-size:15px;
  font-weight:800;
  flex-shrink:0;
}
/* Vychozi NextFIS "N" = brand gradient. :not(.logo--module) nechava modulovou
   variantu bez gradientu, aby se projevil .cat-* tint (stejne jako launcher). */
.sidebar-head .brand .logo:not(.logo--module){
  background:linear-gradient(135deg, var(--brand), var(--brand-dark));
  color:var(--on-accent);   /* bila "N"; modulova varianta bere barvu z .cat-* */
}
/* V modulu: logo = ikona modulu v jeho barvě — tint pozadí + currentColor ikona
   bere z .cat-* třídy (žádný vlastní background tady, ať .cat-* vyhraje; gradient
   je gated přes :not(.logo--module) výše). */
.sidebar-head .brand .logo--module svg{ width:20px; height:20px }
.sidebar-head .brand-text{
  display:flex;
  flex-direction:column;
  line-height:1.2;
  min-width:0;
}
.sidebar-head .brand-text .name{ font-size:var(--font-md); font-weight:700 }
.sidebar-head .brand-text .sub{
  font-size:var(--font-xs);
  font-weight:500;
  color:var(--sidebar-text-muted);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.sidebar-head .brand-text .sub.is-env-test{
  color:var(--env-test);
  font-weight:600;
}

/* ===== Impersonace („Přihlásit se jako") ============================
   Pruh pod brandem, který nepřehlédnutelně signalizuje, že prohlížíme
   aplikaci jako jiný uživatel. Amber (warning) tón + tlačítko Ukončit. */
.impersonate-bar{
  display:flex;
  align-items:center;
  gap:var(--space-8);
  margin:var(--space-8) var(--space-12) 0;
  padding:var(--space-8) var(--space-10);
  border-radius:var(--radius);
  background:var(--warning-soft);
  border:1px solid var(--warning-border);
  color:var(--warning-fg);
}
.impersonate-bar .imp-ico{ display:flex; flex-shrink:0 }
.impersonate-bar .imp-text{
  flex:1; min-width:0;
  display:flex; flex-direction:column; line-height:1.25;
  font-size:var(--font-xs);
}
.impersonate-bar .imp-text strong{ font-size:var(--font-sm); font-weight:700 }
.impersonate-bar .imp-stop{
  flex-shrink:0;
  padding:2px var(--space-8);
  border-radius:var(--radius-pill);
  border:1px solid var(--warning-border);
  background:transparent;
  color:var(--warning-fg);
  font-size:var(--font-xs); font-weight:600;
  cursor:pointer;
}
.impersonate-bar .imp-stop:hover{ background:var(--warning-border) }
/* Sbalený sidebar: pruh = 36×36 čtverec se stejnou šířkou i x-pozicí jako
   ikony nav-item (boční padding --space-12, element 36px, vycentrováno). */
.sidebar-collapsed .impersonate-bar{
  width:36px; height:36px;
  margin:var(--space-8) auto 0;
  padding:0;
  justify-content:center;
}
.sidebar-collapsed .impersonate-bar .imp-text,
.sidebar-collapsed .impersonate-bar .imp-stop{ display:none }

/* Profil dole v režimu impersonace = amber rámeček + odznak „Zobrazeno jako". */
.user-menu.is-impersonating .user-menu-trigger{
  border:1px solid var(--warning-border);
  background:var(--warning-soft);
}
.user-menu.is-impersonating .user-menu-trigger .avatar{
  background:var(--warning); color:var(--white);
}
.user-menu .role.imp-flag{
  color:var(--warning-fg); font-weight:700;
  text-transform:uppercase; font-size:10px; letter-spacing:.04em;
}

/* ===== Pruh testovacího prostředí ===================================
   Nepřehlédnutelný pruh pod brandem (vzor .impersonate-bar), danger tón =
   nejsilnější varování „nejsi v ostrém". Jen v testu; produkce nic. */
.env-bar{
  display:flex;
  align-items:center;
  gap:var(--space-8);
  margin:var(--space-8) var(--space-12) 0;
  padding:var(--space-8) var(--space-10);
  border-radius:var(--radius);
  background:var(--danger-soft);
  border:1px solid var(--danger-border);
  color:var(--danger-fg);
}
.env-bar .env-bar-ico{ display:flex; flex-shrink:0 }
.env-bar .env-bar-text{
  flex:1; min-width:0;
  display:flex; flex-direction:column; line-height:1.25;
  font-size:var(--font-xs);
}
.env-bar .env-bar-text strong{ font-size:var(--font-sm); font-weight:700 }
/* Sbalený sidebar: pruh = 36×36 ikona (stejně jako impersonate-bar), text skryt. */
.sidebar-collapsed .env-bar{
  width:36px; height:36px;
  margin:var(--space-8) auto 0;
  padding:0;
  justify-content:center;
}
.sidebar-collapsed .env-bar .env-bar-text{ display:none }
.user-menu-pop .is-impersonate-stop{ color:var(--warning-fg); font-weight:600 }
/* Above main content AND the floating page-footer (z-index:10) so the user-menu
   popover — which opens upward from the sidebar foot — sits over the footer
   instead of behind it. Still below the detail drawer/modals (80+). Collapsed-
   mode tooltips are a fixed node on <body> (see .sidebar-tooltip), so this
   z-index only governs the panel itself. */
.sidebar{ position:relative; z-index:40 }
/* Let the collapse button overflow the sidebar's right edge into main. */
.sidebar-head{ overflow:visible }

/* Collapse toggle = small circle vertically centered on the sidebar's
   right edge. Half inside the panel, half outside, signaling "fold this
   column in/out". Lives at sidebar root so it lines up to the full
   panel height, not just the head. */
.sidebar > .sidebar-collapse-btn{
  position:absolute;
  top:50%;
  right:-16px;
  transform:translateY(-50%);
  width:32px; height:32px;
  border-radius:50%;
  border:1px solid var(--border);
  background:var(--surface);
  color:var(--text-muted);
  display:grid;
  place-items:center;
  cursor:pointer;
  z-index:50;
  transition:.15s ease;
  box-shadow:var(--shadow-raised);
}
.sidebar > .sidebar-collapse-btn:hover{
  color:var(--brand);
  border-color:var(--brand);
}
.sidebar > .sidebar-collapse-btn:focus-visible{
  outline:none;
  border-color:var(--brand);
  box-shadow:0 0 0 3px var(--brand-ring-strong);
}
.sidebar > .sidebar-collapse-btn .chev{
  transition:transform .18s ease;
}
.shell.sidebar-collapsed .sidebar > .sidebar-collapse-btn .chev{
  transform:rotate(180deg);
}
/* Když je otevřený panel notifikací (nebo user menu), schovej collapse
   tlačítko — jinak ten kulatý šíp koliduje s rohem popoveru. */
.sidebar:has(.notif-menu.open) > .sidebar-collapse-btn,
.sidebar:has(.user-menu.open) > .sidebar-collapse-btn{
  opacity:0;
  pointer-events:none;
}

/* Test-environment indicator on the brand logo — a small dot in the
   bottom-right corner. Visible both expanded and collapsed, so the user
   always knows they're not in production. */
.sidebar-head .brand .logo{ position:relative }
/* Tečka u loga = indikátor TESTOVACÍHO prostředí. Svítí jen v testu; v produkci
   se skryje. Danger (červená) = stejná rodina jako pruh .env-bar. Užitečná hlavně
   ve SBALENÉM sidebaru (u loga vedle 36px ikony pruhu). Jedna velikost. */
.sidebar-head .brand.is-env-test .logo::after{
  content:"";
  position:absolute;
  bottom:-2px; right:-2px;
  width:10px; height:10px;
  border-radius:50%;
  background:var(--danger);
  border:2px solid var(--sidebar-bg);
}

.sidebar-body{
  flex:1;
  min-height:0;          /* allow the scroll area to shrink below content height */
  overflow-y:auto;
  padding:var(--space-8) var(--space-12);
  display:flex;
  flex-direction:column;
  gap:var(--space-2);
}

/* In-sidebar nav filter (long modules, e.g. Design system). Uses the shared
   .search base (full-width, default size + border) tuned to the sidebar.
   IMPORTANT: .search--block carries flex:1, which in this VERTICAL flex column
   (.sidebar-body) would stretch the field to the full panel height — pin it
   with flex:none. White surface (not the sidebar bg, or it reads as disabled). */
.sidebar .nav-search{
  flex:none;
  margin:var(--space-6) var(--space-2) var(--space-10);
  background:var(--surface);
  border-color:var(--border);
}
.sidebar .nav-search input{ color:var(--sidebar-text); }
.sidebar .nav-search input::placeholder{ color:var(--text-faint); }
.sidebar .nav-search:focus-within{ border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-ring); }
.sidebar .nav-search-empty{
  padding:var(--space-8) var(--space-12);
  font-size:var(--font-sm);
  color:var(--sidebar-text-muted);
}
/* The filter sets [hidden] on nav entries / section headings; .sidebar .nav-item
   etc. set display:flex (specificity beats the UA [hidden] rule), so restore it. */
.sidebar .nav-item[hidden],
.sidebar .nav-group[hidden],
.sidebar .nav-section[hidden],
.sidebar .nav-search-empty[hidden]{ display:none !important; }
/* Same trap for buttons / the floating footer / the coverage breakdown: their
   display (inline-flex / flex / grid) beats the UA [hidden] rule, so [hidden]
   would not hide them. Restore it for the elements we toggle. (.tab is handled
   near its own rule.) */
.btn[hidden],
.page-footer[hidden],
.pagination[hidden],
.coverage-list[hidden]{ display:none !important; }
/* No room for the filter when the rail is collapsed to icons. */
.shell.sidebar-collapsed .sidebar .nav-search,
.shell.sidebar-collapsed .sidebar .nav-search-empty{ display:none; }

.sidebar-foot{
  padding:var(--space-10) var(--space-12) var(--space-14);
  display:flex;
  flex-direction:column;
  /* Stejný rozestup mezi všemi řádky footeru (Todo/Nastavení/Nápověda/
     Notifikace/user) jako uvnitř foot-extra. */
  gap:var(--space-4);
}
/* Spodní skupiny footeru: Todo+Nastavení (foot-extra) a Nápověda (foot-help),
   řádky nad Notifikacemi. Jemná horní linka odděluje CELOU spodní skupinu od
   scrollované navigace — nese ji první blok (foot-extra), ne každý zvlášť. */
.sidebar-foot .foot-extra,
.sidebar-foot .foot-help{
  display:flex;
  flex-direction:column;
  gap:var(--space-4);
}
.sidebar-foot .foot-extra{
  padding-top:var(--space-8);
  border-top:1px solid var(--sidebar-border, var(--divider));
}
/* Když Todo/Nastavení chybí, linku nese Nápověda (fallback). */
.sidebar-foot > .foot-help:first-child{
  padding-top:var(--space-8);
  border-top:1px solid var(--sidebar-border, var(--divider));
}
/* Vizuálně sjednotit s řádkem Notifikace (a user-trigger): stejný padding a
   ikona ve 24px boxu, aby labely „Nápověda" / „Notifikace" začínaly na stejném
   x. Bez tohoto by .nav-item (20px ikona, jiný padding) nesedělo. */
.sidebar-foot .foot-help-item{
  padding:var(--space-6) var(--space-10);
  gap:var(--space-10);
  /* barva textu i ikona = stejné jako nav položky (muted, opacity .85) — dědí
     z .nav-item, žádný override. Footer (Nápověda/Notifikace/user) má vypadat
     jako zbytek menu, ne výrazněji. */
}
.sidebar-foot .foot-help-item svg:not(.chev){
  flex:0 0 24px;
  width:24px;
  height:24px;
  padding:2px;
}
/* Počítadlo u nav položky (např. Todo) — vpravo, oválný badge. */
.sidebar .nav-item .nav-badge{
  margin-left:auto;
  flex:none;
  min-width:18px;
  height:18px;
  padding:0 var(--space-6);
  display:inline-flex; align-items:center; justify-content:center;
  border-radius:var(--radius-pill);
  background:var(--surface-muted);
  color:var(--text-muted);
  font-size:var(--font-xs);
  font-weight:600;
}
.sidebar .nav-item.active .nav-badge{ background:var(--brand-soft); color:var(--brand-dark); }
.user-menu{ position:relative }
.user-menu-trigger{
  display:flex;
  align-items:center;
  gap:var(--space-10);
  padding:var(--space-6) var(--space-10);
  width:100%;
  border:1px solid transparent;
  border-radius:var(--radius-sm);
  background:transparent;
  cursor:pointer;
  text-align:left;
  transition:.15s ease;
  color:var(--sidebar-text-muted);   /* stejně jako nav položky + Notifikace/Nápověda */
}
.user-menu-trigger:hover{
  background:var(--sidebar-hover);
  color:var(--sidebar-text);
}
.user-menu-trigger .avatar{
  width:24px; height:24px;
  border-radius:50%;
  background:var(--avatar-usermenu);
  color:var(--on-accent);
  display:grid;
  place-items:center;
  font-size:var(--font-xs);
  font-weight:600;
  flex-shrink:0;
}
.user-menu-trigger .name{
  flex:1;
  font-size:var(--font-md);
  font-weight:500;
  color:inherit;   /* dědí muted z triggeru → stejné jako nav položky */
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.user-menu-trigger .chev{
  color:var(--sidebar-text-muted);
  flex-shrink:0;
  transition:transform .15s ease;
}
.user-menu.open .user-menu-trigger .chev{ transform:rotate(180deg) }
.user-menu-pop{
  position:absolute;
  bottom:calc(100% + 6px);
  left:0; right:0;
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius);
  box-shadow:var(--shadow-menu);
  padding:var(--space-4);
  display:none;
  flex-direction:column;
  z-index:20;
}
.user-menu.open .user-menu-pop{ display:flex }
.user-menu-pop button{ /* radius-sm set below */
  display:flex;
  align-items:center;
  gap:var(--space-10);
  padding:var(--space-8) var(--space-10);
  background:transparent;
  border:0;
  border-radius:var(--radius-sm);
  font-size:var(--font-md);
  color:var(--text);
  cursor:pointer;
  text-align:left;
}
.user-menu-pop button:hover{ background:var(--surface-hover) }
.user-menu-pop button svg{ color:var(--text-muted); flex-shrink:0 }

/* Popover header: avatar + identity (name / role / email) */
.user-menu-pop{ padding:var(--space-6); min-width:240px }
.user-menu-head{
  display:flex;
  align-items:center;
  gap:var(--space-10);
  padding:var(--space-8) var(--space-10) var(--space-10);
}
.user-menu-head .avatar{
  width:38px; height:38px;
  border-radius:50%;
  background:var(--avatar-usermenu);
  color:var(--on-accent);
  display:grid; place-items:center;
  font-size:var(--font-sm);
  font-weight:600;
  flex-shrink:0;
}
.user-menu-id{ display:flex; flex-direction:column; line-height:1.35; min-width:0 }
.user-menu-id .name{ font-size:var(--font-md); font-weight:600; color:var(--text) }
.user-menu-id .role{ font-size:var(--font-sm); color:var(--brand); font-weight:500 }
.user-menu-id .email{
  font-size:var(--font-sm);
  color:var(--text-faint);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.user-menu-sep{
  height:1px;
  background:var(--divider);
  margin:var(--space-4) var(--space-6);
}
.user-menu-pop button.is-danger{ color:var(--danger) }
.user-menu-pop button.is-danger svg{ color:var(--danger) }
.user-menu-pop button.is-danger:hover{ background:var(--danger-soft) }

/* ── Přepínač organizace (tenant) v profilu ─────────────────────────── */
.user-menu-label{
  font-size:var(--font-xs); font-weight:600; letter-spacing:.04em; text-transform:uppercase;
  color:var(--text-faint); padding:var(--space-6) var(--space-8) var(--space-4);
}
.user-menu-pop button.org-item{ display:flex; align-items:center; gap:var(--space-10); text-align:left; }
/* Aktivní org = modré pozadí jako vybraná položka v dropdownech (--surface-active). */
.user-menu-pop button.org-item.is-active{ cursor:default; background:var(--surface-active); }
.user-menu-pop button.org-item.is-active:hover{ background:var(--surface-active); }
.org-item-ava{
  flex:none; width:28px; height:28px; border-radius:50%;   /* kulatý jako ostatní avatary */
  display:grid; place-items:center; font-size:var(--font-xs); font-weight:600;
  background:var(--surface-muted); color:var(--text-muted);
}
.org-item.is-active .org-item-ava{ background:var(--brand-soft); color:var(--brand-dark); }
.org-item-body{ display:flex; flex-direction:column; gap:1px; min-width:0; flex:1; }
.org-item-name{ font-size:var(--font-md); font-weight:500; color:var(--text);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.org-item.is-active .org-item-name{ font-weight:600; }
.org-item-env{ font-size:var(--font-xs); font-weight:600; color:var(--danger-fg); }

/* ── Název organizace + odznak prostředí v hlavičce sidebaru ────────── */
.sidebar-head .brand-text .sub.org-line{ display:flex; align-items:center; gap:var(--space-6); }
.sidebar-head .org-name{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Pilulka prostředí: jen TEST (amber varování). Produkce = normál, bez odznaku.
   Font/řez dle konvence pilulek (.status/.tag): --font-xs, weight 600. */
.sidebar-head .env-pill{
  flex:none; font-size:var(--font-xs); font-weight:600; letter-spacing:.02em;
  padding:1px var(--space-6); border-radius:var(--radius-xs); line-height:1.5;
}
.sidebar-head .env-pill.is-env-test{ background:var(--tag-green-bg); color:var(--tag-green-fg); }

/* ── Notifikace (zvoneček) ─────────────────────────────────────────────
   Samostatná ikona vpravo v patičce (vedle avatara). Jen zvoneček + badge
   počtu nepřečtených v rohu — žádný label, žádný plný řádek. */
.notif-menu{ position:relative }
/* Plný řádek nad uživatelem — zarovnání jako .user-menu-trigger (ikona + text). */
.notif-trigger{
  display:flex; align-items:center;
  gap:var(--space-10);
  width:100%;
  padding:var(--space-6) var(--space-10);
  border:1px solid transparent;
  border-radius:var(--radius-sm);
  background:transparent;
  cursor:pointer;
  text-align:left;
  color:var(--sidebar-text-muted);
  transition:.15s ease;
}
.notif-trigger:hover,
.notif-menu.open .notif-trigger{
  background:var(--sidebar-hover);
  color:var(--sidebar-text);
}
/* Aktivní stav — jsem na stránce Notifikace (data-active="notifications").
   Stejné zvýraznění jako aktivní nav-item. */
.notif-trigger.active{
  background:var(--sidebar-active-bg);
  color:var(--sidebar-active-text);
  font-weight:600;
}
.notif-trigger.active svg{ opacity:1 }
/* 24px box jako avatar v user-trigger → label začíná na stejném x jako jméno. */
.notif-ico{
  position:relative;
  width:24px; height:24px;
  display:grid; place-items:center;
  flex-shrink:0;
  color:inherit;
}
.notif-ico svg{ width:18px; height:18px; opacity:.85 }   /* jako nav ikony */
.notif-trigger.active .notif-ico svg{ opacity:1 }
.notif-label{
  flex:1;
  font-size:var(--font-md);
  font-weight:500;
  color:inherit;   /* dědí z .notif-trigger (muted) → stejné jako nav položky */
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
/* Indikátor nepřečtených = malá červená tečka v pravém horním rohu zvonku. */
.notif-dot{
  position:absolute;
  top:-1px; right:1px;
  width:8px; height:8px;
  border-radius:50%;
  background:var(--danger);
  border:2px solid var(--sidebar-bg);
  box-sizing:content-box;
}
.notif-dot[hidden]{ display:none }

/* Panel popover — otevírá se nahoru. Zvoneček je u pravého kraje sidebaru,
   panel kotvíme levým krajem zvonku a roztáhneme doprava (přesah do mainu). */
.notif-pop{
  position:absolute;
  bottom:calc(100% + 8px);
  left:0; right:auto;
  width:340px;
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius);
  box-shadow:var(--shadow-pop);
  padding:var(--space-4);
  display:none;
  flex-direction:column;
  z-index:30;
}
.notif-menu.open .notif-pop{ display:flex }

.notif-head{
  display:flex; align-items:baseline; justify-content:space-between;
  gap:var(--space-12);
  padding:var(--space-10) var(--space-10) var(--space-8);
}
.notif-title{ font-size:var(--font-md); font-weight:600; color:var(--text) }
/* Sekundární akce — link (brand barva), aby bylo vidět, že je to aktivní prvek */
.notif-readall{
  flex-shrink:0;
  white-space:nowrap;
  background:transparent; border:0; padding:0;
  font-size:var(--font-sm); color:var(--brand);
  font-weight:500; cursor:pointer;
}
.notif-readall:hover{ text-decoration:underline }

/* Seznam: oddělený od hlavičky/patičky tenkými linkami; gap ať položky
   nesplývají dohromady */
.notif-list{
  display:flex; flex-direction:column;
  gap:var(--space-2);
  border-top:1px solid var(--divider);
  border-bottom:1px solid var(--divider);
  padding:var(--space-4) 0;
  margin:0 var(--space-2);
}

/* Jedna notifikace: barevná tečka kategorie + text + čas */
.notif-item{
  display:flex; gap:var(--space-10);
  padding:var(--space-8) var(--space-8);
  border-radius:var(--radius-sm);
  text-decoration:none;
  transition:background .12s ease;
}
.notif-item:hover{ background:var(--surface-hover) }
.notif-item-dot{
  width:7px; height:7px; border-radius:50%;
  margin-top:5px; flex-shrink:0;
  background:var(--border-strong);
}
/* Tečky kategorií přes semantické --cat-*-dot tokeny (živý mid-tone;
   viz definice v :root — laděno zvlášť od -fg, který je pro text). */
.notif-item-dot.cat-identity{ background:var(--cat-identity-dot) }
.notif-item-dot.cat-transport{ background:var(--cat-transport-dot) }
.notif-item-dot.cat-assets{ background:var(--cat-assets-dot) }
.notif-item-body{ display:flex; flex-direction:column; gap:var(--space-2); min-width:0 }
.notif-item-text{
  /* stejné písmo jako texty v user-menu popoveru (--font-md) */
  font-size:var(--font-md); color:var(--text); line-height:1.45;
}
.notif-item-text strong{ font-weight:600 }
.notif-item-time{ font-size:var(--font-xs); color:var(--text-faint) }
/* Nepřečtené: jemné modré pozadí; přečtené mají vybledlou tečku */
.notif-item.is-unread{ background:var(--brand-soft) }
.notif-item.is-unread:hover{ background:var(--surface-hover) }
.notif-item:not(.is-unread) .notif-item-dot{ opacity:.4 }
.notif-item:not(.is-unread) .notif-item-text{ color:var(--text-muted) }

.notif-all{
  display:block; text-align:center;
  padding:var(--space-10) var(--space-8) var(--space-6);
  font-size:var(--font-md); color:var(--brand); font-weight:500;
  text-decoration:none; border-radius:var(--radius-sm);
}
.notif-all:hover{ text-decoration:underline }

/* Collapsed sidebar: notif řádek → vycentrovaná 36×36 ikona (jako nav ikony +
   user trigger), text schovaný, červená tečka na zvonku zůstává. */
.shell.sidebar-collapsed .notif-trigger{
  width:36px; height:36px; padding:0; gap:0; justify-content:center;
}
.shell.sidebar-collapsed .notif-label{ display:none }
.shell.sidebar-collapsed .notif-pop{ left:0; right:auto; width:320px }

/* ── Stránka „Všechny notifikace" (feed) ───────────────────────────────
   Plnohodnotný seznam notifikací seskupený podle času. Sdílí tečky
   kategorií + nepřečtené zvýraznění s popoverem, ale v plné šířce. */
.notif-page{ max-width:760px }
.notif-page-toolbar{
  display:flex; align-items:center; gap:var(--space-12);
  margin-bottom:var(--space-16);
}
.notif-filters{ display:flex; gap:var(--space-6); flex:1; flex-wrap:wrap }
.notif-filter{
  padding:var(--space-6) var(--space-12);
  border:1px solid var(--border);
  border-radius:var(--radius-pill);
  background:var(--surface);
  font-size:var(--font-sm); color:var(--text-muted);
  font-weight:500; cursor:pointer;
  transition:.12s ease;
}
.notif-filter:hover{ border-color:var(--border-strong); color:var(--text) }
.notif-filter.is-active{
  background:var(--brand-soft); border-color:var(--brand);
  color:var(--brand);
}
.notif-filter .nf-badge{
  margin-left:var(--space-6); font-weight:700;
  opacity:.7;
}

.notif-group-label{
  font-size:var(--font-xs); font-weight:600;
  text-transform:uppercase; letter-spacing:.04em;
  color:var(--text-faint);
  margin:var(--space-20) 0 var(--space-8);
}
.notif-group-label:first-child{ margin-top:0 }

/* Karta feedu — položky jako řádky s dělicí linkou */
.notif-feed{
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius);
  overflow:hidden;
}
/* Filtr nastavuje [hidden]; flex/blok display jinak přebije UA [hidden] rule. */
.notif-feed[hidden],
.notif-feed-item[hidden],
.notif-group-label[hidden]{ display:none !important; }
.notif-feed-item{
  display:flex; gap:var(--space-14); align-items:flex-start;
  padding:var(--space-14) var(--space-16);
  border-bottom:1px solid var(--divider);
  text-decoration:none;
  transition:background .12s ease;
}
.notif-feed-item:last-child{ border-bottom:0 }
.notif-feed-item:hover{ background:var(--surface-hover) }
.notif-feed-item.is-unread{ background:var(--brand-soft) }
.notif-feed-item.is-unread:hover{ background:var(--surface-hover) }
/* Barevná tečka kategorie (stejná logika jako v popoveru) */
.notif-feed-item .notif-item-dot{ width:9px; height:9px; margin-top:6px }
.notif-feed-body{ flex:1; min-width:0; display:flex; flex-direction:column; gap:var(--space-2) }
.notif-feed-text{ font-size:var(--font-md); color:var(--text); line-height:1.45 }
.notif-feed-text strong{ font-weight:600 }
.notif-feed-meta{
  display:flex; align-items:center; gap:var(--space-8);
  font-size:var(--font-sm); color:var(--text-faint);
}
.notif-feed-cat{
  font-weight:600;
}
.notif-feed-cat.cat-identity{ color:var(--cat-identity-fg) }
.notif-feed-cat.cat-transport{ color:var(--cat-transport-fg) }
.notif-feed-cat.cat-assets{ color:var(--cat-assets-fg) }
.notif-feed-time::before{ content:"·"; margin-right:var(--space-8); color:var(--text-faint) }
.notif-feed-item:not(.is-unread) .notif-item-dot{ opacity:.4 }
.notif-feed-item:not(.is-unread) .notif-feed-text{ color:var(--text-muted) }
/* Modrá „nepřečteno" tečka vpravo */
.notif-unread-mark{
  width:8px; height:8px; border-radius:50%;
  background:var(--brand); flex-shrink:0; margin-top:6px;
}
.notif-feed-item:not(.is-unread) .notif-unread-mark{ visibility:hidden }

/* Dark-mode toggle row: label (icon swaps moon/sun) + a pill switch */
.user-menu-themetoggle{ justify-content:space-between !important }
.user-menu-themetoggle .tt-label{ display:flex; align-items:center; gap:var(--space-10) }
.user-menu-themetoggle .tt-ic-sun{ display:none }
html[data-theme="dark"] .user-menu-themetoggle .tt-ic-moon{ display:none }
html[data-theme="dark"] .user-menu-themetoggle .tt-ic-sun{ display:inline }
.tt-switch{
  position:relative;
  width:34px; height:20px;
  border-radius:var(--radius-pill);
  background:var(--border-strong);
  flex-shrink:0;
  transition:background .18s ease;
}
.tt-switch::after{
  content:"";
  position:absolute;
  top:2px; left:2px;
  width:16px; height:16px;
  border-radius:50%;
  background:var(--on-accent);
  box-shadow:var(--shadow-knob);
  transition:transform .18s ease;
}
html[data-theme="dark"] .tt-switch{ background:var(--brand) }
html[data-theme="dark"] .tt-switch::after{ transform:translateX(14px) }

/* Collapsed sidebar — icon-only mode */
/* In collapsed mode each element centers within the 64px panel. The
   panel has a 1px border so the inner width is 62px — pick paddings so
   2*pad + 36px element = 62 → 13px sides. The logo, nav-items and the
   user pill end up at the same x-position (left:26) in collapsed; in
   expanded they sit at left:25. That 1px delta is below the threshold
   of perception, so no visible jump. */
.shell.sidebar-collapsed .sidebar-head{ padding:var(--space-14) var(--space-12); align-items:center }
.shell.sidebar-collapsed .sidebar-head .brand{ gap:0 }
/* Section headings, dividers and the green "real page" dot are all hidden
   in icon-only mode — there's no room for the dot next to a 36×36 square and
   it just adds visual noise. The text labels (brand-text / user name /
   chevron / nav-item span) are NOT hidden here — they're animated via the
   opacity + max-width transitions in the collapse-animation block below
   (display:none would kill the fade). */
.shell.sidebar-collapsed .sidebar .nav-section,
.shell.sidebar-collapsed .sidebar .nav-divider,
.shell.sidebar-collapsed .sidebar a.nav-item[data-real]::after{ display:none }
/* In collapsed mode the 64px panel collapses every interactive element
   to a 36×36 square, centered horizontally. The var(--space-12) side padding (62px
   inner − 36px element) keeps the squares on the same x-position as the
   logo above. */
.shell.sidebar-collapsed .sidebar-body{ padding:var(--space-8) var(--space-12) }
.shell.sidebar-collapsed .sidebar .nav-item{
  width:36px; height:36px;
  flex:none;           /* nesmršťovat na malé výšce → místo mačkání scrolluje .sidebar-body */
  padding:0;
  gap:0;
  justify-content:center;
  position:relative;   /* kotva pro badge tečku ve sbaleném stavu */
}
/* Sbalené: skupina s aktivním dítětem (.open) má skryté děti, takže by
   vypadala neaktivně. Dej hlavičce skupiny STEJNÝ aktivní vizuál jako běžné
   aktivní položce, ať je vidět, že aktivní stránka je uvnitř. */
.shell.sidebar-collapsed .sidebar .nav-group.open > .nav-item{
  background:var(--sidebar-active-bg);
  color:var(--sidebar-active-text);
}
/* Sbalené menu: label i číslo badge se schová (viz .nav-item span rule), ale
   počet Todo je důležitý signál → zobraz ho jako malou tečku v rohu ikony,
   podobně jako status tečky modulů. Číslo skryjeme, ponecháme jen bod. */
.shell.sidebar-collapsed .sidebar .nav-item .nav-badge{
  display:block;
  position:absolute;
  top:3px; right:3px;
  min-width:0; width:8px; height:8px;
  padding:0;
  border-radius:50%;
  font-size:0;                 /* skryj číslici, zbude jen kolečko */
  line-height:0;
  background:var(--brand);
  color:transparent;
  box-shadow:0 0 0 2px var(--sidebar-bg);   /* odsazení od ikony */
}
.shell.sidebar-collapsed .sidebar-foot{ padding:var(--space-10) var(--space-12) var(--space-14) }
.shell.sidebar-collapsed .user-menu-trigger{
  width:36px; height:36px;
  padding:0;
  gap:0;
  justify-content:center;
}

/* -------------------------------------------------------------------------
   Sidebar collapse — CSS transitions (works in every browser, Firefox too)
   -----------------------------------------------------------------------
   Two things animate, in a deliberately staggered order so the panel never
   shows squashed text:

   - The grid column / panel width: 240px ↔ 64px over ~220ms.
   - The labels (brand text, nav-item text, user name + chevron): fade +
     collapse their width.

   Stagger via transition-delay:
   - Collapsing  → labels fade out FAST (~110ms), THEN the panel narrows.
   - Expanding   → the panel widens FIRST, THEN labels fade back in.
   This keeps the text inside the panel at all times, so nothing clips or
   reflows mid-animation. Icons never move horizontally — only the panel
   edge slides past them.
   -----------------------------------------------------------------------*/
:root{
  --sb-ease:cubic-bezier(.4,0,.2,1);
  --sb-dur:.22s;       /* panel width */
  --sb-label-dur:.11s; /* label fade  */
}

/* Panel width: animate the grid track + the sidebar's own box. */
.shell{
  transition:grid-template-columns var(--sb-dur) var(--sb-ease);
}

/* --- Labels: animatable replacement for the old display:none rules ---
   Collapsed = opacity 0 + width 0 (so they don't reserve space and the
   icons can center). Expanded reverses it. */
.sidebar-head .brand-text,
.user-menu-trigger .name,
.user-menu-trigger .chev,
.sidebar .nav-item span:not(.avatar){
  /* Expanding: panel widens (delay), then labels appear. */
  transition:opacity var(--sb-label-dur) var(--sb-ease) var(--sb-dur),
             max-width var(--sb-label-dur) var(--sb-ease) var(--sb-dur);
  opacity:1;
  max-width:200px;
  overflow:hidden;
  white-space:nowrap;
}
.shell.sidebar-collapsed .sidebar-head .brand-text,
.shell.sidebar-collapsed .user-menu-trigger .name,
.shell.sidebar-collapsed .user-menu-trigger .chev,
.shell.sidebar-collapsed .sidebar .nav-item span:not(.avatar):not(.nav-badge){
  /* Collapsing: labels fade out immediately, before the panel narrows.
     .nav-badge je výjimka — ve sbaleném zůstává jako tečka (viz pravidlo výše). */
  transition:opacity var(--sb-label-dur) var(--sb-ease),
             max-width var(--sb-label-dur) var(--sb-ease);
  opacity:0;
  max-width:0;
}

/* Nav items + user pill: animate width / padding / gap so the icon-to-label
   spacing collapses smoothly together with the label fade (no gap snap). */
.sidebar .nav-item{
  transition:background .16s ease, color .16s ease,
             width var(--sb-dur) var(--sb-ease),
             gap var(--sb-dur) var(--sb-ease),
             padding var(--sb-dur) var(--sb-ease);
}
.user-menu-trigger{
  transition:background .15s ease,
             width var(--sb-dur) var(--sb-ease),
             gap var(--sb-dur) var(--sb-ease),
             padding var(--sb-dur) var(--sb-ease);
}

/* First-paint guard: applySidebarState() adds this for one frame so the
   persisted state lands without animating from the default open width. */
.shell.no-sidebar-anim,
.shell.no-sidebar-anim *{
  transition:none !important;
}

/* Respect motion-reduction preferences — snap, don't animate. */
@media (prefers-reduced-motion: reduce){
  .shell,
  .shell .sidebar-head .brand-text,
  .shell .user-menu-trigger .name,
  .shell .user-menu-trigger .chev,
  .shell .sidebar .nav-item span:not(.avatar),
  .shell .sidebar .nav-item,
  .shell .user-menu-trigger{
    transition:none !important;
  }
}
/* In collapsed mode the user menu pops out to the right of the sidebar
   instead of stretching across its (tiny) width. */
.shell.sidebar-collapsed .user-menu-pop{
  left:calc(100% + 8px);
  right:auto;
  bottom:0;
  width:200px;
}

/* -------------------------------------------------------------------------
   Collapsed-sidebar tooltips
   -----------------------------------------------------------------------
   When the panel is icon-only, each nav item shows its label as a tooltip.

   IMPORTANT: this is a SINGLE position:fixed node appended to <body> by
   sidebar.js (initTooltips), NOT a ::after on each nav-item. A pseudo-
   element lives inside the sidebar's stacking context, where page content
   in main (the .toolbar band in particular) painted over the part of the
   tooltip that escapes past the panel edge — that's why it clipped on the
   Identity pages (item sits at toolbar height) but looked fine on
   warehouse (item sat at table height). A fixed body node is outside every
   stacking/overflow context on the page, so it always paints on top.
   sidebar.js positions it (left/top) and toggles .visible on hover/focus.
   -----------------------------------------------------------------------*/
.sidebar-tooltip{
  position:fixed;
  z-index:300;               /* above page content AND overlays' backdrops */
  transform:translateY(-50%) translateX(-4px);
  white-space:nowrap;
  background:var(--tooltip-bg);
  color:var(--tooltip-fg);
  font-size:var(--font-sm);
  font-weight:500;
  line-height:1;
  padding:var(--space-8) var(--space-10);
  border-radius:var(--radius-sm);
  box-shadow:var(--shadow-tooltip);
  pointer-events:none;
  opacity:0;
  transition:opacity .12s ease, transform .12s ease;
}
.sidebar-tooltip.visible{
  opacity:1;
  transform:translateY(-50%) translateX(0);
}
/* Arrow pointing back at the icon. */
.sidebar-tooltip::before{
  content:"";
  position:absolute;
  right:100%;
  top:50%;
  transform:translateY(-50%);
  border:5px solid transparent;
  border-right-color:var(--tooltip-bg);
}

/* -------------------------------------------------------------------------
   Flyout skupiny (sidebar.js initGroupFlyouts) — děti accordion skupiny
   (např. Evidence obalů) ve SBALENÉM sidebaru, kde se accordion nevejde.
   Panel vedle ikony, klikací odkazy. Fixed body node (mimo overflow sidebaru).
   ------------------------------------------------------------------------- */
.sidebar-flyout{
  position:fixed;
  z-index:300;
  min-width:180px;
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  box-shadow:var(--shadow-pop);
  padding:var(--space-6);
  opacity:0;
  transform:translateX(-4px);
  pointer-events:none;
  transition:opacity .12s ease, transform .12s ease;
}
.sidebar-flyout.visible{ opacity:1; transform:translateX(0); pointer-events:auto; }
.sidebar-flyout-title{
  font-size:var(--font-xs);
  font-weight:700;
  color:var(--text-faint);
  letter-spacing:.06em;
  text-transform:uppercase;
  padding:var(--space-6) var(--space-8) var(--space-4);
}
/* Odkazy uvnitř flyoutu = plné řádky s labelem (ne icon-only jako v sidebaru). */
.sidebar-flyout .nav-item{
  display:flex; align-items:center; gap:var(--space-10);
  width:auto; height:auto;
  padding:var(--space-8) var(--space-10);
  border-radius:var(--radius-sm);
  color:var(--text); text-decoration:none;
  font-size:var(--font-sm); white-space:nowrap;
}
.sidebar-flyout .nav-item span{ display:inline; }              /* label zpět (v sidebaru je skrytý) */
.sidebar-flyout .nav-item svg{ flex:0 0 18px; width:18px; height:18px; opacity:.8; }
.sidebar-flyout .nav-item:hover{ background:var(--surface-hover); }
.sidebar-flyout .nav-item.active{ background:var(--surface-active); color:var(--brand); font-weight:600; }

/* -------------------------------------------------------------------------
   Obecný UI tooltip (tooltip.js) — stejný vzhled jako sidebar tooltip, ale
   zobrazuje se NAD prvkem (šipka dolů). Pro libovolný prvek s data-tip,
   typicky ikonové akce v posledním sloupci tabulky. Jeden position:fixed
   node na <body>, mimo overflow kontexty, takže se nikdy neořízne.
   ------------------------------------------------------------------------- */
.ui-tooltip{
  position:fixed;
  z-index:300;
  transform:translate(-50%, calc(-100% - 8px)) translateY(4px);
  white-space:nowrap;
  background:var(--tooltip-bg);
  color:var(--tooltip-fg);
  font-size:var(--font-sm);
  font-weight:500;
  line-height:1;
  padding:var(--space-8) var(--space-10);
  border-radius:var(--radius-sm);
  box-shadow:var(--shadow-tooltip);
  pointer-events:none;
  opacity:0;
  transition:opacity .12s ease, transform .12s ease;
}
.ui-tooltip.visible{
  opacity:1;
  transform:translate(-50%, calc(-100% - 8px)) translateY(0);
}
/* Šipka mířící dolů na prvek. */
.ui-tooltip::after{
  content:"";
  position:absolute;
  top:100%;
  left:50%;
  transform:translateX(-50%);
  border:5px solid transparent;
  border-top-color:var(--tooltip-bg);
}


/* -------------------------------------------------------------------------
   Main content area
   ------------------------------------------------------------------------- */
.main{
  grid-area:main;
  overflow:hidden;
  display:flex;
  flex-direction:column;
  min-height:0;
}
.page{
  display:flex;
  flex-direction:column;
  flex:1;
  min-height:0;
  overflow:hidden;
}

.page-header{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  padding:var(--space-20) 28px var(--space-16);
  gap:var(--space-24);
  background:var(--surface);
}
.page-header .crumbs{
  display:flex;
  align-items:center;
  gap:var(--space-6);
  font-size:var(--font-sm);
  color:var(--text-muted);
  margin-bottom:var(--space-6);
}
/* Dvě úrovně: klikací články = odkaz (brandová modrá), neklikací <span>
   (modul i aktuální stránka) zůstávají muted. Uživatel na první pohled
   pozná, kam se dá kliknout. */
.page-header .crumbs a{ color:var(--brand); border-radius:var(--radius-sm); }
.page-header .crumbs a:hover{ color:var(--brand-dark); text-decoration:underline; }
.page-header .crumbs a:focus-visible{ outline:2px solid var(--brand-ring-strong); outline-offset:2px; }
.page-header h1{
  font-size:var(--font-2xl);
  font-weight:700;
  letter-spacing:-.01em;
  color:var(--text);
  display:flex;
  align-items:center;
  gap:var(--space-12);
}
.page-header h1 .count{
  font-size:var(--font-md);
  font-weight:500;
  color:var(--text-faint);
}
.page-header .page-actions{
  display:flex;
  gap:var(--space-8);
  align-items:center;
  flex-shrink:0;
}

.page-body{
  flex:1;
  min-height:0;
  padding:var(--space-8) 28px var(--space-16);
  display:flex;
  flex-direction:column;
  /* Default: the body itself scrolls vertically (detail pages with free
     content). List pages override this via .page-body > .table-shell —
     that inner shell takes over the scroll, so the page-header / toolbar
     / pagination above and below it stay fixed. */
  overflow-y:auto;
}
/* Spacing between the optional toolbar/bulk-bar and the table — but NOT
   between the table and its pagination footer (those share a card). */
/* A card placed directly in the (flex-column) page body must not be squashed
   by flex — keep its natural height. */
/* A card or toolbar directly in the (flex-column) page body keeps its natural
   height — it must not be stretched by flex. */
.page-body > .card,
.page-body > .toolbar{ flex-shrink:0 }
/* Inside a list page, the table-shell grows to fill remaining space and
   scrolls internally; toolbar + pagination stay put. */
.page-body > .table-shell{
  flex:1;
  min-height:0;
  overflow:auto;
}


/* -------------------------------------------------------------------------
   Buttons
   ------------------------------------------------------------------------- */
.btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:var(--space-8);
  padding:var(--space-8) var(--space-14);
  border-radius:var(--radius-sm);
  font-size:var(--font-md);
  font-weight:600;
  letter-spacing:.005em;
  border:1px solid transparent;
  transition:.16s ease;
  white-space:nowrap;
}
.btn svg{ width:16px; height:16px; flex-shrink:0 }
.btn-primary{
  background:var(--btn-primary-bg);
  color:var(--btn-primary-fg);
  box-shadow:var(--shadow-sm);
}
.btn-primary:hover{ background:var(--btn-primary-bg-hover) }
.btn-secondary{
  background:var(--btn-secondary-bg);
  border-color:var(--btn-secondary-border);
  color:var(--btn-secondary-fg);
}
.btn-secondary:hover{
  background:var(--btn-secondary-bg-hover);
  border-color:var(--btn-secondary-border-hover);
}
/* Sekundární tlačítko s destruktivním významem (text „Smazat vše") — stejný
   tvar jako .btn-secondary, jen červený text; na hover jemné červené pozadí. */
.btn-secondary.btn-danger-text{ color:var(--btn-danger-fg); }
.btn-secondary.btn-danger-text:hover{ background:var(--danger-soft); border-color:var(--btn-danger-fg); color:var(--btn-danger-fg-hover); }
.btn-ghost{
  background:transparent;
  color:var(--btn-ghost-fg);
}
.btn-ghost:hover{
  background:var(--btn-ghost-bg-hover);
  color:var(--btn-ghost-fg-hover);
}
.btn-danger{
  background:var(--surface);
  color:var(--btn-danger-fg);
  border-color:var(--danger-soft);
}
.btn-danger:hover{
  background:var(--danger-soft);
  border-color:var(--btn-danger-fg-hover);
  color:var(--btn-danger-fg-hover);
}
/* Consistent keyboard focus ring, coloured per variant (so an auto-focused
   modal button matches its variant instead of the browser's default blue). */
.btn:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring-strong) }
.btn-danger:focus-visible{ box-shadow:0 0 0 3px var(--danger-ring) }
.btn-icon{
  width:32px;
  height:32px;
  padding:0;
  display:grid;             /* centre the icon — 32×32 box, 16px icon = even inset */
  place-items:center;
  border-radius:var(--radius-sm);
  background:transparent;
  border:0;
  color:var(--text-muted);
  cursor:pointer;
}
.btn-icon svg{ width:16px; height:16px }
.btn-icon:hover{ background:var(--surface-hover); color:var(--text) }
.btn-icon:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring-strong) }
.btn[disabled],
.btn[aria-disabled="true"]{
  opacity:.45;
  cursor:not-allowed;
  pointer-events:none;
}


/* -------------------------------------------------------------------------
   Search — one component, variants via modifiers (maps 1:1 to a future
   Angular <nf-search [variant] [size] [block]>).

   Base:    .search           = wrapper with a leading magnifier + <input>.
   Border:  default has a border; .search--seamless drops it (launcher look).
   Size:    .search--sm (compact, e.g. column-filter popover)
            default (.font-md, table toolbars / panels / pickers)
            .search--lg (.font-lg, launcher overlay)
   Width:   .search--block fills its container (and grows in a flex parent).

   Layout is a FLEX ROW, not an absolutely-positioned icon over a padded input.
   The border / background / radius live on the WRAPPER, so the magnifier sits
   inside the bordered box as a real flex child; a single `gap` controls the
   icon↔text distance and `padding` the inset. This keeps the icon and text
   from drifting apart (the old absolute icon + input padding-left set the two
   independently and easily disagreed). The input itself is borderless and
   transparent, just grows to fill. Focus ring is on the wrapper via
   :focus-within. Per size we only scale the padding, gap and glyph — never a
   separate icon offset. An optional trailing .kbd chip is just the last child.
   ------------------------------------------------------------------------- */
.search{
  display:flex;
  align-items:center;
  gap:var(--space-8);
  padding:0 var(--space-12);
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface);
  color:var(--text-faint);                 /* the magnifier inherits this */
}
.search > svg{ flex:none; }
.search input{
  flex:1;
  min-width:0;                              /* let the input shrink in flex */
  padding:var(--space-8) 0;
  border:0;
  background:transparent;
  color:var(--text);
  font-size:var(--font-md);
}
.search input::placeholder{ color:var(--text-faint); }
.search input:focus,
.search input:focus-visible{ outline:none; }
/* When a .search sits inside a .form-field (e.g. the multiselect panel lives in
   a Lokace field), the generic `.form-field input:not([type=checkbox])…` rules
   would re-add a border, focus ring and select-arrow background to the input —
   drawing a SECOND ring inside the wrapper's own :focus-within ring. The wrapper
   owns the chrome, so strip the field styling from the inner input. We MUST
   match the field rule's specificity (it uses two :not() pseudo-classes), hence
   the same :not() chain here. */
.form-field .search input:not([type=checkbox]):not([type=radio]){
  border:0; background:transparent; padding:var(--space-8) 0;
}
.form-field .search input:not([type=checkbox]):not([type=radio]):focus,
.form-field .search input:not([type=checkbox]):not([type=radio]):focus-visible{
  border-color:transparent; box-shadow:none;
}
.search:focus-within{
  border-color:var(--brand);
  box-shadow:0 0 0 3px var(--brand-ring);
}

/* Size: compact (column-filter popover) */
.search--sm{ gap:var(--space-6); padding:0 var(--space-8); }
.search--sm input{ padding:var(--space-4) 0; font-size:var(--font-sm); }
.search--sm > svg{ width:14px; height:14px; }

/* Size: large (launcher) */
.search--lg{ gap:var(--space-12); padding:0 var(--space-16); }
.search--lg input{ padding:var(--space-14) 0; font-size:var(--font-lg); }

/* Border: seamless (launcher) — no border/background; ring rounds itself. */
.search--seamless{ border:0; background:transparent; }

/* Toolbar search: pevná výška 32px, ať lícuje s tool tlačítky a „Pohledy"
   (bez tohoto ho padding inputu roztáhl na ~35px = nekonzistence). */
.toolbar .search{ height:32px; }
.toolbar .search input{ padding:0; }
.search--seamless:focus-within{ box-shadow:0 0 0 3px var(--brand-ring); }

/* Width: fill the container (panels, pickers) and grow in a flex parent.
   A flex .search is block-level, so it already takes the full content width
   AND respects its own horizontal margins — no hard width:100% (that ignores
   margins and overflowed the margin-inset type-picker). flex:1 makes it grow
   when the parent IS a flex row. */
.search--block{ flex:1; }

/* Optional trailing keyboard hint (launcher's "ESC"/"⌘K" chip) — last child. */
.search .kbd{
  flex:none;
  display:inline-flex;
  align-items:center;
  gap:var(--space-4);
}

/* -------------------------------------------------------------------------
   Toolbar (above tables)
   ------------------------------------------------------------------------- */
.toolbar{
  display:flex;
  align-items:center;
  gap:var(--space-10);
  padding:var(--space-14) var(--space-16);
  background:var(--sidebar-bg);
  border:1px solid var(--sidebar-border);
  border-radius:var(--radius);
  margin-bottom:var(--space-16);
}
/* Toolbar search: the shared .search base + toolbar-only layout (flex-grows,
   capped width). Inherits the icon/focus/border styling from .search above;
   only the flex sizing lives here. */
.toolbar .search{
  flex:1;
  max-width:260px;   /* search je sekundární (hlavní filtrování = chipy/pohledy) */
}

/* ===== Sbalitelný search — sbalí se, když je aktivní filtr =====
   Search je sekundární (hlavní filtrování = Filtry/chipy). Dokud nefiltruju,
   je plný. Jakmile přidám filtr (.toolbar.has-filters — nastavuje list.js),
   chipy potřebují místo → search se sbalí do ikony lupy (32px). Rozbalí se zpět
   při fokusu/kliku NEBO když do něj něco napíšu (.has-query). */
.toolbar.has-filters .search:not(:focus-within):not(.has-query){
  flex:0 0 32px; max-width:32px; padding:0; gap:0; justify-content:center; cursor:text;
}
.toolbar.has-filters .search:not(:focus-within):not(.has-query) > input{
  flex:0 0 0; width:0; min-width:0; padding:0; opacity:0; pointer-events:none;
}
.toolbar.has-filters .search:focus-within,
.toolbar.has-filters .search.has-query{
  flex:0 1 260px; max-width:320px;
}
.toolbar .search{ transition:flex-basis .18s ease, max-width .18s ease; }
.toolbar .filter-chips{
  display:flex;
  gap:var(--space-6);
}
.toolbar .filter-chips .chip{
  display:inline-flex;
  align-items:center;
  gap:var(--space-6);
  padding:var(--space-6) var(--space-12);
  border-radius:var(--radius-pill);
  background:var(--surface-alt);
  border:1px solid var(--border);
  font-size:var(--font-sm);
  font-weight:500;
  color:var(--text-muted);
  cursor:pointer;
  transition:.16s ease;
}
.toolbar .filter-chips .chip:hover{
  background:var(--surface-hover);
  color:var(--text);
}
.toolbar .filter-chips .chip.active{
  background:var(--brand-soft);
  color:var(--brand-dark);
  border-color:var(--brand-ring-strong);
}
.toolbar .filter-chips .chip .num{
  background:rgba(59,130,246,.18);
  color:var(--brand-dark);
  padding:1px var(--space-6);
  border-radius:var(--radius-pill);
  font-size:var(--font-xs);
  font-weight:700;
}
.toolbar .chip.active .num{
  background:var(--brand);
  color:var(--on-accent);
}
.toolbar .spacer{ flex:1 }


/* Bulk-action bar (replaces toolbar when rows are selected) */
/* Bulk action bar — floats at the bottom of the screen (same card language as
   the save footer) when rows are selected. Inset from the edges, rounded,
   bordered, shadow; left edge lines up with the content (past the sidebar). */
.bulk-bar{
  position:fixed;
  bottom:var(--floatbar-inset);
  /* Align symmetrically to the content area: left = shell pad + sidebar + gap,
     right = shell pad — both then plus the float inset. (right was missing the
     12px shell pad, pushing the bar visually rightwards.) */
  left:calc(var(--space-12) + var(--sidebar-w) + var(--space-12) + var(--floatbar-inset));
  right:calc(12px + var(--floatbar-inset));
  z-index:10;
  display:flex;
  align-items:center;
  gap:var(--space-10);
  padding:var(--space-12);   /* symmetric all round */
  /* Dark bar (snackbar/toast language) so a selection is impossible to miss. */
  background:var(--toast-bg);
  border:1px solid var(--toast-border);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-pop);
  color:var(--toast-fg);
  font-size:var(--font-sm);
  font-weight:500;
}
/* Track the collapsed sidebar (64px). The bar lives inside .shell, so target it
   as a descendant (the footer is a sibling, hence its different selector). */
.shell.sidebar-collapsed .bulk-bar{
  left:calc(12px + 64px + 12px + var(--floatbar-inset));
}
/* When the detail drawer is open, stop the bulk-bar before it so it isn't hidden
   underneath (the panel has a higher z-index). body.detail-open is toggled by
   openDetail/closeDetail. Panel = --detail-drawer-w + insets. */
body.detail-open .bulk-bar{
  right:calc(12px + var(--detail-drawer-w) + 12px + var(--floatbar-inset));
}
.bulk-bar strong{ font-weight:700 }
.bulk-bar .spacer{ flex:1 }
.bulk-bar .num{ color:var(--toast-fg) }
/* "× N vybráno" as one subtle ghost button that clears the selection.
   Sized like the action buttons on the right (.btn): same padding, font, weight. */
.bulk-bar .bulk-clear{
  flex-shrink:0;
  display:inline-flex; align-items:center; gap:var(--space-8);
  padding:var(--space-8) var(--space-12);
  border-radius:var(--radius-sm);
  color:var(--toast-fg);
  background:transparent;
  cursor:pointer;
  font-size:var(--font-md);
  font-weight:600;
}
.bulk-bar .bulk-clear svg{ color:var(--toast-subtle); flex-shrink:0 }
.bulk-bar .bulk-clear:hover{ background:var(--toast-hover) }
.bulk-bar .bulk-clear:hover svg{ color:var(--toast-fg) }
.bulk-bar .bulk-clear:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--toast-hover) }
.bulk-bar .bulk-clear strong{ font-weight:700 }
/* Buttons = modal buttons from the opposite theme (the bar surface is inverted).
   Same shape as the modal's .btn-secondary / .btn-danger, on --barbtn-* tokens. */
.bulk-bar .btn-secondary{
  background:var(--barbtn-bg);
  border-color:var(--barbtn-border);
  color:var(--barbtn-fg);
}
.bulk-bar .btn-secondary:hover{ background:var(--barbtn-hover); border-color:var(--barbtn-hover-border) }
.bulk-bar .btn-danger{
  background:var(--barbtn-bg);
  border-color:var(--barbtn-danger-border);
  color:var(--barbtn-danger-fg);
}
.bulk-bar .btn-danger:hover{ background:var(--barbtn-danger-hover-bg); border-color:var(--barbtn-danger-hover); color:var(--barbtn-danger-hover) }
/* Focus rings tuned for the bar's inverted surface (the theme rings vanish here). */
.bulk-bar .btn-secondary:focus-visible{ box-shadow:0 0 0 3px var(--barbtn-ring) }
.bulk-bar .btn-danger:focus-visible{ box-shadow:0 0 0 3px var(--barbtn-danger-ring) }


/* -------------------------------------------------------------------------
   Data table
   ------------------------------------------------------------------------- */
.table-shell{
  background:var(--surface);
  border:1px solid var(--border);
  /* Round only the top corners — the pagination box below rounds the bottom. */
  border-radius:var(--radius) var(--radius) 0 0;
  overflow:auto;
}
/* Tlumený popisek nad tabulkou (např. „Přeneste hlavičku sloupce zde pro
   sloučení" v trasování). */
.table-hint{
  padding:var(--space-10) var(--space-16);
  font-size:var(--font-sm);
  color:var(--text-faint);
  border-bottom:1px solid var(--divider);
}
/* Odkaz v buňce tabulky bez podtržení, jen barvou (např. vazba na paletu). */
.link-plain{ color:var(--brand); text-decoration:none; }
.link-plain:hover{ text-decoration:underline; }
/* Barevný swatch (čtvereček) — sloupec Barva u úloh. Jen vzorek, bez hex textu. */
.task-swatch{
  display:inline-block;
  width:18px; height:18px;
  border-radius:var(--radius-xs);
  border:1px solid var(--border);
  vertical-align:middle;
}
/* Barevné kolečko ve sloupci/buňce (např. Barva u úloh). Funguje samostatně
   (na rozdíl od .tag-swatch, který je button v gridu). Barva z --tag-<key>-dot. */
.color-dot{
  display:inline-block;
  width:16px; height:16px;
  border-radius:50%;
  vertical-align:middle;
  background:var(--_cd, var(--tag-slate-dot));
}
/* Barevná buňka v seznamu — swatch (dot) + název barvy vedle sebe. */
.color-cell{ display:inline-flex; align-items:center; gap:var(--space-8); }
.color-dot[data-tag-color="slate"]{   --_cd:var(--tag-slate-dot) }
.color-dot[data-tag-color="red"]{     --_cd:var(--tag-red-dot) }
.color-dot[data-tag-color="orange"]{  --_cd:var(--tag-orange-dot) }
.color-dot[data-tag-color="amber"]{   --_cd:var(--tag-amber-dot) }
.color-dot[data-tag-color="lime"]{    --_cd:var(--tag-lime-dot) }
.color-dot[data-tag-color="green"]{   --_cd:var(--tag-green-dot) }
.color-dot[data-tag-color="emerald"]{ --_cd:var(--tag-emerald-dot) }
.color-dot[data-tag-color="teal"]{    --_cd:var(--tag-teal-dot) }
.color-dot[data-tag-color="cyan"]{    --_cd:var(--tag-cyan-dot) }
.color-dot[data-tag-color="sky"]{     --_cd:var(--tag-sky-dot) }
.color-dot[data-tag-color="blue"]{    --_cd:var(--tag-blue-dot) }
.color-dot[data-tag-color="indigo"]{  --_cd:var(--tag-indigo-dot) }
.color-dot[data-tag-color="violet"]{  --_cd:var(--tag-violet-dot) }
.color-dot[data-tag-color="purple"]{  --_cd:var(--tag-purple-dot) }
.color-dot[data-tag-color="fuchsia"]{ --_cd:var(--tag-fuchsia-dot) }
.color-dot[data-tag-color="pink"]{    --_cd:var(--tag-pink-dot) }
.color-dot[data-tag-color="rose"]{    --_cd:var(--tag-rose-dot) }
/* Input uvnitř buňky tabulky (editovatelná hodnota, např. atributy úlohy).
   Lehčí než plný input — vyplní buňku, rámeček jen na focus. */
.cell-input{
  width:100%;
  padding:var(--space-4) var(--space-8);
  border:1px solid transparent;
  border-radius:var(--radius-sm);
  background:transparent;
  font-size:var(--font-md);
  color:var(--text);
  transition:.14s ease;
}
.cell-input:hover{ border-color:var(--border); }
.cell-input:focus{ outline:none; border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-ring); background:var(--surface); }
/* overflow:auto ořezává rozbalený combobox (.ss-panel je position:absolute).
   Když je uvnitř tabulky OTEVŘENÝ select-search, povol overflow, ať se panel
   vejde mimo tabulku. Stejný princip jako u .modal-card. */
.table-shell:has(.select-search.open),
.table-shell:has(.select-menu-host.open){ overflow:visible; }
.table-shell:has(.select-search.open) tbody td,
.table-shell:has(.select-menu-host.open) tbody td{ overflow:visible; }
.data-table{
  width:100%;
  border-collapse:collapse;
}
/* Sloupec Název (produkty apod.) nezalamovat na dva řádky — přeteče vodorovně
   (tabulka je v .table-shell s overflow:auto). Dlouhé názvy zůstanou na řádku. */
.data-table td[data-col="nazev"]{ white-space:nowrap; }
.data-table thead th{
  text-align:left;
  padding:var(--row-pad-th-y) var(--row-pad-x);
  background:var(--surface-alt);
  border-bottom:1px solid var(--border);
  font-size:var(--font-xs);
  font-weight:700;
  color:var(--text-muted);
  position:sticky;
  top:0;
  z-index:3;
  letter-spacing:.06em;
  text-transform:uppercase;
  white-space:nowrap;
  vertical-align:middle;
}
/* Sortable/filterable header layout: text + sort + filter as flex row.
   Wrap header content in a flex container so text and icons align vertically
   regardless of baseline / uppercase / letter-spacing quirks. */
.data-table thead th[data-col]{
  vertical-align:middle;
}
.data-table thead th[data-col] > span,
.data-table thead th[data-col] > svg{
  display:inline-block;
  vertical-align:middle;
}
/* Nudge icons 1px down to match the optical centre of the uppercase text. */
.data-table thead th .filter-icon,
.data-table thead th .sort-icon{
  position:relative;
  top:1px;
}
.data-table tbody tr{
  border-bottom:1px solid var(--divider);
  transition:background .14s ease;
  cursor:pointer;
}
.data-table tbody tr:hover{
  background:var(--surface-hover);
}
.data-table tbody tr.selected{
  background:var(--surface-active);
}
/* Row whose detail is open in the side panel (master-detail). A left brand bar
   + tint marks it, distinct from the checkbox .selected state. */
.data-table tbody tr.row-active{
  background:var(--surface-active);
  box-shadow:inset 3px 0 0 var(--brand);
}
.data-table td{
  padding:var(--row-pad-td-y) var(--row-pad-x);
  font-size:var(--font-md);
  color:var(--text);
  vertical-align:middle;
}
/* Součtový řádek (tfoot) — semibold popisek + celkový rozdíl. Bez podbarvení a
   bez horní linky (poslední řádek tbody už linku má, jinak by se zdvojila).
   Použito v rozpadu po lokacích (Naskenované záznamy). Spodní rohy zaoblené,
   protože pod tabulkou v pravém panelu už nic nenavazuje. */
.data-table tfoot .row-total th,
.data-table tfoot .row-total td{
  padding:var(--space-12) var(--space-16);   /* výška jako pagination v listu */
  font-weight:600;
  font-size:var(--font-md);   /* stejné jako tělo tabulky (14px) */
  color:var(--text);
}
.data-table tfoot .row-total th{ text-align:left }
/* Číselné sloupce (Očekávaný/Skutečný/Rozdíl) zarovnané doprava — tělo i součet. */
.data-table th.num,
.data-table td.num{ text-align:right }
/* Sloupec Zóny (chip s počtem) zarovnaný doprava — hlavička i buňky. */
.data-table th[data-col="zones"],
.data-table td[data-zones]{ text-align:right }
/* Boolean sloupce se zaškrtnutím (Je pickovací / Pickování) zarovnané na střed. */
.data-table th[data-col="pick"],
.data-table td[data-col="pick"],
.data-table th[data-col="pickable"],
.data-table td[data-col="pickable"]{ text-align:center }
/* Obecné vycentrování buňky/hlavičky přes .ta-center (sloupce jako Barva u úloh,
   Pickování apod.). Hlavička se centruje taky, ať sedí pod ní obsah. */
.data-table th.ta-center,
.data-table td.ta-center{ text-align:center }
.data-table th.ta-right,
.data-table td.ta-right{ text-align:right }
/* Sloupec Produkt (Podrobné skladové zásoby) — širší, ať se název nezalamuje. */
.data-table th[data-col="nazevp"],
.data-table td[data-col="nazevp"]{ min-width:220px; }
/* Množství: manko (záporné) červeně, přebytek (kladné) zeleně. */
.data-table td.qty-neg{ color:var(--danger-fg); font-weight:600; }
.data-table td.qty-pos{ color:var(--success-fg); font-weight:600; }
/* Shell se simple-listem nemá pod sebou pagination (na rozdíl od plného listu),
   tak zaobluje VŠECHNY rohy — stejný radius jako hlavička, jen i dole. Navázáno
   na simple-list (ne na .detail rodiče), ať platí všude — v panelu i v katalogu. */
.table-shell:has(> table[data-simple-list]){ border-radius:var(--radius) }

/* ===== simple-list — odlehčená read-only mini-tabulka =================
   Menší než plný list (je to rozpad v panelu, ne hlavní tabulka): užší řádky
   přes sdílený token --row-pad-compact-* (tentýž, který používá „compact“
   density). Font těla i footeru zůstává --font-md (14px) jako u listu,
   hlavička malá (--font-xs uppercase). Odlehčení je jen ve výšce řádků. */
table[data-simple-list] thead th,
table[data-simple-list] tbody td,
table[data-simple-list] tfoot .row-total th,
table[data-simple-list] tfoot .row-total td{
  padding:var(--row-pad-compact-y) var(--row-pad-compact-x);
}
/* Read-only — řádky nejsou klikatelné: žádný hover ani pointer cursor. */
table[data-simple-list] tbody tr{ cursor:default }
table[data-simple-list] tbody tr:hover{ background:transparent }
.data-table .col-check{
  width:44px;
}
.data-table .col-actions{
  width:80px;
  text-align:center;
}
.data-table .row-actions{
  display:flex;
  gap:var(--space-2);
  justify-content:center;   /* centre the action icons under the centred "Akce" header */
  opacity:0;
  transition:opacity .14s ease;
}
.data-table tbody tr:hover .row-actions,
.data-table tbody tr.selected .row-actions,
.data-table tbody tr:focus-within .row-actions,
.data-table tbody tr.kbd-focus .row-actions{ opacity:1 }   /* akce vidět i při fokusu klávesnicí, ne jen hover */

/* Řádek fokusovaný klávesnicí (roving tabindex). Viditelný indikátor + akce. */
.data-table tbody tr.kbd-focus{ background:var(--surface-active) }
.data-table tbody tr:focus-visible{ outline:2px solid var(--brand); outline-offset:-2px }
.data-table tbody tr:focus{ outline:none }   /* jen :focus-visible kreslí prstenec */
.data-table .user-cell{
  display:flex;
  align-items:center;
  gap:var(--space-12);
}
/* Nadpis detailu s ikonou/avatarem vlevo (page-header heading slot). Dřív inline
   `display:inline-flex;gap:14px` na .user-cell, které se ale mimo .data-table
   neaplikovalo — proto vlastní třída. */
.heading-inline{ display:inline-flex; align-items:center; gap:var(--space-14); }
.data-table .user-cell .avatar{
  width:32px;
  height:32px;
  border-radius:50%;
  display:grid;
  place-items:center;
  font-weight:600;
  font-size:var(--font-sm);
  color:var(--on-accent);
  flex-shrink:0;
}
.data-table .user-cell .meta{
  display:flex;
  flex-direction:column;
}
.data-table .user-cell .meta .username{
  font-weight:400;          /* not bold — reads like the other list cells */
  font-size:var(--font-md);
}
.data-table .user-cell .meta .handle{
  font-size:var(--font-sm);
  color:var(--text-muted);
}
.data-table .email{ color:var(--text-muted) }
.data-table .text-muted{ color:var(--text-muted) }
/* Druhy dopravy: keep the name on one line (it's the bold identity column). */
.data-table .type-name{ white-space:nowrap }
/* Doprava: the Druh column (bold, with emoji) shouldn't wrap on smaller widths. */
.data-table td[data-col="type"] strong{ white-space:nowrap }

/* Cell content clamp — opt-in per column via <th data-clamp="N">.
   The runtime wraps the cell's content in <div class="clamp-N"> so the
   inner box can clamp without breaking the table layout. */
.data-table .clamp-1,
.data-table .clamp-2,
.data-table .clamp-3{
  display:-webkit-box;
  -webkit-box-orient:vertical;
  overflow:hidden;
  word-break:break-word;
}
.data-table .clamp-1{ -webkit-line-clamp:1; line-clamp:1 }
.data-table .clamp-2{ -webkit-line-clamp:2; line-clamp:2 }
.data-table .clamp-3{ -webkit-line-clamp:3; line-clamp:3 }



/* Checkbox */
.checkbox{
  appearance:none;
  -webkit-appearance:none;
  width:18px;
  height:18px;
  border:1.5px solid var(--border-strong);
  border-radius:var(--radius-xs);
  background:var(--surface);
  cursor:pointer;
  display:inline-grid;
  place-items:center;
  transition:.14s ease;
  flex-shrink:0;
  vertical-align:middle;   /* ukotvit baseline — jinak checked/indeterminate stav
                              mění výšku buňky o ~1-2px a tabulka „skáče" */
}
.checkbox:hover{ border-color:var(--brand) }
/* .checked class mirrors :checked so decorative <span class="checkbox checked">
   in the catalogue renders the filled state (spans can't match :checked). */
.checkbox:checked,
.checkbox.checked{
  background:var(--brand);
  border-color:var(--brand);
}
.checkbox:checked::after,
.checkbox.checked::after{
  content:"";
  width:10px;
  height:10px;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='white'%3E%3Cpath d='M13.485 4.515a1 1 0 0 1 0 1.414l-6.364 6.364a1 1 0 0 1-1.414 0L2.515 8.95a1 1 0 1 1 1.414-1.414l2.485 2.485 5.657-5.657a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E") center/contain no-repeat;
}
.checkbox.indeterminate,
.checkbox:indeterminate{
  background:var(--brand);
  border-color:var(--brand);
}
.checkbox.indeterminate::after,
.checkbox:indeterminate::after{
  content:"";
  width:10px;
  height:2px;
  background:var(--on-accent);
  border-radius:1px;
}
/* Disabled checkbox — faded, no-go cursor; the row label dims too (see .radio-row
   / .form-field label rules). Keeps the checked fill but muted. */
.checkbox:disabled{
  cursor:not-allowed;
  opacity:.5;
}
.checkbox:disabled:hover{ border-color:var(--border-strong) }
/* A label wrapping a disabled control dims with it. */
label:has(.checkbox:disabled),
label:has(input:disabled){ cursor:not-allowed; color:var(--text-faint); }

/* Checkbox + label on one line — the inline-form pattern, formalised so it's
   reused (was an ad-hoc inline style on a few labels). In Angular = <nf-checkbox>. */
.checkbox-row{
  display:inline-flex; align-items:center; gap:var(--space-8);
  font-size:var(--font-md); font-weight:400; color:var(--text);
  cursor:pointer;
}
.checkbox-row .checkbox{ flex:none }

/* -------------------------------------------------------------------------
   Todo / checklist (Sklady › Todo a další moduly) — osobní seznam položek
   s odškrtáváním. Přidávací řádek (input + tlačítko) nad seznamem.
   ------------------------------------------------------------------------- */
.todo-add{ display:flex; gap:var(--space-10); margin-bottom:var(--space-16); }
.todo-add input{ flex:1; }
.todo-list{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; }
.todo-item{
  display:flex; align-items:center; gap:var(--space-12);
  padding:var(--space-10) var(--space-4);
  border-bottom:1px solid var(--divider);
}
.todo-item:last-child{ border-bottom:0; }
.todo-num{ flex:none; min-width:1.6em; text-align:right; color:var(--text-faint); font-size:var(--font-sm); font-variant-numeric:tabular-nums; }
.todo-check{ display:inline-flex; flex:none; cursor:pointer; }
.todo-text{ flex:1; font-size:var(--font-md); color:var(--text); }
.todo-item.is-done .todo-text{ text-decoration:line-through; color:var(--text-muted); }
.todo-del{ flex:none; opacity:0; transition:opacity .14s ease; }
.todo-item:hover .todo-del{ opacity:1; }
/* Badge u Todo položky = počet komentářů/poznámek (ikona bubliny + číslo). */
.todo-badge{
  flex:none; display:inline-flex; align-items:center; gap:var(--space-4);
  padding:2px var(--space-6);
  border-radius:var(--radius-pill);
  background:var(--surface-muted); color:var(--text-muted);
  font-size:var(--font-xs); font-weight:600;
}
.todo-badge svg{ flex:none; }

/* -------------------------------------------------------------------------
   Nastavení modulu — řádek přepínače: popisek + nápověda vlevo, checkbox
   vpravo. Použito na *-settings stránkách modulů.
   ------------------------------------------------------------------------- */
.setting-rows{ display:flex; flex-direction:column; }
.setting-row{
  display:flex; align-items:center; justify-content:space-between; gap:var(--space-16);
  padding:var(--space-12) var(--space-4);
  border-bottom:1px solid var(--divider);
  cursor:pointer;
}
.setting-row:last-child{ border-bottom:0; }
.setting-info{ display:flex; flex-direction:column; gap:2px; }
.setting-label{ font-size:var(--font-md); color:var(--text); }
.setting-help{ font-size:var(--font-sm); color:var(--text-muted); }
.setting-row .checkbox{ flex:none; }
/* As a field in a .form-grid, the checkbox row takes the input row height so it
   lines up with neighbouring fields (input/select are ~38px tall). */
.form-field > .checkbox-row{ min-height:38px }


/* -------------------------------------------------------------------------
   Banner — full-width inline callout for a state or message. A soft tone bg +
   coloured icon carry the tone (semantic, NOT the swappable accent); a uniform
   1px tone border frames it. Parts: .banner-icon · .banner-body (optional
   .banner-title + text) · .banner-action (right) · .banner-close (✕). Tone via
   modifier: .banner--info (default sky) / --warning (amber) / --danger (red) /
   --success (green).
   ------------------------------------------------------------------------- */
.banner{
  display:flex; gap:var(--space-10); align-items:center;
  padding:var(--space-12) var(--space-14);
  border-radius:var(--radius-sm);
  border:1px solid;                               /* uniform tone border */
  color:var(--text); font-size:var(--font-body); line-height:1.5;
}
/* display:flex above would otherwise beat [hidden]'s display:none (class wins
   over the attribute on specificity), so a hidden banner would stay visible. */
.banner[hidden]{ display:none }
.banner-icon{ flex-shrink:0; display:flex }
.banner-icon svg{ width:18px; height:18px }
.banner-body{ flex:1; min-width:0 }
.banner-body strong{ font-weight:600 }   /* inline lead-in label, e.g. "Upozornění:" */
.banner-title{ font-weight:600; margin-bottom:var(--space-2) }
/* Action — a quiet ghost button, sized down so it doesn't compete with the message. */
.banner-action{ flex-shrink:0; align-self:center; margin-left:var(--space-8) }
.banner-action.btn{ font-size:var(--font-sm); padding:var(--space-6) var(--space-10) }
.banner-action.btn svg{ width:14px; height:14px }
/* Ghost hover on a soft tinted bg: a transparent dark wash reads on any tone. */
.banner .btn-ghost.banner-action:hover{ background:rgba(15,23,42,.06); color:var(--text) }
.banner-close{
  flex-shrink:0; margin:0 -4px 0 var(--space-6);
  display:grid; place-items:center; width:24px; height:24px;
  border:0; background:transparent; cursor:pointer; border-radius:var(--radius-xs);
  color:var(--text-muted);
}
.banner-close svg{ width:16px; height:16px }
.banner-close:hover{ background:rgba(15,23,42,.06); color:var(--text) }
/* Tones — soft bg + soft tone border (gentle frame) + tone icon. Semantic, accent-independent. */
.banner--info{ background:var(--info-soft); border-color:var(--info-border) }
.banner--info .banner-icon{ color:var(--info-fg) }
.banner--warning{ background:var(--warning-soft); border-color:var(--warning-border) }
.banner--warning .banner-icon{ color:var(--warning-fg) }
.banner--danger{ background:var(--danger-soft); border-color:var(--danger-border) }
.banner--danger .banner-icon{ color:var(--danger-fg) }
.banner--success{ background:var(--success-soft); border-color:var(--success-border) }
.banner--success .banner-icon{ color:var(--success-dark) }

/* Status pill (Active / Inactive / Suspended) */
.status{
  display:inline-flex;
  align-items:center;
  gap:var(--space-6);
  padding:2px var(--space-10) 2px var(--space-8);
  border-radius:var(--radius-pill);
  font-size:var(--font-sm);
  font-weight:600;
  line-height:1.4;          /* shodná výška se .loc-badge → řádky neskáčou */
  letter-spacing:.005em;
  white-space:nowrap;       /* chip se nikdy nezalomí na víc řádků */
}
.status::before{
  content:"";
  width:6px;
  height:6px;
  border-radius:50%;
}
.status.active{
  background:var(--success-soft);
  color:var(--success-fg);
}
.status.active::before{
  background:var(--success);
  box-shadow:0 0 0 3px rgba(34,197,94,.18);
}
.status.inactive{
  background:var(--surface-muted);
  color:var(--text-muted);
}
.status.inactive::before{ background:var(--text-faint) }
/* Stavy odchozích dat (API): Chyba červeně, Nezpracovaný amber. Odesláno = .active. */
.status.danger{ background:var(--danger-soft); color:var(--danger-fg) }
.status.danger::before{ background:var(--danger) }
.status.pending{ background:var(--warning-soft); color:var(--warning-fg) }
.status.pending::before{ background:var(--warning) }
/* Operace odchozích dat (API) — používá komponentu .status, jen bez tečky
   (.no-dot potlačí ::before). Barva podle typu operace:
   Nový záznam zeleně, Odstranění červeně, Oprava modře, Požadavek na akci žlutě. */
.status.no-dot{ padding-left:var(--space-10); }
.status.no-dot::before{ display:none; }
.status.op-create{ background:var(--success-soft); color:var(--success-fg) }   /* Nový záznam */
.status.op-delete{ background:var(--danger-soft);  color:var(--danger-fg) }    /* Odstranění */
.status.op-update{ background:var(--info-soft);    color:var(--info-fg) }      /* Oprava */
.status.op-action{ background:var(--warning-soft); color:var(--warning-fg) }   /* Požadavek na akci */
/* Sloupec Chyba (Odchozí data API) širší, ať se text vejde; clamp na 2 řádky
   drží výšku řádku (data-clamp="2" v markupu). */
#api-table th[data-col="error"], #api-table td[data-col="error"]{ min-width:340px; }

/* ===========================================================================
   Tagy (uživatelské štítky) — barevný pill s tečkou. Na rozdíl od .status
   (pevné stavy) je tag volně vytvořitelný a barvu nese přes data-tag-color,
   která mapuje na --tag-<barva>-* trojici. Sdílí rozměry/rádius se .status.
   =========================================================================== */
.tag{
  display:inline-flex;
  align-items:center;
  gap:var(--space-6);
  padding:2px var(--space-10);
  border-radius:var(--radius-pill);
  font-size:var(--font-sm);
  font-weight:600;
  line-height:1.4;
  letter-spacing:.005em;
  white-space:nowrap;
  max-width:100%;
  /* Výchozí (bez data-tag-color) = neutrální slate. */
  background:var(--tag-slate-bg);
  color:var(--tag-slate-fg);
}
/* Dlouhý název se zkrátí, ne zalomí — pill drží jednu výšku v buňce i v chips. */
.tag .tag-label{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Barevné varianty (16) — pozadí/text/tečka z trojice tokenů. */
.tag[data-tag-color="slate"]{   background:var(--tag-slate-bg);   color:var(--tag-slate-fg);   --_dot:var(--tag-slate-dot) }
.tag[data-tag-color="red"]{     background:var(--tag-red-bg);     color:var(--tag-red-fg);     --_dot:var(--tag-red-dot) }
.tag[data-tag-color="orange"]{  background:var(--tag-orange-bg);  color:var(--tag-orange-fg);  --_dot:var(--tag-orange-dot) }
.tag[data-tag-color="amber"]{   background:var(--tag-amber-bg);   color:var(--tag-amber-fg);   --_dot:var(--tag-amber-dot) }
.tag[data-tag-color="lime"]{    background:var(--tag-lime-bg);    color:var(--tag-lime-fg);    --_dot:var(--tag-lime-dot) }
.tag[data-tag-color="green"]{   background:var(--tag-green-bg);   color:var(--tag-green-fg);   --_dot:var(--tag-green-dot) }
.tag[data-tag-color="emerald"]{ background:var(--tag-emerald-bg); color:var(--tag-emerald-fg); --_dot:var(--tag-emerald-dot) }
.tag[data-tag-color="teal"]{    background:var(--tag-teal-bg);    color:var(--tag-teal-fg);    --_dot:var(--tag-teal-dot) }
.tag[data-tag-color="cyan"]{    background:var(--tag-cyan-bg);    color:var(--tag-cyan-fg);    --_dot:var(--tag-cyan-dot) }
.tag[data-tag-color="sky"]{     background:var(--tag-sky-bg);     color:var(--tag-sky-fg);     --_dot:var(--tag-sky-dot) }
.tag[data-tag-color="blue"]{    background:var(--tag-blue-bg);    color:var(--tag-blue-fg);    --_dot:var(--tag-blue-dot) }
.tag[data-tag-color="indigo"]{  background:var(--tag-indigo-bg);  color:var(--tag-indigo-fg);  --_dot:var(--tag-indigo-dot) }
.tag[data-tag-color="violet"]{  background:var(--tag-violet-bg);  color:var(--tag-violet-fg);  --_dot:var(--tag-violet-dot) }
.tag[data-tag-color="purple"]{  background:var(--tag-purple-bg);  color:var(--tag-purple-fg);  --_dot:var(--tag-purple-dot) }
.tag[data-tag-color="fuchsia"]{ background:var(--tag-fuchsia-bg); color:var(--tag-fuchsia-fg); --_dot:var(--tag-fuchsia-dot) }
.tag[data-tag-color="pink"]{    background:var(--tag-pink-bg);    color:var(--tag-pink-fg);    --_dot:var(--tag-pink-dot) }
.tag[data-tag-color="rose"]{    background:var(--tag-rose-bg);    color:var(--tag-rose-fg);    --_dot:var(--tag-rose-dot) }
/* Skupina tagů v buňce / chips — zalamuje se a drží mezery. */
.tag-group{ display:inline-flex; flex-wrap:wrap; gap:var(--space-6); align-items:center; }
/* Odebíratelný tag (v chips pickeru) — × vpravo. Tečka odpadá, ať není přeplněno. */
.tag--removable{ padding-right:var(--space-4); }
.tag--removable .tag-x{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:14px; height:14px;
  border-radius:50%;
  cursor:pointer;
  color:inherit;
  opacity:.6;
  transition:opacity .12s, background .12s;
}
.tag--removable .tag-x:hover{ opacity:1; background:rgba(0,0,0,.10) }
.tag--removable .tag-x svg{ width:9px; height:9px }
/* Prázdný stav buňky bez tagů. */
.tag-empty{ color:var(--text-faint); font-size:var(--font-sm) }

/* -------------------------------------------------------------------------
   Tag popover (NextfisTagField, .tag-pop) — přiřazení tagů k záznamu. Čistý
   seznam barevných pilulek (klik = přiřadit/odebrat, popover se zavře), NE
   multiselect s checkboxy. Jeden body-mounted popover, pozicovaný k triggeru.
   Vzhled ladí s .dropdown-menu (surface-raised, border, radius, hover).
   ------------------------------------------------------------------------- */
.tag-pop{
  position:fixed; z-index:200;
  background:var(--dropdown-bg); border:1px solid var(--dropdown-border);
  border-radius:var(--radius-sm); box-shadow:var(--shadow-lg); overflow:hidden;
  display:none;
}
.tag-pop.open{ display:block; }
.tag-pop-search{ display:flex; align-items:center; gap:var(--space-8); padding:var(--space-10) var(--space-12); border-bottom:1px solid var(--divider); }
.tag-pop-search svg{ width:15px; height:15px; color:var(--text-faint); flex:none; }
.tag-pop-search input{ border:0; outline:0; background:none; font-size:var(--font-md); color:var(--text); width:100%; }
.tag-pop-search input::placeholder{ color:var(--text-faint); }
.tag-pop-list{ max-height:280px; overflow-y:auto; padding:var(--space-4); }
.tag-pop-item{
  display:flex; align-items:center; gap:var(--space-8); width:100%;
  padding:var(--space-6) var(--space-8); border:0; background:none;
  border-radius:var(--radius-xs); cursor:pointer; text-align:left;
}
.tag-pop-item:hover{ background:var(--surface-hover); }
.tag-pop-item.is-on{ background:var(--surface-active); }
.tag-pop-item .spacer{ flex:1; }
/* Edit ikona (tužka) — skrytá, viditelná jen na hover/focus řádku. Klik = Edit Tag modal. */
.tag-pop-edit{
  display:inline-flex; align-items:center; justify-content:center; flex:none;
  width:24px; height:24px; border-radius:var(--radius-xs);
  color:var(--text-faint); opacity:0; transition:opacity .12s ease, background .12s ease, color .12s ease;
}
.tag-pop-edit svg{ width:15px; height:15px; }
.tag-pop-item:hover .tag-pop-edit,
.tag-pop-item:focus-within .tag-pop-edit{ opacity:1; }
.tag-pop-edit:hover{ background:var(--surface-active); color:var(--brand); }
.tag-pop-empty{ padding:var(--space-12); color:var(--text-faint); font-size:var(--font-sm); text-align:center; }
.tag-pop-foot{ border-top:1px solid var(--divider); padding:var(--space-4); }
.tag-pop-new{
  display:flex; align-items:center; gap:var(--space-8); width:100%;
  padding:var(--space-8) var(--space-10); border:0; background:none;
  border-radius:var(--radius-xs); cursor:pointer; color:var(--brand);
  font-size:var(--font-md); font-weight:600; text-align:left;
}
.tag-pop-new:hover{ background:var(--surface-hover); }
.tag-pop-new svg{ width:15px; height:15px; flex:none; }

/* -------------------------------------------------------------------------
   Edit Tag modal (NextfisTagModal) — YouTrack styl. Používá VÝHRADNĚ komponenty
   z DS: .form-field (label NAD polem) pro řádky, .color-picker (barva),
   .radio-group--horizontal (rozsah), .checkbox (Sdílený → odkryje Přístup), .ms-combo
   (Kdo vidí/používá/edituje = multiselect role+uživatelé). Žádné vlastní pole.
   ------------------------------------------------------------------------- */
/* Specificita 0,2,0 — musí přebít pozdější .modal-card{width:420px} (stejná specificita,
   ale definován níž → jinak vyhrává on a modal zůstane 420px). */
.modal-card.tag-modal-card{ width:min(560px, calc(100% - 40px)); }
/* Jeden sloupec, vše pod sebou. modal-body scroll pro dlouhý obsah; ms-panel je
   position:absolute → aby ho scroll neořízl, při otevřeném combu/dropdownu přepneme
   kartu na overflow:visible (níže). */
.tag-modal-card .modal-body{ display:flex; flex-direction:column; gap:var(--space-14); max-height:min(76vh, 640px); overflow-y:auto; }
/* Otevřený multiselect/dropdown/color-picker → karta i body nesmí ořezávat panel. */
.tag-modal-card:has(.ms-combo.open) .modal-body,
.tag-modal-card:has(.color-picker.open) .modal-body,
.tag-modal-card:has(.select-menu-host.open) .modal-body{ overflow:visible; }
.tag-modal-card:has(.ms-combo.open),
.tag-modal-card:has(.color-picker.open),
.tag-modal-card:has(.select-menu-host.open){ overflow:visible; }

/* Přístup (Vlastník + Kdo vidí/používá/edituje) — blok pod Sdílený, jen když sdílený.
   Oddělený horní linkou. */
.tag-modal-access{ display:flex; flex-direction:column; gap:var(--space-14); padding-top:var(--space-14); border-top:1px solid var(--divider); }
.tag-modal-access[hidden]{ display:none; }
.tag-modal-access-head{ font-size:var(--font-xs); font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--text-faint); }

/* Název + barevný picker vedle sebe — dva stejně široké fieldy (1:1). */
.tag-modal-name{ display:flex; align-items:flex-end; gap:var(--space-10); }
.tag-modal-name .form-field{ flex:1 1 0; min-width:0; }
.tag-modal-color{ flex:1 1 0; min-width:0; width:auto; }
.tag-modal-preview{ margin-top:calc(-1 * var(--space-6)); }
/* Rozsah dropdown na plnou šířku řádku form-field. */
.tag-modal-scope{ width:100%; }
/* Smazat tag = vlevo ve spodní liště (margin-right:auto odtlačí Zrušit/Uložit doprava). */
.tag-modal-delete{ margin-right:auto; display:inline-flex; align-items:center; gap:var(--space-6); }

/* Trigger button (v hlavičce detailu i v řádku seznamu). Aktivní = otevřený. */
.tag-field-btn.btn-icon svg{ width:16px; height:16px; }
.tag-field-btn.is-open{ background:var(--surface-active); color:var(--brand); }

/* Pás vybraných tagů (řádek pilulek pod nadpisem). Prázdný = žádná výška. */
.tag-field-pills{ display:flex; flex-wrap:wrap; gap:var(--space-6); align-items:center; }
.tag-field-pills:empty{ display:none; }

/* Drawer hlavička s .drawer-head-row = dva řádky pod sebou: pevný horní řádek
   (avatar + jméno + akce) se NEHÝBE, tagy jsou samostatný řádek pod ním. JEN
   tam, kde je .drawer-head-row (Uživatelé) — ostatní drawery zůstávají 1 řádek. */
.drawer-head:has(.drawer-head-row){ flex-direction:column; align-items:stretch; gap:var(--space-8); }
.drawer-head-row{ display:flex; align-items:center; gap:var(--space-10); }
.drawer-head-row h3{ margin:0; flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; }
.drawer-head .tag-field-pills{ margin-top:var(--space-2); }
/* Tag button v hlavičce detailu = ohraničený (jako ve velkém detailu). */
.drawer-head .tag-field-btn{ border:1px solid var(--border-strong); border-radius:var(--radius-sm); }

/* Meta pás v page-header (pod nadpisem) — nese tagy velkého detailu. */
.page-header-meta{ margin-top:var(--space-8); }
.page-header-meta:empty{ display:none; }

/* Sloupec Tagy v seznamu: omezená šířka, hodně tagů se zalomí (ne roztažení
   tabulky do strany). Pilulky v buňce jsou odebíratelné (× přímo v seznamu). */
.data-table td[data-col="tags"]{ max-width:260px; }
.data-table td[data-col="tags"] .tag-group{ display:flex; flex-wrap:wrap; gap:var(--space-4); }
/* Výběr barvy tagu — mřížka kruhových vzorků (swatch). Vybraný má prstenec.
   Barva vzorku = plná tečka tagu (--tag-<barva>-dot). */
.tag-swatches{ display:flex; flex-wrap:wrap; gap:var(--space-8); }
.tag-swatch{
  width:26px; height:26px;
  border-radius:50%;
  border:2px solid transparent;
  cursor:pointer;
  padding:0;
  position:relative;
  background:var(--_sw, var(--tag-slate-dot));
  transition:transform .1s ease, box-shadow .12s ease;
}
.tag-swatch:hover{ transform:scale(1.08) }
.tag-swatch[data-tag-color="slate"]{   --_sw:var(--tag-slate-dot) }
.tag-swatch[data-tag-color="red"]{     --_sw:var(--tag-red-dot) }
.tag-swatch[data-tag-color="orange"]{  --_sw:var(--tag-orange-dot) }
.tag-swatch[data-tag-color="amber"]{   --_sw:var(--tag-amber-dot) }
.tag-swatch[data-tag-color="lime"]{    --_sw:var(--tag-lime-dot) }
.tag-swatch[data-tag-color="green"]{   --_sw:var(--tag-green-dot) }
.tag-swatch[data-tag-color="emerald"]{ --_sw:var(--tag-emerald-dot) }
.tag-swatch[data-tag-color="teal"]{    --_sw:var(--tag-teal-dot) }
.tag-swatch[data-tag-color="cyan"]{    --_sw:var(--tag-cyan-dot) }
.tag-swatch[data-tag-color="sky"]{     --_sw:var(--tag-sky-dot) }
.tag-swatch[data-tag-color="blue"]{    --_sw:var(--tag-blue-dot) }
.tag-swatch[data-tag-color="indigo"]{  --_sw:var(--tag-indigo-dot) }
.tag-swatch[data-tag-color="violet"]{  --_sw:var(--tag-violet-dot) }
.tag-swatch[data-tag-color="purple"]{  --_sw:var(--tag-purple-dot) }
.tag-swatch[data-tag-color="fuchsia"]{ --_sw:var(--tag-fuchsia-dot) }
.tag-swatch[data-tag-color="pink"]{    --_sw:var(--tag-pink-dot) }
.tag-swatch[data-tag-color="rose"]{    --_sw:var(--tag-rose-dot) }
.tag-swatch.selected{ box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--_sw); }
.tag-swatch.selected::after{
  content:"";
  position:absolute; inset:0;
  margin:auto;
  width:8px; height:8px;
  border-radius:50%;
  background:var(--surface);
}

/* Lokace skladu — barevný badge bez tečky (Externí zeleně, Interní modře).
   Sdílí rozměry se .status (viz výše), ale bez ::before tečky. */
.loc-badge{
  display:inline-flex; align-items:center;
  padding:2px var(--space-8);
  border-radius:var(--radius-pill);
  font-size:var(--font-sm);
  font-weight:600;
  line-height:1.4;
}
.loc-badge.loc-ext{ background:var(--success-soft); color:var(--success-fg) }
.loc-badge.loc-int{ background:var(--info-soft);    color:var(--info-fg) }
/* Typ skladového předmětu (Skladová místa) — tytéž badge, jiné barvy:
   Palety a kusy modrá, Kusy zelená, Palety amber. */
.loc-badge.loc-both{   background:var(--info-soft);    color:var(--info-fg) }
.loc-badge.loc-units{  background:var(--success-soft); color:var(--success-fg) }
.loc-badge.loc-pallets{background:var(--warning-soft); color:var(--warning-fg) }

/* ── Inline editovatelná tabulka (child kolekce v detailu) ─────────────
   KANONICKÝ pattern pro vnořené tabulky, jejichž řádky se editují přímo na
   místě (buňky jsou trvale vstupy, ne ✎-toggle). Použito pro Atributy tříd
   šarží; stejně použitelné pro OPC proměnné, Akce zařízení apod.

   Stejně jako simple-list je to VARIANTA `.data-table` — markup je
   `table.data-table[data-attrs]`, takže DĚDÍ veškerý vizuál (hlavička, font,
   bordery, paddingy). Overridujeme jen specifika: inline vstupy v buňkách,
   žádný hover/klikání řádků, horizontální scroll v úzkém kontejneru.
   Markup: .attrs-scroll > table.data-table[data-attrs]; vstupy .attr-in,
   + tlačítko .attr-add-btn, prázdný stav .attrs-empty. Viz design-detail.html. */
.section-head--action{
  display:flex; align-items:flex-start; justify-content:space-between;
  gap:var(--space-12);
}
/* Plněné brand tlačítko + (NE .btn-icon — to je šedý ikonový knoflík s vlastním
   hoverem, který by přebil barvu ikony). Proto vlastní samostatná třída. */
.attr-add-btn{
  flex-shrink:0;
  width:32px; height:32px;
  border-radius:var(--radius-sm);
  background:var(--brand);
  color:var(--on-accent);
  display:grid; place-items:center;
  border:0; cursor:pointer;
  transition:background .12s ease;
}
.attr-add-btn:hover{ background:var(--brand-dark); color:var(--on-accent) }
.attr-add-btn svg{ display:block }

.attrs-scroll{ overflow-x:auto; border:1px solid var(--border); border-radius:var(--radius); }
/* Kompaktní hustota řádků jako simple-list — je to taky vnořená tabulka
   v detailu (ne hlavní seznam). Sdílí token --row-pad-compact-*. */
.data-table[data-attrs] thead th,
.data-table[data-attrs] tbody td{
  padding:var(--row-pad-compact-y) var(--row-pad-compact-x);
}
/* Centrovaný sloupec (Povinný / Aktivní …) — .data-table to nemá. */
.data-table[data-attrs] th.ta-center,
.data-table[data-attrs] td.ta-center{ text-align:center }
/* Řádky nejsou klikatelné (editují se na místě) — žádný hover ani pointer. */
.data-table[data-attrs] tbody tr{ cursor:default }
/* Drag & drop přeřazení atributů: úchyt ve sloupci Pořadí + stavy řádku. */
/* Sloupec Pořadí je .num (pravé zarovnání) — to by úchyt u kratšího čísla (1)
   posunulo jinam než u delšího (99). Zarovnáme obsah vlevo, takže handle stojí
   vždy na stejné pozici a „neskáče". */
.data-table[data-attrs] td.num:has(.attr-order){ text-align:left; }
.attr-order{ display:inline-flex; align-items:center; gap:var(--space-6); }
.attr-order-num{ display:inline-block; min-width:2ch; text-align:right; }
.data-table[data-attrs] tbody tr:hover .drag-grip{ color:var(--text-muted); }
.data-table[data-attrs] tbody tr.dragging{ opacity:.5; }
.data-table[data-attrs] tbody tr.drag-over td{ box-shadow:inset 0 2px 0 0 var(--brand); }
.data-table[data-attrs] tbody tr:hover{ background:transparent }
.data-table[data-attrs] tbody tr:last-child td{ border-bottom:0 }
.data-table[data-attrs] .col-actions{ width:48px }
/* Inline vstupy uvnitř buněk — font-md jako tělo tabulky, neutrální okraj. */
.attr-in{
  width:100%;
  min-width:120px;
  padding:var(--space-6) var(--space-8);
  border:1px solid transparent;
  border-radius:var(--radius-sm);
  background:transparent;
  font-size:var(--font-md);
  color:var(--text);
}
.attr-in--sm{ min-width:90px }
/* Číselná varianta — užší, zarovnaná doprava (množství v num sloupcích). */
.attr-in--num{ min-width:0; width:96px; text-align:right; display:inline-block; }
/* Stepper uvnitř buňky tabulky (např. Patro od v zaskladňovacích zónách). */
.cell-stepper{ display:inline-block; width:120px; vertical-align:middle; }
.cell-stepper .input-wrap{ position:relative; }
.cell-stepper .input-wrap input{ width:100%; }
.attr-in:hover{ border-color:var(--border) }
.attr-in:focus{ border-color:var(--brand); background:var(--surface); outline:none; box-shadow:0 0 0 3px var(--brand-ring) }
.attrs-empty{
  padding:var(--space-20);
  text-align:center;
  color:var(--text-muted);
  font-size:var(--font-md);
}
.status.suspended{
  background:var(--warning-soft);
  color:var(--warning-fg);
}
.status.suspended::before{ background:var(--warning) }

/* Inventory lifecycle states (reuse the stage palette). */
.status.inv-planned{ background:var(--stage-arrived-bg); color:var(--stage-arrived-fg) }
.status.inv-planned::before{ background:var(--stage-arrived-dot) }
.status.inv-running{ background:var(--stage-loading-bg); color:var(--stage-loading-fg) }
.status.inv-running::before{ background:var(--stage-loading-dot) }
.status.inv-done{ background:var(--stage-done-bg); color:var(--stage-done-fg) }
.status.inv-done::before{ background:var(--stage-done-dot) }
.status.inv-cancelled{ background:var(--surface-muted); color:var(--text-muted) }
.status.inv-cancelled::before{ background:var(--text-faint) }
/* Per-item SCAN state inside a Záznamy table — distinct semantics from the
   inventory state above (item scanned vs not), same green/grey visual language. */
.status.scanned{ background:var(--stage-done-bg); color:var(--stage-done-fg) }
.status.scanned::before{ background:var(--stage-done-dot) }
.status.unscanned{ background:var(--surface-muted); color:var(--text-muted) }
.status.unscanned::before{ background:var(--text-faint) }
/* Stav jednotlivého kusu MAJETKU: Aktivní (green) / Nový (amber, čerstvě
   pořízený, zatím nezařazený) / Vyřazený (grey, mimo evidenci). */
.status.asset-active{ background:var(--stage-done-bg); color:var(--stage-done-fg) }
.status.asset-active::before{ background:var(--stage-done-dot) }
.status.asset-new{ background:var(--warning-soft); color:var(--warning-fg) }
.status.asset-new::before{ background:var(--warning) }
.status.asset-disposed{ background:var(--surface-muted); color:var(--text-muted) }
.status.asset-disposed::before{ background:var(--text-faint) }

/* Inventurní rozdíl Typ — pill WITH an icon (arrow): Manko (shortage, red,
   arrow down) vs Přebytek (overage, green, arrow up). Icon + label, not the
   dot-style .status pill. */
.inv-pill{
  display:inline-flex; align-items:center; gap:var(--space-6);
  padding:var(--space-2) var(--space-8);
  border-radius:var(--radius-pill);
  font-size:var(--font-xs); font-weight:600; line-height:1.6;
  white-space:nowrap;
}
.inv-pill svg{ width:13px; height:13px; }
.inv-pill--manko{ background:var(--danger-soft); color:var(--danger-fg) }
.inv-pill--prebytek{ background:var(--success-soft); color:var(--success-dark) }

/* "Důvod vyřazení" buňka v souhrnu rozdílů. Nezměněný default je odšeděný
   (placeholder styl) — vizuálně odliší "ještě jsem nezasahoval" od potvrzeného.
   Buňka přebytku (.muted) nese jen pomlčku. */
.reason-val.is-default{ color:var(--text-faint); font-style:italic; }
td.muted{ color:var(--text-faint) }
/* U dílčí inventury se sloupec Důvod vyřazení skrývá (vyrovnává se až v souhrnu). */
.data-table.hide-reason th[data-col="reason"],
.data-table.hide-reason td[data-col="reason"]{ display:none }

/* Link state (e.g. code → asset binding): icon instead of the dot. */
.status.linked,
.status.unlinked{ padding-left:var(--space-8) }
.status.linked::before,
.status.unlinked::before{ display:none }   /* replace the dot with an inline SVG */
.status.linked{ background:var(--success-soft); color:var(--success-fg) }
.status.unlinked{ background:var(--surface-muted); color:var(--text-muted) }
.status.linked svg,
.status.unlinked svg{ width:13px; height:13px; flex-shrink:0 }


/* Footer pagination */
.pagination{
  display:flex;
  align-items:center;
  justify-content:space-between;
  padding:var(--space-12) var(--space-16);
  background:var(--surface);
  border:1px solid var(--border);
  border-top:0;
  border-radius:0 0 var(--radius) var(--radius);
  margin-top:-1px;
  font-size:var(--font-body);
  color:var(--text-muted);
}
.pagination .page-size{
  display:flex;
  align-items:center;
  gap:var(--space-8);
}
.pagination .page-size label{
  font-size:var(--font-body);
  color:var(--text-muted);
}
.pagination .page-size select{
  padding:var(--space-4) var(--space-8);
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface);
  font-size:var(--font-body);
  color:var(--text);
  cursor:pointer;
}
.pagination .page-pos{
  font-size:var(--font-body);
  color:var(--text-muted);
  font-variant-numeric:tabular-nums;
  padding:0 var(--space-4);
}
.pagination .page-pos strong{ color:var(--text); font-weight:600 }
.pagination .nav{
  display:flex;
  align-items:center;
  gap:var(--space-6);
}
.pagination .nav button{
  width:28px;
  height:28px;
  border-radius:var(--radius-sm);
  display:grid;
  place-items:center;
  color:var(--text-muted);
}
.pagination .nav button:hover{ background:var(--surface-hover); color:var(--text) }
.pagination .nav button:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring-strong) }
/* When all rows fit on a single page, hide pager controls (arrows + numbers).
   Keep page-size and the range/count summary so the user knows what they see. */
.pagination.single-page .nav{ display:none }

/* Inline editovatelná tabulka pro child kolekce (Atributy tříd šarží, OPC
   proměnné, …) je varianta `.data-table[data-attrs]` níže (sekce „Inline
   editovatelná tabulka“). Buňky jsou TRVALE editovatelné (vstupy přímo
   v řádku), + přidá řádek, 🗑 smaže. Viz Detail záznamu v design systému. */

/* -------------------------------------------------------------------------
   Section — the system-wide way to group content inside a detail/form.
   Just a heading (+ optional meta on the right) above its content. No box,
   no border — the heading alone separates groups. Use everywhere a detail
   needs to break content into named groups (Základ, Role, Oprávnění, …).
   ------------------------------------------------------------------------- */
.section + .section{ margin-top:36px }   /* generous gap separates groups (ClickUp-style) */

/* -------------------------------------------------------------------------
   Šířka obsahu velkého detailu — 3 sjednocené hladiny (dřív roztříštěné inline
   max-width 760/980/1000/1100). Dej třídu na .section (VŠECHNY sekce stránky
   stejnou → celá stránka drží jednu šířku). Výběr dle obsahu:
   - .detail-sm (760)  = jednoduchý form (pár polí, žádná/malá tabulka)
   - .detail-md (980)  = běžný form s víc sekcemi / lehká tabulka  [default]
   - .detail-lg (1180) = bohatý detail (víc tabulek / záložek s daty)
   Výjimka: tabulka jako JEDINÝ content stránky smí přes celou plochu (bez třídy).
   POZOR: NESMÍ být jen `.detail` — koliduje s komponentou `.detail` (boční panel,
   position:fixed + visibility:hidden), sekce by zdědila skrytí. Proto `-sm/-md/-lg`.
   ------------------------------------------------------------------------- */
:root{ --detail-sm:760px; --detail-md:980px; --detail-lg:1180px; }
.section.detail-sm{ max-width:var(--detail-sm); }
.section.detail-md{ max-width:var(--detail-md); }
.section.detail-lg{ max-width:var(--detail-lg); }
/* Generované sekce (module-settings.js) jsou v kontejneru [data-module-settings],
   takže .section + .section nechytne přes hranici kontejneru — dorovnáme mezeru
   ručně: první sekce v kontejneru i sekce hned za kontejnerem. */
[data-module-settings] > .section{ margin-top:36px }
[data-module-settings] + .section{ margin-top:36px }

/* -------------------------------------------------------------------------
   Field group — lehčí úroveň NEŽ sekce. Jen popisek + shluk souvisejících polí
   UVNITŘ sekce (typicky Rozměry: šířka/výška/hloubka). Žádný velký předěl ani
   h2 — menší label (caps, muted) a těsnější rozestup. Sekce = samostatný oddíl
   formuláře; skupina = pojmenovaný shluk polí v něm.
   ------------------------------------------------------------------------- */
.field-group + .field-group{ margin-top:var(--space-18) }
/* Popisek skupiny vizuálně jako hlavička tabulky (uppercase, prostrkané, muted),
   o stupínek větší pro čitelnost jako label skupiny. */
.field-group > .field-group-label{
  display:block;
  font-size:var(--font-xs);   /* jako hlavička tabulky (th) */
  font-weight:700;
  color:var(--text-subtle);
  letter-spacing:.06em;
  text-transform:uppercase;
  margin-bottom:var(--space-10);
}
.section-head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:var(--space-12);
  margin-bottom:var(--space-14);
}
.section-head h2,
.section-head h3{
  font-size:var(--font-xl);
  font-weight:700;
  color:var(--text);
  letter-spacing:-.01em;
  /* inline-flex so any trailing element (sub text, status pill, badge) sits
     vertically centred next to the title with a consistent gap. */
  display:inline-flex;
  align-items:center;
  gap:var(--space-8);
}
.section-head .sub{
  font-size:var(--font-sm);
  color:var(--text-muted);
  font-weight:400;
}
.section-head .section-meta{
  font-size:var(--font-sm);
  color:var(--text-muted);
  flex-shrink:0;
}
/* Intro paragraph above a section/tab content (e.g. "Sestavte posloupnost…").
   Replaces repeated inline <p style="color:…;font-size:…"> on several pages. */
.section-intro{
  font-size:var(--font-md);
  color:var(--text-muted);
  margin:0 0 var(--space-16);
  max-width:760px;
  line-height:1.5;
}

/* Audit row — read-only record metadata (who/when created + updated). Sits at
   the bottom of a detail; dimmed, small, separated by a top rule. */
.audit-row{
  display:flex; flex-wrap:wrap; gap:var(--space-6) var(--space-16);
  margin-top:var(--space-16);
  padding-top:var(--space-12);
  border-top:1px solid var(--divider);
  font-size:var(--font-sm);
  color:var(--text-faint);
}
.audit-row .audit-item strong{ color:var(--text-muted); font-weight:600 }

/* -------------------------------------------------------------------------
   Card / form sections
   ------------------------------------------------------------------------- */
.card{
  background:var(--card-bg);
  border:1px solid var(--card-border);
  border-radius:var(--card-radius);
  overflow:hidden;
}
.card-header{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:var(--space-12);
  padding:var(--space-14) var(--space-18);
  border-bottom:1px solid var(--divider);
  background:var(--surface-alt);
}
.card-header h2,
.card-header h3{
  font-size:var(--font-md);
  font-weight:700;
  color:var(--text);
}
.card-header .sub{
  font-size:var(--font-sm);
  color:var(--text-muted);
  font-weight:400;
  margin-left:var(--space-8);
}
.card-body{ padding:var(--space-18) }

.form-grid{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:var(--space-18) var(--space-20);
  /* On narrow content (small windows / tablet portrait) two columns squeeze
     the fields too thin — collapse to one. Fields that span both columns
     (grid-column:1/-1) still fill the single column naturally. */
}
/* Čtyřsloupcová varianta — řádky rozměrů (Šířka / Hloubka / Výška / Jedn.). */
.form-grid-4{ grid-template-columns:repeat(4, minmax(0, 1fr)); }

/* Hromadné vytvoření skladových míst — formulář vlevo, nápověda vpravo. */
.bulk-layout{
  display:grid;
  grid-template-columns:minmax(0, 1fr) minmax(0, 1fr);
  gap:var(--space-24) calc(var(--space-24) * 2);   /* širší mezera mezi formulářem a nápovědou */
  align-items:start;
}
/* Responzivita: pod 1100px nápověda padá pod formulář (1 sloupec). */
@media (max-width:1100px){ .bulk-layout{ grid-template-columns:1fr; } }
/* Řádek „od až" (Patra / Rozsah) — dva vstupy se spojkou, volitelný koš.
   Žádný margin-bottom: mezeru k labelu řeší .form-field gap, k „+" range-add. */
.range-row{
  display:flex; align-items:center; gap:var(--space-10);
}
.range-row input{ flex:1 1 0; min-width:0; }
.range-sep{ color:var(--text-faint); flex:0 0 auto; }
/* „+" pro přidání části rozsahu — na řádku za poli od/až. Čtverec 32×32
   jako koš (.range-del) a ostatní .btn-icon. */
.range-add{ flex:0 0 auto; width:32px; height:32px; padding:0; display:inline-grid; place-items:center; }
.range-add svg{ width:16px; height:16px; }
/* Další části rozsahu (od 2. dál). Každý sloupec (Rozsah / Oddělovač) má vlastní
   label nad polem; řádek je zarovnaný na vrch, takže labely jsou v jedné lince
   a nic neskáče. Koš je jemná ikona zarovnaná ke spodku polí. */
.range-part{ margin-top:var(--space-14); }
.range-part .range-row{ align-items:flex-end; }
.range-col{ flex:1 1 0; min-width:0; display:flex; flex-direction:column; gap:var(--space-6); }
.range-col--delim{ flex:0 0 auto; }
.range-col--delim select{ min-width:150px; }
/* Sloupec s košem — prázdný label-spacer drží koš na lince se selectem. */
.range-col--del{ flex:0 0 auto; }
.range-part-label{ font-size:var(--font-sm); font-weight:600; color:var(--text-muted); letter-spacing:.015em; }
/* Vnitřní „od až" dvojice uvnitř sloupce Rozsah. */
.range-fromto{ display:flex; align-items:center; gap:var(--space-10); }
.range-fromto input{ flex:1 1 0; min-width:0; }
/* Koš u části rozsahu = jemné ikonové tlačítko (.btn-icon styl), bez pozadí.
   Zarovnán svisle na střed pole od/až (ne na label). */
.range-del{
  flex:0 0 auto;
  width:32px; height:32px; padding:0;    /* čtverec jako každý .btn-icon */
  display:inline-grid; place-items:center;
  background:transparent; border:0;
  color:var(--text-muted);
  border-radius:var(--radius-sm); cursor:pointer;
  transition:.12s ease;
}
.range-del svg{ width:16px; height:16px; }
/* Destruktivní hover = systémový (jako .btn-danger): červené podbarvení + text. */
.range-del:hover{ background:var(--danger-soft); color:var(--danger-fg); }
.range-del:focus{ outline:none; background:transparent; }
.range-del:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--danger-ring); }
.range-del:active{ background:var(--danger-soft); }
/* Nápovědový panel u hromadného vytvoření. */
.bulk-help{
  background:var(--surface-soft);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  padding:var(--space-18) var(--space-20);
}
.bulk-help h3{ margin:0 0 var(--space-12); font-size:var(--font-md); }
.bulk-help ul{ margin:0; padding-left:var(--space-18); color:var(--text-muted); font-size:var(--font-sm); line-height:1.7; }
.bulk-help ul ul{ margin-top:var(--space-2); }
.bulk-help strong{ color:var(--text); }
.bulk-help-note{ margin:var(--space-14) 0 0; color:var(--text-faint); font-size:var(--font-sm); font-style:italic; }
/* Živý náhled vygenerovaných názvů. */
.bulk-preview{
  margin-top:var(--space-16);
  padding-top:var(--space-16);
  border-top:1px solid var(--border);
}
.bulk-preview-head{ display:flex; align-items:baseline; gap:var(--space-8); margin-bottom:var(--space-10); }
.bulk-preview-head strong{ font-size:var(--font-md); color:var(--text); }
.bulk-preview-count{ font-size:var(--font-sm); color:var(--text-muted); }
.bulk-preview-body{ display:flex; flex-wrap:wrap; gap:var(--space-6); align-items:center; }
.bulk-preview-body code{
  font-family:var(--font-mono, ui-monospace, monospace);
  font-size:var(--font-sm);
  background:var(--surface-active);
  color:var(--text);
  padding:2px var(--space-8);
  border-radius:var(--radius-sm);
}
.bulk-preview-body .preview-ell{ color:var(--text-faint); }
.bulk-preview-body .preview-empty{ color:var(--text-faint); font-size:var(--font-sm); font-style:italic; }

/* Inventura — akce v hlavičce tabulky míst (Přidat vše + tlačítko „+").
   „+" je standardní .attr-add-btn (jako Atributy), „Přidat vše" jen .btn. */
.attr-head-actions{ display:flex; align-items:center; gap:var(--space-8); }
/* Všechna tlačítka v hlavičce tabulky míst mají výšku 32px (jako .attr-add-btn). */
.attr-head-actions .btn{ height:32px; padding-top:0; padding-bottom:0; }
/* Rozbalený combobox (select-search) uvnitř .attrs-scroll (overflow-x:auto) by se
   ořízl — povol overflow, dokud je otevřený. POZOR: to rozlije širokou tabulku ven
   z kontejneru; select-menu proto NEpoužívá tento trik, ale position:fixed panel
   (viz select-menu.js), takže .select-menu-host.open zde ZÁMĚRNĚ není. */
.attrs-scroll:has(.select-search.open){ overflow:visible; }
/* Borderless varianta select-search ve vnořené tabulce — konzistentní s .attr-in:
   rámeček/pozadí jen na hover a focus, v klidu splývá s buňkou. */
.attrs-scroll .ss-control{ border-color:transparent; background:transparent; }
.attrs-scroll .ss-control:hover{ border-color:var(--border); }
.attrs-scroll .select-search.open .ss-control{ border-color:var(--brand); background:var(--surface); box-shadow:0 0 0 3px var(--brand-ring); }
/* Totéž pro custom dropdown (.sm-control) a stepper input v inline tabulce —
   splývají s buňkou, rámeček až na hover/otevření/focus. Výška SJEDNOCENA
   s .attr-in / .cell-input (kompaktní inline, ne 38px form výška). */
.attrs-scroll .sm-control{
  border-color:transparent; background:transparent;
  min-height:0; padding:var(--space-6) var(--space-8); font-size:var(--font-md);
}
.attrs-scroll .sm-control:hover{ border-color:var(--border); }
.attrs-scroll .select-menu-host.open .sm-control{ border-color:var(--brand); background:var(--surface); box-shadow:0 0 0 3px var(--brand-ring); }
/* V inline tabulce jsou sloupce úzké → panel by měl stejnou (malou) šířku jako
   control a dlouhé položky by se ořízly („Povoleno vše" → „Povoleno …"). Nech
   panel roztáhnout na šířku nejdelší položky (min = šířka controlu). */
.attrs-scroll .sm-panel{ right:auto; min-width:100%; width:max-content; max-width:280px; }
.attrs-scroll .sm-option{ white-space:nowrap; }
.attrs-scroll .cell-stepper .input-wrap input,
.attrs-scroll td .cell-input{ border-color:transparent; background:transparent; padding:var(--space-6) var(--space-8); }
.attrs-scroll .cell-stepper:hover .input-wrap input{ border-color:var(--border); }
.attrs-scroll .cell-stepper .input-wrap input:focus{ border-color:var(--brand); background:var(--surface); box-shadow:0 0 0 3px var(--brand-ring); }
/* Stepper tlačítka v buňce se ukážou až na hover řádku/pole (jinak splývá). */
.attrs-scroll .cell-stepper .stepper-btns{ opacity:0; transition:opacity .12s; }
.attrs-scroll tr:hover .cell-stepper .stepper-btns,
.attrs-scroll .cell-stepper:hover .stepper-btns,
.attrs-scroll .cell-stepper:focus-within .stepper-btns{ opacity:1; }

/* --- Responzivita hromadného vytvoření --------------------------------- */
/* Pod 900px má formulář uvnitř bulk-layoutu jen 1 sloupec polí. */
@media (max-width:900px){
  .bulk-layout .form-grid{ grid-template-columns:1fr; }
}
/* Úzké obrazovky: části rozsahu se zalomí, oddělovač/koš se nevejdou na řádek.
   Sloupce roztáhneme na plnou šířku a koš posuneme na konec. */
@media (max-width:560px){
  .range-part .range-row{ flex-wrap:wrap; align-items:flex-end; }
  .range-col,
  .range-col--delim{ flex:1 1 100%; }
  .range-col--delim select{ width:100%; min-width:0; }
  .range-col--del{ flex:0 0 auto; margin-left:auto; }
  .range-col--del .range-part-label{ display:none; }   /* prázdný spacer netřeba */
  /* první řádek rozsahu (od/až/+) ať se taky vejde */
  .range-fromto{ flex:1 1 100%; }
}
/* display:grid above beats [hidden]'s display:none (class > attribute) — make
   the attribute win so a toggled-off form-grid actually hides. */
.form-grid[hidden]{ display:none }
.form-field{
  display:flex;
  flex-direction:column;
  gap:var(--space-6);
}
/* display:flex beats the UA [hidden] rule — restore it so a field can be
   conditionally shown/hidden (e.g. mode-dependent fields). */
.form-field[hidden]{ display:none; }
/* Field label — small, semibold, muted. Excludes .radio-row / .checkbox-row,
   which ARE <label>s but are option ROWS (not field captions): they carry their
   own --font-md / normal-weight / --text colour and must not shrink+bold here. */
.form-field label:not(.radio-row):not(.checkbox-row){
  font-size:var(--font-sm);
  font-weight:600;
  color:var(--text-muted);
  letter-spacing:.015em;
}
.form-field label .req{ color:var(--danger); margin-left:var(--space-2) }
/* Text-like inputs only — exclude checkbox/radio, which carry their own
   sizing (.checkbox / .radio-row); otherwise the field padding/border would
   inflate them into ~38px buttons. */
.form-field input:not([type=checkbox]):not([type=radio]),
.form-field select,
.form-field textarea{
  padding:var(--space-8) var(--space-12);
  border:1px solid var(--input-border);
  border-radius:var(--radius-sm);
  background:var(--input-bg);
  font-size:var(--font-md);
  color:var(--input-fg);
  transition:.16s ease;
}
/* Placeholder = --text-faint (slate-500), stejně jako .ms-placeholder u
   multiselectu — bez pravidla form inputy dědily UA default jiné barvy. */
.form-field input::placeholder,
.form-field textarea::placeholder{ color:var(--input-placeholder); opacity:1; }
/* Textarea — multi-line text (poznámky, popisy). Inherits the input look; adds a
   sensible min height and lets the user drag-resize vertically only. */
.form-field textarea{
  font-family:inherit;
  min-height:76px;          /* ~3 lines — spodní hranice, výš roste s obsahem */
  resize:none;              /* výšku řídí obsah (textarea-autogrow.js), ne ruční tažení */
  overflow:hidden;          /* žádný scrollbar během růstu */
  line-height:1.5;
}
/* Custom chevron — SELECT only (an input must not get a dropdown arrow). The
   native arrow sat flush to the border; appearance:none replaces it with room. */
.form-field select{
  appearance:none;
  -webkit-appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 10px center;
  padding-right:38px;
}
.form-field input:not([type=checkbox]):not([type=radio]):focus,
.form-field select:focus,
.form-field textarea:focus{
  outline:none;
  border-color:var(--input-border-focus);
  box-shadow:0 0 0 3px var(--brand-ring);
}
/* Disabled — the field is OFF: greyed surface, faint text, no-go cursor. The
   value is de-emphasised because you can't act on it. */
.form-field input:not([type=checkbox]):not([type=radio]):disabled,
.form-field select:disabled,
.form-field textarea:disabled{
  background:var(--surface-muted);
  border-color:var(--border);
  color:var(--text-faint);
  /* WebKit/Blink fade disabled fields extra (lower opacity + own fill colour),
     which made <select> read lighter than a disabled <input>. Pin both so all
     three disabled fields share the exact same text colour. */
  -webkit-text-fill-color:var(--text-faint);
  opacity:1;
  cursor:not-allowed;
}
.form-field select:disabled{
  /* grey the chevron to match the faint disabled text (slate-500, = --text-faint) */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 10px center;
}
/* Read-only — render as plain text, matching the .kv-list read-only detail look
   (one read-only vocabulary across the app). No border / background / field
   padding: the label stays muted on top, the value reads as text (--text, 500),
   so a locked field looks the same whether it sits in a kv-list detail or inside
   an editable form.
   NB: driven by `.form-field.is-readonly`, NOT the bare `readonly` attribute —
   some fields (datepicker) use `readonly` only to block typing while still being
   an ACTIVE picker, so the attribute alone must not flatten them to text. */
/* Match the .kv-list detail spacing exactly: 2px label→value gap, no field inset. */
.form-field.is-readonly{ gap:var(--space-2); }
.form-field.is-readonly input:not([type=checkbox]):not([type=radio]),
.form-field.is-readonly select,
.form-field.is-readonly textarea{
  border:0;
  background:transparent;
  padding:0;
  color:var(--text);
  font-weight:500;
  cursor:default;
  appearance:none; -webkit-appearance:none; background-image:none;  /* kill select chevron */
}
.form-field.is-readonly textarea{ resize:none; min-height:0; }
.form-field.is-readonly input:focus,
.form-field.is-readonly select:focus,
.form-field.is-readonly textarea:focus{
  outline:none; border:0; box-shadow:none;
}
.form-field .help{
  font-size:var(--font-sm);
  color:var(--text-muted);
}
.form-field.with-action{
  position:relative;
}
.form-field.with-action .input-wrap{
  position:relative;
}
.form-field.with-action .input-wrap input{
  width:100%;
  padding-right:38px;   /* room for the reveal toggle, same as the date field */
}
/* Reveal (show/hide password) — same box + inset + icon size as the date/time
   .cal-toggle, so every in-field control reads identically across the system. */
.form-field.with-action .reveal{
  position:absolute;
  top:50%; right:var(--space-6);
  transform:translateY(-50%);
  display:grid; place-items:center;
  width:26px; height:26px; padding:0;
  background:transparent; border:0;
  color:var(--text-muted);
  border-radius:var(--radius-sm);
  cursor:pointer;
}
.form-field.with-action .reveal:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring) }
.form-field.with-action .reveal:hover{ background:var(--surface-hover); color:var(--text) }
.form-field.with-action .reveal svg{ width:16px; height:16px }
.form-field .input-wrap .generate{
  position:absolute;
  top:50%;
  right:36px;
  transform:translateY(-50%);
  font-size:var(--font-sm);
  color:var(--brand);
  font-weight:500;
}

/* Number stepper — a number input with −/+ buttons inside the field on the right
   (same "control inside the field" language as the date/password fields). The two
   buttons sit side by side. For counts / dimensions / temperatures / ordering.
   JS nudges the value respecting min/max/step. */
/* Nativní number spinner (OS šipky) skryjeme VŠUDE — vypadá nekonzistentně napříč
   prohlížeči. Krokování řeší buď .with-stepper (−/+), nebo se hodnota píše přímo.
   Platí i pro inline number v tabulkách (.cell-input / .attr-in). */
.form-field input[type=number],
input.cell-input[type=number],
input.attr-in[type=number]{ -moz-appearance:textfield; appearance:textfield; }
.form-field input[type=number]::-webkit-outer-spin-button,
.form-field input[type=number]::-webkit-inner-spin-button,
input.cell-input[type=number]::-webkit-outer-spin-button,
input.cell-input[type=number]::-webkit-inner-spin-button,
input.attr-in[type=number]::-webkit-outer-spin-button,
input.attr-in[type=number]::-webkit-inner-spin-button{ -webkit-appearance:none; margin:0 }
.form-field.with-stepper .input-wrap,
.cell-stepper.with-stepper .input-wrap{ position:relative }
.form-field.with-stepper .input-wrap input,
.cell-stepper.with-stepper .input-wrap input{
  width:100%;
  padding-right:64px;   /* room for the two buttons */
}
.form-field.with-stepper .stepper-btns,
.cell-stepper.with-stepper .stepper-btns{
  position:absolute;
  top:50%; right:var(--space-6);
  transform:translateY(-50%);
  display:flex;
  gap:var(--space-2);
}
.form-field.with-stepper .stepper-btn,
.cell-stepper.with-stepper .stepper-btn{
  display:grid; place-items:center;
  width:26px; height:26px;
  font-size:var(--font-lg); line-height:1;   /* fixed glyph size — same in every state */
  border-radius:var(--radius-sm);
  background:transparent;   /* ghost — fill only on hover, like the calendar icon */
  color:var(--text-muted);
  cursor:pointer;
}
.form-field.with-stepper .stepper-btn:hover{ background:var(--surface-hover); color:var(--text) }
.form-field.with-stepper .stepper-btn:active{ background:var(--surface-active) }
.form-field.with-stepper .stepper-btn:focus-visible{ outline:none; box-shadow:0 0 0 2px var(--brand-ring-strong) }
/* Disabled stepper — input greys (shared rule) and the ± buttons go faint + inert. */
.form-field.with-stepper .input-wrap:has(input:disabled) .stepper-btn{
  color:var(--text-faint); cursor:not-allowed; pointer-events:none;
}

/* Date / datetime / time fields — a text input with an icon on the right. date +
   datetime open the calendar popup (datetime adds an HH:MM row); time is a plain
   HH:MM input normalised on blur. Own look (consistent + dark-friendly). JS in
   launcher.js. The three share one structure so they read as a set. */
.form-field.with-date .input-wrap,
.form-field.with-date-range .input-wrap,
.form-field.with-datetime .input-wrap,
.form-field.with-time .input-wrap{ position:relative }
.form-field.with-lock .input-wrap{ position:relative }
.form-field.with-date .input-wrap input,
.form-field.with-date-range .input-wrap input,
.form-field.with-datetime .input-wrap input,
.form-field.with-time .input-wrap input,
.form-field.with-lock .input-wrap input{ width:100%; padding-right:38px }
/* Zámek u atributu = signál read-only (needitovatelné pole). Jen dekorativní. */
.form-field.with-lock .cal-toggle{ position:absolute; top:50%; right:var(--space-6); transform:translateY(-50%); display:grid; place-items:center; width:26px; height:26px; color:var(--text-faint); pointer-events:none; }
.form-field.with-date .cal-toggle,
.form-field.with-date-range .cal-toggle,
.form-field.with-datetime .cal-toggle,
.form-field.with-time .cal-toggle{
  position:absolute;
  top:50%; right:var(--space-6);   /* match the ~6px vertical inset → even margin all round */
  transform:translateY(-50%);
  display:grid; place-items:center;
  width:26px; height:26px;
  color:var(--text-muted);
  border-radius:var(--radius-sm);
  cursor:pointer;
}
.form-field.with-date .cal-toggle:hover,
.form-field.with-date-range .cal-toggle:hover,
.form-field.with-datetime .cal-toggle:hover,
.form-field.with-time .cal-toggle:hover{ background:var(--surface-hover); color:var(--text) }
/* Disabled date/time field — icon greys + goes inert (input greys via shared rule). */
.form-field.with-date .input-wrap:has(input:disabled) .cal-toggle,
.form-field.with-datetime .input-wrap:has(input:disabled) .cal-toggle,
.form-field.with-time .input-wrap:has(input:disabled) .cal-toggle{
  color:var(--text-faint); cursor:not-allowed; pointer-events:none;
}
/* Read-only date/time (`.is-readonly`) — value renders as plain text, so the
   calendar icon has no meaning: hide it and drop the padding it reserved.
   (Bare `readonly` is NOT enough — the datepicker uses it just to block typing.) */
.form-field.with-date.is-readonly .cal-toggle,
.form-field.with-datetime.is-readonly .cal-toggle,
.form-field.with-time.is-readonly .cal-toggle{ display:none; }
.form-field.with-date.is-readonly .input-wrap input,
.form-field.with-datetime.is-readonly .input-wrap input,
.form-field.with-time.is-readonly .input-wrap input{ padding-right:0; }

/* Calendar popup — appended to <body>, positioned under the field via JS. */
/* Sloupec Zóny (Skladová místa): klikací počet → popover s mini-tabulkou zón. */
.zones-count{
  display:inline-flex; align-items:center; gap:var(--space-4);
  padding:2px var(--space-10) 2px var(--space-8);
  border-radius:var(--radius-pill);
  background:var(--surface-active);
  color:var(--text);
  font-size:var(--font-sm); font-weight:600;
  line-height:1.4;          /* shodná výška/padding se .status → chipy stejně vysoké */
  cursor:pointer; border:0;
  transition:.12s ease;
}
.zones-count:hover{ background:var(--brand-soft); color:var(--brand) }
.zones-count svg{ width:13px; height:13px; opacity:.7 }
.zones-count.is-zero{ background:none; color:var(--text-faint); cursor:default; font-weight:400; padding-left:0 }
.zones-pop{
  position:fixed;
  z-index:200;
  width:280px;
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius);
  box-shadow:var(--shadow-pop);
  padding:var(--space-4);
  display:none;
}
.zones-pop.open{ display:block }
.zones-pop-head{
  padding:var(--space-8) var(--space-10) var(--space-6);
  font-size:var(--font-sm); font-weight:600; color:var(--text);
}
.zones-pop-head .text-faint{ color:var(--text-faint); font-weight:500; }
/* Popover „Použito uživateli" u Rolí — řádek = malý avatar + jméno.
   Sdílí .zones-pop kontejner; jen obsah buňky je avatar+jméno. */
.role-users-pop td{ padding:var(--space-6) var(--space-10); border-bottom:1px solid var(--divider); }
.role-users-pop tr:last-child td{ border-bottom:0 }
.role-users-pop .ru-cell{ display:flex; align-items:center; gap:var(--space-8); white-space:nowrap; }
.role-users-pop .av{
  width:24px; height:24px; flex:none;
  border-radius:50%;
  display:grid; place-items:center;
  font-size:var(--font-xs); font-weight:600;
  color:var(--on-accent);
}
.zones-pop table{ width:100%; border-collapse:collapse }
.zones-pop th{
  text-align:left; padding:var(--space-4) var(--space-10);
  font-size:var(--font-xs); font-weight:600; text-transform:uppercase;
  letter-spacing:.04em; color:var(--text-faint);
  border-bottom:1px solid var(--divider);
}
.zones-pop td{ padding:var(--space-6) var(--space-10); font-size:var(--font-sm); color:var(--text) }
.zones-pop th.ta-center, .zones-pop td.ta-center{ text-align:center }
.zones-pop tbody tr + tr td{ border-top:1px solid var(--divider) }

.calendar-pop{
  position:fixed;
  z-index:200;
  width:260px;
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius);
  box-shadow:var(--shadow-pop);
  padding:var(--space-10);
  display:none;
}
.calendar-pop.open{ display:block }
.calendar-pop .cal-head{
  display:flex; align-items:center; justify-content:space-between;
  margin-bottom:var(--space-8);
}
.calendar-pop .cal-title{ font-size:var(--font-md); font-weight:600; color:var(--text) }
/* The month·year title doubles as a button that opens the year picker. */
.calendar-pop button.cal-title{
  border:0; background:transparent; cursor:pointer;
  padding:var(--space-4) var(--space-8);
  border-radius:var(--radius-sm);
}
.calendar-pop button.cal-title:hover{ background:var(--surface-hover) }
.calendar-pop button.cal-title:focus-visible{ outline:none; box-shadow:0 0 0 2px var(--brand-ring-strong) }
.calendar-pop .cal-nav{
  width:28px; height:28px;
  display:grid; place-items:center;
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface);
  color:var(--text-muted);
  cursor:pointer;
}
.calendar-pop .cal-nav:hover{ background:var(--surface-hover); color:var(--text) }
.calendar-pop .cal-grid{
  display:grid;
  grid-template-columns:repeat(7, 1fr);
  gap:2px;
}
.calendar-pop .cal-dow{
  font-size:var(--font-xs);
  font-weight:600;
  color:var(--text-faint);
  text-align:center;
  padding:var(--space-4) 0;
}
.calendar-pop .cal-day{
  aspect-ratio:1;
  display:grid; place-items:center;
  font-size:var(--font-sm);
  color:var(--text);
  border-radius:var(--radius-sm);
  cursor:pointer;
  border:0; background:transparent;
}
.calendar-pop .cal-day:hover{ background:var(--surface-hover) }
.calendar-pop .cal-day.is-other{ color:var(--text-faint) }
.calendar-pop .cal-day.is-today{ box-shadow:inset 0 0 0 1px var(--border-strong) }
.calendar-pop .cal-day.is-selected{ background:var(--brand); color:var(--on-accent) }
/* Range režim: dny mezi začátkem a koncem dostanou jemné pozadí; krajní dny
   zůstanou plné (.is-selected). Souvislý pruh bez mezer (čtvercové vnitřní rohy). */
.calendar-pop .cal-day.is-in-range{ background:var(--brand-soft); color:var(--brand-dark); border-radius:0 }
.calendar-pop .cal-day.is-range-start{ border-top-right-radius:0; border-bottom-right-radius:0 }
.calendar-pop .cal-day.is-range-end{ border-top-left-radius:0; border-bottom-left-radius:0 }
.calendar-pop .cal-day:focus-visible{ outline:none; box-shadow:0 0 0 2px var(--brand-ring-strong) }
/* Year picker grid — 4×3 years, reuses the day-cell look. */
.calendar-pop .cal-years{
  display:grid;
  grid-template-columns:repeat(3, 1fr);
  gap:var(--space-4);
}
.calendar-pop .cal-year-cell{
  padding:var(--space-8) 0;
  display:grid; place-items:center;
  font-size:var(--font-sm);
  color:var(--text);
  border-radius:var(--radius-sm);
  cursor:pointer;
  border:0; background:transparent;
}
.calendar-pop .cal-year-cell:hover{ background:var(--surface-hover) }
.calendar-pop .cal-year-cell.is-today{ box-shadow:inset 0 0 0 1px var(--border-strong) }
.calendar-pop .cal-year-cell.is-selected{ background:var(--brand); color:var(--on-accent) }
.calendar-pop .cal-year-cell:focus-visible{ outline:none; box-shadow:0 0 0 2px var(--brand-ring-strong) }
/* Time row in a datetime popup — HH:MM under the calendar grid. */
.calendar-pop .cal-time{
  display:flex; align-items:center; justify-content:space-between;
  margin-top:var(--space-8);
  padding-top:var(--space-8);
  border-top:1px solid var(--border);
}
.calendar-pop .cal-time-label{ font-size:var(--font-sm); font-weight:600; color:var(--text-muted) }
.calendar-pop .cal-time-input{
  width:72px;
  text-align:center;
  padding:var(--space-6) var(--space-8);
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface);
  color:var(--text);
  font-size:var(--font-md);
  font-variant-numeric:tabular-nums;
}
.calendar-pop .cal-time-input:focus-visible{ outline:none; border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-ring) }

/* Time popover — two scrollable columns (hours / minutes). Shares .calendar-pop
   for the floating frame; .is-time swaps the body to the columns. */
.calendar-pop.is-time{ width:160px; padding:var(--space-8) }
.calendar-pop .time-cols{ display:flex; gap:var(--space-6) }
.calendar-pop .time-col{
  flex:1;
  max-height:180px;
  overflow-y:auto;
  display:flex; flex-direction:column; gap:2px;
  scrollbar-width:thin;
}
.calendar-pop .time-col-label{
  font-size:var(--font-xs); font-weight:600; color:var(--text-faint);
  text-align:center; padding-bottom:var(--space-4);
  position:sticky; top:0; background:var(--surface-raised);
}
.calendar-pop .time-opt{
  padding:var(--space-6) 0;
  text-align:center;
  font-size:var(--font-sm);
  color:var(--text);
  border:0; background:transparent;
  border-radius:var(--radius-sm);
  cursor:pointer;
  font-variant-numeric:tabular-nums;
}
.calendar-pop .time-opt:hover{ background:var(--surface-hover) }
.calendar-pop .time-opt.is-selected{ background:var(--brand); color:var(--on-accent) }

/* "Hotovo" footer — confirms + closes a popup that stays open during editing
   (time, datetime). The date popup closes on day pick, so it has none. */
.calendar-pop .cal-done{
  display:block;
  width:100%;
  margin-top:var(--space-8);
  padding:var(--space-8);
  border-top:1px solid var(--border);
  background:transparent;
  color:var(--brand);
  font-size:var(--font-sm);
  font-weight:500;   /* unified brand action weight (cal-done / generate / Vybrat vše) */
  cursor:pointer;
  text-align:center;
}
.calendar-pop .cal-done:hover{ color:var(--brand-dark) }

/* Radio choice list — a labelled set of single-select options as full-width
   "cards". A system form control (dialogs, forms needing one-of-many). Built on
   the native <input type="radio">. */
.radio-group{ display:flex; flex-direction:column; gap:var(--space-8) }
/* Horizontal layout — options share the width and wrap when they don't fit
   (safe inside narrow modals/panels). Default (no modifier) stays vertical. */
.radio-group--horizontal{ flex-direction:row; flex-wrap:wrap }
.radio-group--horizontal .radio-row{ flex:1 1 0; min-width:140px }
.radio-row{
  display:flex;
  align-items:center;
  gap:var(--space-10);
  padding:var(--space-10) var(--space-12);
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  cursor:pointer;
  font-size:var(--font-md);
  font-weight:400;   /* option text, not a bold field caption */
  color:var(--text);
}
.radio-row:hover{ background:var(--surface-hover) }
.radio-row:has(input:checked){ border-color:var(--brand); background:var(--brand-soft) }
/* Custom radio (not native accent-color) — so it keeps the brand dot in the
   disabled state, matching the custom checkbox. Browsers grey out a native
   disabled radio's accent regardless, which read inconsistently next to it. */
.radio-row input{
  appearance:none; -webkit-appearance:none;
  width:18px; height:18px; flex-shrink:0; margin:0;
  border:1.5px solid var(--border-strong); border-radius:50%;
  background:var(--surface); cursor:pointer;
  display:inline-grid; place-items:center; transition:.14s ease;
}
.radio-row input:hover{ border-color:var(--brand) }
.radio-row input:checked{ border-color:var(--brand) }
.radio-row input:checked::after{
  content:''; width:10px; height:10px; border-radius:50%; background:var(--brand);
}
.radio-row input:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring) }
/* Disabled radio row — off: faint text, no-go cursor, no hover lift. The dot
   keeps the brand colour, just dimmed (opacity) — exactly like the checkbox. */
.radio-row:has(input:disabled){
  cursor:not-allowed;
  color:var(--text-faint);
  background:var(--surface-muted);
  border-color:var(--border);
}
.radio-row:has(input:disabled):hover{ background:var(--surface-muted) }
.radio-row input:disabled{ cursor:not-allowed; opacity:.5 }
.radio-row input:disabled:hover{ border-color:var(--border-strong) }

.password-meter{
  display:flex;
  gap:var(--space-4);
  margin-top:var(--space-6);
}
.password-meter span{
  flex:1;
  height:4px;
  border-radius:var(--radius-pill);
  background:var(--border);
}
.password-meter span.on-weak{ background:var(--danger) }
.password-meter span.on-med{ background:var(--warning) }
.password-meter span.on-strong{ background:var(--success) }
.password-rules{
  display:flex;
  flex-wrap:wrap;
  gap:var(--space-10);
  margin-top:var(--space-6);
  font-size:var(--font-sm);
  color:var(--text-muted);
}
.password-rules .rule.ok{ color:var(--success) }
.password-rules .rule.ok::before{ content:"✓ "; font-weight:700 }
.password-rules .rule::before{ content:"○ "; opacity:.5 }


/* Tabs */
.tabs{
  display:flex;
  gap:var(--space-4);
  border-bottom:1px solid var(--border);
  margin-bottom:var(--space-20);
  padding:0 var(--space-4);
}
.tabs .tab{
  padding:var(--space-10) var(--space-16);
  font-size:var(--font-md);
  font-weight:500;
  color:var(--text-muted);
  border-bottom:2px solid transparent;
  margin-bottom:-1px;
  transition:.16s ease;
  display:inline-flex;
  align-items:center;
  gap:var(--space-8);
}
/* inline-flex beats UA [hidden] — restore it so a tab can be hidden per context. */
.tabs .tab[hidden]{ display:none; }
.tabs .tab:hover{ color:var(--text) }
.tabs .tab.active{
  color:var(--brand);   /* same blue as the underline — readable in dark */
  font-weight:600;
  border-bottom-color:var(--brand);
}
.tabs .tab .count{
  background:var(--brand-soft);
  color:var(--brand-dark);
  padding:1px var(--space-8);
  border-radius:var(--radius-pill);
  font-size:var(--font-xs);
  font-weight:700;
}
.tabs .tab.active .count{
  background:var(--brand);
  color:var(--on-accent);
}
/* Krokový stepper (.tabs.step-tabs) — číslo kroku v kroužku před názvem.
   Neaktivní krok = tlumený kroužek, aktivní = brand. */
.step-tabs .step-num{
  display:inline-grid; place-items:center;
  width:22px; height:22px; flex:none;
  border-radius:50%;
  background:var(--surface-muted);
  color:var(--text-muted);
  font-size:var(--font-sm); font-weight:700;
}
.step-tabs .tab.active .step-num{ background:var(--brand); color:var(--on-accent); }


/* -------------------------------------------------------------------------
   Permission accordion (Edit role)
   ------------------------------------------------------------------------- */
.perm-list{
  display:flex;
  flex-direction:column;
  gap:var(--space-10);
}
.perm-group{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  overflow:hidden;
  transition:.16s ease;
}
.perm-group.open{ border-color:var(--brand-soft) }
.perm-group-head{
  display:flex;
  align-items:center;
  gap:var(--space-14);
  padding:var(--space-14) var(--space-18);
  cursor:pointer;
  transition:.14s ease;
}
.perm-group-head:hover{ background:var(--surface-hover) }
.perm-group.open .perm-group-head{ background:var(--surface-alt) }
/* Master checkbox for the whole group (tri-state: empty / indeterminate = some
   on / checked = all on). Reuses the shared .checkbox; group state classes drive
   its appearance so the markup can stay a styled <div role="checkbox">. */
/* The master checkbox is its own click target (toggle the whole group); clicks
   elsewhere on the head collapse/expand. Give it a pointer + hit affordance. */
.perm-group-head .checkbox{ cursor:pointer }
.perm-group.partial .perm-group-head .checkbox{
  background:var(--brand); border-color:var(--brand);
}
.perm-group.partial .perm-group-head .checkbox::after{
  content:""; width:10px; height:2px; background:var(--on-accent); border-radius:1px;
}
.perm-group.all-on .perm-group-head .checkbox{
  background:var(--brand); border-color:var(--brand);
}
.perm-group.all-on .perm-group-head .checkbox::after{
  content:""; width:10px; height:10px;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='white'%3E%3Cpath d='M13.485 4.515a1 1 0 0 1 0 1.414l-6.364 6.364a1 1 0 0 1-1.414 0L2.515 8.95a1 1 0 1 1 1.414-1.414l2.485 2.485 5.657-5.657a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E") center/contain no-repeat;
}
/* Title stacked above its description (was side-by-side). Takes the leftover
   width and WRAPS — so the counter/chevron (.meta) always render in full. */
.perm-group-head .ptitle{
  flex:1; min-width:0;
  display:flex;
  flex-direction:column;
  gap:var(--space-2);
}
.perm-group-head .title{
  font-size:var(--font-md);
  font-weight:700;
  color:var(--text);
}
.perm-group-head .desc{
  font-size:var(--font-sm);
  color:var(--text-muted);
  font-weight:400;
  line-height:1.4;
}
/* Counter + chevron — priority cluster: never shrinks, never wraps, so "0 / 5"
   stays whole even when the title text is long (the title wraps instead). */
.perm-group-head .meta{
  margin-left:auto;
  flex:none;
  display:flex;
  align-items:center;
  gap:var(--space-14);
}
.perm-group-head .counter{
  font-size:var(--font-sm);
  color:var(--text-muted);
  font-weight:500;
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
}
.perm-group-head .counter strong{
  color:var(--text);
  font-weight:700;
}
.perm-group-head .all-link{
  font-size:var(--font-sm);
  color:var(--brand);
  font-weight:500;
}
.perm-group-head .all-link:hover{ color:var(--brand-dark) }
.perm-group-head .chev{
  color:var(--text-faint);
  transition:transform .18s ease;
}
.perm-group.open .perm-group-head .chev{ transform:rotate(180deg) }

.perm-group-body{
  display:none;
  border-top:1px solid var(--divider);
  padding:var(--space-6) 0;
}
.perm-group.open .perm-group-body{ display:block }

.perm-row{
  display:flex;
  align-items:flex-start;       /* checkbox aligns to the title line */
  gap:var(--space-12);
  padding:var(--space-10) var(--space-18);            /* checkbox aligns to the group-head checkbox (same left axis) */
  transition:.12s ease;
  cursor:pointer;
}
.perm-row:hover{ background:var(--surface-hover) }
/* The shared .checkbox handles the box; group-row state drives :checked via the
   .on class (markup keeps a styled <div role="checkbox"> for the prototype). */
.perm-row .checkbox{ margin-top:1px; pointer-events:none }
.perm-row.on .checkbox{ background:var(--brand); border-color:var(--brand) }
.perm-row.on .checkbox::after{
  content:""; width:10px; height:10px;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='white'%3E%3Cpath d='M13.485 4.515a1 1 0 0 1 0 1.414l-6.364 6.364a1 1 0 0 1-1.414 0L2.515 8.95a1 1 0 1 1 1.414-1.414l2.485 2.485 5.657-5.657a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E") center/contain no-repeat;
}
.perm-row .label{
  flex:1;
  display:flex;
  flex-direction:column;
  gap:var(--space-2);
}
.perm-row .label .perm-name{
  font-size:var(--font-md);
  color:var(--text);
  font-weight:500;
}
.perm-row .label .perm-desc{
  font-size:var(--font-sm);
  color:var(--text-muted);
  line-height:1.4;
}
.perm-row .changed-dot{
  width:6px; height:6px;
  border-radius:50%;
  background:var(--brand);
  box-shadow:0 0 0 3px rgba(59,130,246,.18);
  margin-top:var(--space-6);
  flex-shrink:0;
}


/* -------------------------------------------------------------------------
   Roles panel (Edit user - right column)
   ------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
   Multiselect combobox (.ms-combo) — a form field that shows the selection as
   removable chips and opens a searchable, checkable list (reuses .search-row /
   .filter-row / .role-list). Used e.g. for picking inventory locations.
   In read-only context just render the .ms-chips (no control / no dropdown).
   ------------------------------------------------------------------------- */
.ms-combo{ position:relative; }
.ms-control{
  display:flex; flex-wrap:nowrap; align-items:center; gap:var(--space-6);
  min-height:38px; padding:var(--space-6) var(--space-10);
  border:1px solid var(--border); border-radius:var(--radius-sm);
  background:var(--surface); cursor:pointer; transition:.16s ease;
}
/* .ms-chips uvnitř řeší vlastní wrap (chips/count varianta); caret drží nowrap
   na .ms-control VŽDY vedle. .ms-chip nezalamuje text (jinak roste výška řádku). */
/* Disabled — off: greyed, no-go cursor, can't open. Add .disabled on .ms-combo.
   border-color restated explicitly to match the other disabled fields' declaration. */
.ms-combo.disabled .ms-control{
  background:var(--surface-muted); border-color:var(--border); cursor:not-allowed; pointer-events:none;
}
.ms-combo.disabled .ms-placeholder,
.ms-combo.disabled .ms-caret{ color:var(--text-faint); }
.ms-combo.open .ms-control{ border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-ring); }
/* flex-basis:0 (ne auto) → chips vezmou jen dostupné místo a NEVYTLAČÍ caret pod sebe
   (jinak se .ms-control zalomí na 2 řádky i když chips jsou na jednom). */
.ms-chips{ display:flex; flex-wrap:wrap; gap:var(--space-6); flex:1 1 0; min-width:0; }
/* summary:'overflow' — chips na JEDEN řádek (přebytek řeší JS „+N"). */
.ms-chips.ms-chips--nowrap{ flex-wrap:nowrap; overflow:hidden; }
/* Dočasný stav při měření šířek (JS collapseOverflow) — vždy nowrap. */
.ms-chips.ms-chips--measuring{ flex-wrap:nowrap; }
.ms-chip{
  display:inline-flex; align-items:center; gap:var(--space-6); white-space:nowrap;
  padding:2px var(--space-6) 2px var(--space-8);
  background:var(--surface-muted); border:1px solid var(--border);
  border-radius:var(--radius-pill); font-size:var(--font-sm); color:var(--text);
}
.ms-chip .code{ color:var(--text-muted); font-weight:600; }
/* summary:'overflow' varianta — pilulka „+N" pro chips, které se nevešly na řádek.
   Klikací (otevře panel), vizuálně odlišená (brand tint). */
.ms-chip-more{
  background:var(--brand-soft); border-color:var(--brand-ring-strong);
  color:var(--brand-dark); font-weight:600; cursor:pointer; user-select:none;
}
.ms-chip-more:hover{ background:var(--brand-ring); }
/* summary:'count' varianta — kompaktní „N vybraných" místo pilulek (dlouhé seznamy). */
/* .ms-count vyplní celou šířku .ms-chips (flex:1), aby křížek „× vymazat vše"
   šel k pravému kraji pole (margin-left:auto) vedle caretu — stejné zarovnání
   jako .ss-clear u single-selectu. */
.ms-count{ display:flex; flex:1; align-items:center; gap:var(--space-8); font-size:var(--font-md); color:var(--text); }
.ms-count-clear{ display:inline-flex; margin-left:auto; border:0; background:none; color:var(--text-faint); cursor:pointer; padding:0; line-height:0; border-radius:50%; }
.ms-count-clear:hover{ color:var(--danger); }
.ms-count-clear svg{ width:14px; height:14px; }
.ms-chip button{
  display:inline-flex; border:0; background:none; color:var(--text-faint);
  cursor:pointer; padding:0; line-height:0; border-radius:50%;
}
.ms-chip button:hover{ color:var(--danger); }
.ms-chip button svg{ width:13px; height:13px; }
/* Placeholder text in the field — matches the native input placeholder colour
   uses the --text-faint token (placeholder/label colour, flips in dark). Not selectable,
   so a click anywhere (incl. on the text) opens the panel. */
.ms-placeholder{ color:var(--text-faint); font-size:var(--font-md); user-select:none; pointer-events:none; }
.ms-caret{ margin-left:auto; color:var(--text-faint); display:flex; flex-shrink:0; }
.ms-caret svg{ width:16px; height:16px; }
/* Dropdown panel. max-height nastavuje JS podle místa ve viewportu (positionPanel);
   panel je flex-column, aby search+filtr zůstaly nahoře a scrolloval jen seznam. */
.ms-panel{
  position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:40;
  background:var(--surface-raised); border:1px solid var(--border);
  border-radius:var(--radius-sm); box-shadow:var(--shadow-pop);
  display:none; overflow:hidden;
}
.ms-combo.open .ms-panel{ display:flex; flex-direction:column; max-height:min(360px, 60vh); }
/* Panel otevřený NAHORU (dole nebylo místo — např. modal nízko u kraje obrazovky). */
.ms-panel.ms-panel--up{ top:auto; bottom:calc(100% + 4px); }
/* The multiselect dropdown panel (search field, filter chips, role-item rows).
   Panel has NO side padding so the list rows + their dividers reach the edges;
   search and filter rows pad themselves. (Was historically shared with a
   now-removed `.roles-panel`; these are `.ms-panel`-only.) */
.ms-panel .search-row{ margin:var(--space-12) var(--space-14) var(--space-10); }   /* layout only; input styling from .search base */
/* Filter row: just the chips ("Vybrat vše" moved into the list as its first row). */
/* "Vybrat vše" as the first list row — a normal role-item with a tri-state
   checkbox, set apart from the data rows by a divider below it. */
.ms-panel .role-item.ms-selall-row{
  border-bottom:1px solid var(--divider);
}
.ms-panel .role-item.ms-selall-row .name{
  font-weight:500; color:var(--brand);   /* unified brand action weight */
}
/* Seznam scrolluje a vezme zbytek výšky panelu (flex:1, min-height:0). Výšku panelu
   řídí .ms-panel max-height (CSS fallback + JS positionPanel podle viewportu).
   Search+filtr zůstávají fixní nahoře. */
.ms-panel .role-list,
.ms-panel .tag-list,
.ms-panel .ms-list{ overflow-y:auto; flex:1 1 auto; min-height:0; }
.ms-panel .search-row,
.ms-panel .filter-row{ flex:none; }
.ms-panel .ms-empty{ padding:var(--space-14); color:var(--text-muted); font-size:var(--font-sm); text-align:center; }

/* Search rows carry the shared .search base class in markup (input/icon/focus
   from .search); only LAYOUT remains here. */
.ms-panel .filter-row{
  display:flex;
  flex-wrap:wrap;            /* narrow panel: chips wrap instead of clipping past the edge */
  gap:var(--space-6);
  padding:var(--space-10) var(--space-16);
  border-bottom:1px solid var(--divider);
}
.ms-panel .filter-row .chip{
  padding:var(--space-4) var(--space-10);
  border-radius:var(--radius-pill);
  background:var(--surface-alt);
  border:1px solid var(--border);
  font-size:var(--font-xs);
  font-weight:600;
  color:var(--text-muted);
  cursor:pointer;
}
.ms-panel .filter-row .chip.active{
  background:var(--brand-soft);
  color:var(--brand-dark);
  border-color:var(--brand-ring-strong);
}
.ms-panel .role-item{
  display:flex;
  align-items:center;
  gap:var(--space-12);
  padding:var(--space-10) var(--space-16);
  cursor:pointer;
  transition:.12s ease;
  border-bottom:1px solid var(--divider);
}
.ms-panel .role-item:last-child{ border-bottom:0 }
.ms-panel .role-item:hover{ background:var(--surface-hover) }
.ms-panel .role-item.checked{ background:var(--surface-active) }
/* Hlavička skupiny (Role / Uživatelé) uvnitř ms-listu — když initMsCombo dostane opts.group. */
.ms-panel .ms-group-head{
  padding:var(--space-8) var(--space-16) var(--space-4);
  font-size:var(--font-xs);
  font-weight:600;
  letter-spacing:.04em;
  text-transform:uppercase;
  color:var(--text-faint);
  background:var(--surface-alt);
  border-bottom:1px solid var(--divider);
}
/* Ikona role/uživatele před názvem řádku. */
.ms-panel .ms-item-ico{ display:inline-flex; vertical-align:-2px; margin-right:var(--space-6); color:var(--text-muted); }
.ms-panel .ms-item-ico svg{ width:14px; height:14px; }
.ms-panel .role-item .meta{
  display:flex;
  flex-direction:column;
  gap:1px;
}
.ms-panel .role-item .name{
  font-size:var(--font-md);
  font-weight:400;   /* list items use the normal weight; hierarchy is carried by the muted second line */
  color:var(--text);
}
.ms-panel .role-item .perm-count{
  font-size:var(--font-xs);
  color:var(--text-muted);
}

/* -------------------------------------------------------------------------
   Single-select combobox with search (.select-search) — one field, one value,
   a search-filtered dropdown. For pick-one-from-many where the list is long
   enough to need typing (e.g. assign a code to one asset). Sibling of .ms-combo
   (which is multi); shares the control/panel shape + tokens. JS in components.js
   reads <option> children + a `data-search-select` host. Parts: .ss-control
   (value/placeholder + caret) · .ss-panel (search + .ss-option rows). A selected
   value shows a small ✕ to clear (back to unassigned).
   ------------------------------------------------------------------------- */
.select-search{ position:relative; }
.ss-control{
  display:flex; align-items:center; gap:var(--space-8);
  min-height:38px; padding:var(--space-6) var(--space-10);
  border:1px solid var(--border); border-radius:var(--radius-sm);
  background:var(--surface); cursor:pointer; font-size:var(--font-md);
  transition:.16s ease;
}
.select-search.open .ss-control{ border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-ring); }
.ss-value{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--text); }
.ss-value .code{ color:var(--text-muted); font-weight:600; margin-left:var(--space-6); }
.ss-value.is-empty{ color:var(--text-faint); }
.ss-clear{
  display:none; border:0; background:none; color:var(--text-faint); cursor:pointer;
  padding:0; line-height:0; border-radius:50%; flex-shrink:0;
}
.ss-clear svg{ width:14px; height:14px; }
.ss-clear:hover{ color:var(--danger); }
.select-search.has-value .ss-clear{ display:inline-flex; }
.ss-caret{ color:var(--text-faint); display:flex; flex-shrink:0; }
.ss-caret svg{ width:16px; height:16px; }
/* Disabled — matches the native input/select disabled look (muted bg, faint text,
   no-go cursor, can't interact). Locked value, no clear (✕ hidden). */
.select-search.disabled .ss-control{ background:var(--surface-muted); border-color:var(--border); cursor:not-allowed; pointer-events:none; color:var(--text-faint); }
.select-search.disabled .ss-value,
.select-search.disabled .ss-value .code{ color:var(--text-faint); }   /* code fades with the value too */
.select-search.disabled .ss-caret{ color:var(--text-faint); }
.select-search.disabled.has-value .ss-clear{ display:none; }
/* Dropdown panel — same shape as .ms-panel. */
.ss-panel{
  position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:40;
  background:var(--surface-raised); border:1px solid var(--border);
  border-radius:var(--radius-sm); box-shadow:var(--shadow-pop);
  display:none; overflow:hidden;
}
.select-search.open .ss-panel{ display:block; }
.ss-panel .search-row{ margin:var(--space-12) var(--space-14) var(--space-10); }
.ss-list{ max-height:260px; overflow-y:auto; }
/* Option rows match the multiselect .role-item convention (size / gap / padding). */
.ss-option{
  display:flex; align-items:center; gap:var(--space-12);
  padding:var(--space-10) var(--space-16); cursor:pointer;
  border-top:1px solid var(--divider);
}
.ss-option:first-child{ border-top:0; }
.ss-option:hover{ background:var(--surface-hover); }
.ss-option.selected{ background:var(--surface-active); }
.ss-option .name{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--text); font-size:var(--font-md); }
.ss-option .code{ color:var(--text-muted); font-weight:600; font-size:var(--font-sm); flex-shrink:0; }
.ss-empty{ padding:var(--space-16); color:var(--text-muted); font-size:var(--font-md); text-align:center; }

/* ===== Custom dropdown (.select-menu) — jednoduchý výběr bez searche =========
   Progresivní enhancement nativního <select class="select-menu">. Vizuálně
   shodné s .select-search (jen bez search pole a bez clear). Nativní <select>
   zůstává v DOM skrytý jako zdroj pravdy (select-menu.js ho zrcadlí). */
.select-menu-host{ position:relative; }
.select-menu-host .sm-native{
  position:absolute; width:1px; height:1px; opacity:0; pointer-events:none;
  clip:rect(0 0 0 0); overflow:hidden; margin:0; padding:0; border:0;
}
.sm-control{
  display:flex; align-items:center; gap:var(--space-8); width:100%;
  min-height:38px; padding:var(--space-6) var(--space-10);
  border:1px solid var(--border); border-radius:var(--radius-sm);
  background:var(--surface); cursor:pointer; font-size:var(--font-md);
  color:var(--text); text-align:left; transition:.16s ease;
}
.select-menu-host.open .sm-control{ border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-ring); }
.sm-control:focus-visible{ outline:none; border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-ring); }
/* Kompaktní varianta — menší výška/font/padding. Sdílený `--sm` modifikátor
   (jako .search--sm / .attr-in--sm) pro husté kontexty: paginace, toolbary. */
.select-menu--sm .sm-control{ min-height:30px; padding:var(--space-4) var(--space-8); font-size:var(--font-sm); gap:var(--space-6); }
.select-menu--sm .sm-control .sm-caret{ width:14px; height:14px; }
.select-menu--sm .sm-option{ padding:var(--space-6) var(--space-10); font-size:var(--font-sm); }
.sm-value{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sm-value.is-empty{ color:var(--text-faint); }
.sm-caret{ color:var(--text-faint); display:flex; flex-shrink:0; transition:transform .16s ease; }
.sm-caret svg{ width:16px; height:16px; }
.select-menu-host.open .sm-caret{ transform:rotate(180deg); }
/* Disabled — stejný vzhled jako nativní select/combobox disabled. */
.select-menu-host.disabled .sm-control{ background:var(--surface-muted); border-color:var(--border); color:var(--text-faint); cursor:not-allowed; }
.select-menu-host.disabled .sm-caret{ color:var(--text-faint); }
/* Panel — shodný s .ss-panel. */
.sm-panel{
  position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:40;
  background:var(--surface-raised); border:1px solid var(--border);
  border-radius:var(--radius-sm); box-shadow:var(--shadow-pop);
  display:none; overflow:hidden; max-height:260px; overflow-y:auto;
}
.select-menu-host.open .sm-panel{ display:block; }
/* Když se pod controlem nevejde (např. paginace na konci stránky), panel se
   vyklopí NAHORU. Třídu .flip-up nastaví select-menu.js podle místa ve viewportu. */
.select-menu-host.flip-up .sm-panel{ top:auto; bottom:calc(100% + 4px); }
.sm-option{
  padding:var(--space-10) var(--space-16); cursor:pointer;
  border-top:1px solid var(--divider); color:var(--text); font-size:var(--font-md);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.sm-option:first-child{ border-top:0; }
.sm-option:hover,
.sm-option.active{ background:var(--surface-hover); }
.sm-option.selected{ background:var(--surface-active); }
.sm-option.is-disabled{ color:var(--text-faint); cursor:default; background:none; }

/* -------------------------------------------------------------------------
   Color picker (.color-picker) — form komponenta: pole + rozbalovací paleta.
   Sourozenec .select-search (stejný control/panel tvar). Hodnota = barva ze
   sdílené palety Tagů (data-tag-color). JS v color-picker.js (data-color-picker).
   Control: tečka barvy + název + ✕ + caret. Panel: swatch grid (16).
   ------------------------------------------------------------------------- */
.color-picker{ position:relative; }
.cp-control{
  display:flex; align-items:center; gap:var(--space-8);
  min-height:38px; padding:var(--space-6) var(--space-10);
  border:1px solid var(--border); border-radius:var(--radius-sm);
  background:var(--surface); cursor:pointer; font-size:var(--font-md);
  transition:.16s ease;
}
.color-picker.open .cp-control{ border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-ring); }
.cp-value{ flex:1; min-width:0; display:flex; align-items:center; gap:var(--space-8); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--text); }
.cp-value.is-empty{ color:var(--text-faint); }
/* Tečka barvy v poli (vybraná barva). Barva z --tag-<key>-dot. */
.cp-dot{ width:14px; height:14px; border-radius:50%; flex:none; background:var(--_dot, var(--tag-slate-dot)); }
.cp-dot[data-tag-color="slate"]{   --_dot:var(--tag-slate-dot) }
.cp-dot[data-tag-color="red"]{     --_dot:var(--tag-red-dot) }
.cp-dot[data-tag-color="orange"]{  --_dot:var(--tag-orange-dot) }
.cp-dot[data-tag-color="amber"]{   --_dot:var(--tag-amber-dot) }
.cp-dot[data-tag-color="lime"]{    --_dot:var(--tag-lime-dot) }
.cp-dot[data-tag-color="green"]{   --_dot:var(--tag-green-dot) }
.cp-dot[data-tag-color="emerald"]{ --_dot:var(--tag-emerald-dot) }
.cp-dot[data-tag-color="teal"]{    --_dot:var(--tag-teal-dot) }
.cp-dot[data-tag-color="cyan"]{    --_dot:var(--tag-cyan-dot) }
.cp-dot[data-tag-color="sky"]{     --_dot:var(--tag-sky-dot) }
.cp-dot[data-tag-color="blue"]{    --_dot:var(--tag-blue-dot) }
.cp-dot[data-tag-color="indigo"]{  --_dot:var(--tag-indigo-dot) }
.cp-dot[data-tag-color="violet"]{  --_dot:var(--tag-violet-dot) }
.cp-dot[data-tag-color="purple"]{  --_dot:var(--tag-purple-dot) }
.cp-dot[data-tag-color="fuchsia"]{ --_dot:var(--tag-fuchsia-dot) }
.cp-dot[data-tag-color="pink"]{    --_dot:var(--tag-pink-dot) }
.cp-dot[data-tag-color="rose"]{    --_dot:var(--tag-rose-dot) }
.cp-clear{
  display:none; border:0; background:none; color:var(--text-faint); cursor:pointer;
  padding:0; line-height:0; border-radius:50%; flex-shrink:0;
}
.cp-clear svg{ width:14px; height:14px; }
.cp-clear:hover{ color:var(--danger); }
.color-picker.has-value .cp-clear{ display:inline-flex; }
.cp-caret{ color:var(--text-faint); display:flex; flex-shrink:0; }
.cp-caret svg{ width:16px; height:16px; }
.color-picker.disabled .cp-control{ background:var(--surface-muted); border-color:var(--border); cursor:not-allowed; pointer-events:none; color:var(--text-faint); }
.color-picker.disabled .cp-caret{ color:var(--text-faint); }
.color-picker.disabled.has-value .cp-clear{ display:none; }
/* Panel se swatch gridem — stejný tvar jako .ss-panel. */
.cp-panel{
  position:absolute; left:0; top:calc(100% + 4px); z-index:40;
  background:var(--surface-raised); border:1px solid var(--border);
  border-radius:var(--radius-sm); box-shadow:var(--shadow-pop);
  display:none; padding:var(--space-12);
}
.color-picker.open .cp-panel{ display:block; }
/* Swatche reuse .tag-swatch look (kolečka, vybraný prstenec). */
.cp-swatches{ display:grid; grid-template-columns:repeat(6, 1fr); gap:var(--space-8); }
.cp-swatch{
  width:26px; height:26px; border-radius:50%; border:2px solid transparent;
  cursor:pointer; padding:0; position:relative;
  background:var(--_sw, var(--tag-slate-dot));
  transition:transform .1s ease;
}
.cp-swatch:hover{ transform:scale(1.08) }
.cp-swatch[data-tag-color="slate"]{   --_sw:var(--tag-slate-dot) }
.cp-swatch[data-tag-color="red"]{     --_sw:var(--tag-red-dot) }
.cp-swatch[data-tag-color="orange"]{  --_sw:var(--tag-orange-dot) }
.cp-swatch[data-tag-color="amber"]{   --_sw:var(--tag-amber-dot) }
.cp-swatch[data-tag-color="lime"]{    --_sw:var(--tag-lime-dot) }
.cp-swatch[data-tag-color="green"]{   --_sw:var(--tag-green-dot) }
.cp-swatch[data-tag-color="emerald"]{ --_sw:var(--tag-emerald-dot) }
.cp-swatch[data-tag-color="teal"]{    --_sw:var(--tag-teal-dot) }
.cp-swatch[data-tag-color="cyan"]{    --_sw:var(--tag-cyan-dot) }
.cp-swatch[data-tag-color="sky"]{     --_sw:var(--tag-sky-dot) }
.cp-swatch[data-tag-color="blue"]{    --_sw:var(--tag-blue-dot) }
.cp-swatch[data-tag-color="indigo"]{  --_sw:var(--tag-indigo-dot) }
.cp-swatch[data-tag-color="violet"]{  --_sw:var(--tag-violet-dot) }
.cp-swatch[data-tag-color="purple"]{  --_sw:var(--tag-purple-dot) }
.cp-swatch[data-tag-color="fuchsia"]{ --_sw:var(--tag-fuchsia-dot) }
.cp-swatch[data-tag-color="pink"]{    --_sw:var(--tag-pink-dot) }
.cp-swatch[data-tag-color="rose"]{    --_sw:var(--tag-rose-dot) }
.cp-swatch.selected{ box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--_sw); }
.cp-swatch.selected::after{
  content:""; position:absolute; inset:0; margin:auto;
  width:8px; height:8px; border-radius:50%; background:var(--surface);
}


/* -------------------------------------------------------------------------
   Sticky page footer (Save / Cancel)
   ------------------------------------------------------------------------- */
/* Floating save footer — a detached card (like the sidebar/drawer), inset from
   the window edges, rounded, bordered all round. Left edge starts past the
   sidebar + the shell gap so it lines up with the content. */
.page-footer{
  position:fixed;
  bottom:var(--floatbar-inset);
  left:calc(12px + var(--sidebar-w) + 12px + var(--floatbar-inset));
  right:calc(12px + var(--floatbar-inset));   /* +shell pad → symmetric to content */
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:var(--space-16);
  padding:var(--space-12) var(--space-12) var(--space-12) var(--space-16);   /* extra left padding for the status text */
  background:var(--page-footer-bg);
  backdrop-filter:saturate(160%) blur(8px);
  -webkit-backdrop-filter:saturate(160%) blur(8px);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  z-index:10;
  box-shadow:var(--shadow-pop);
}
/* Follow the collapsed sidebar (64px) so the footer's left edge tracks the grid. */
.shell.sidebar-collapsed ~ .page-footer{
  left:calc(12px + 64px + 12px + var(--floatbar-inset));
}
/* Record pager — step between sibling records without leaving the detail
   ("Vybraná položka 1 / 50"). Sits in the centre of the footer / detail head. */
.detail-pager{
  display:inline-flex;
  align-items:center;
  gap:var(--space-8);
  font-size:var(--font-sm);
  color:var(--text-muted);
  white-space:nowrap;
}
.detail-pager .pager-label{ font-weight:500 }
.detail-pager .pager-label strong{ color:var(--text); font-weight:600 }
.detail-pager button{
  width:28px; height:28px;
  display:grid; place-items:center;
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface);
  color:var(--text-muted);
  cursor:pointer;
}
.detail-pager button:hover{ background:var(--surface-hover); color:var(--text) }
.detail-pager button:disabled{ opacity:.4; cursor:default }
.detail-pager button:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring-strong) }
/* The fixed footer floats over the scrolling page body — reserve space at the
   bottom of the scroll area so the last content isn't hidden behind it.
   (~footer height 56px + its inset + a little breathing room.) */
body:has(.page-footer:not([hidden])) .page-body{
  /* Reserve the footer's ACTUAL height (set by components.js, kept in sync on
     resize) so the last content always clears it — even when the footer grows
     (substatus line) or wraps to two rows on a narrow viewport. The fallback
     covers the moment before the script measures. :not([hidden]) so a footer
     toggled off per state (inventory detail) reserves no space. */
  padding-bottom:calc(var(--floatbar-inset) + var(--page-footer-h, 72px) + var(--space-16));
}
.page-footer .status-msg{
  font-size:var(--font-md);
  color:var(--text-muted);
  display:flex;
  align-items:center;
  gap:var(--space-8);
  min-width:0;                /* let the text wrap/ellipsis instead of pushing buttons off */
}
.page-footer .status-msg .pulse{
  width:8px;
  height:8px;
  border-radius:50%;
  background:var(--warning);
  box-shadow:0 0 0 3px var(--warning-ring);
  flex:none;
}
/* Status text + optional secondary line ("Změny nejsou uložené"). The primary
   text flows inline (wraps on spaces); the substatus is a block on its own line,
   same size as the primary, set off by a small gap. */
.page-footer .status-msg .status-text{ min-width:0 }
.page-footer .status-msg .substatus{
  display:block;
  margin-top:var(--space-6);
  font-size:var(--font-md);
  color:var(--text-faint);
}
.page-footer .actions{
  display:flex;
  gap:var(--space-10);
  flex:none;
}
/* Left cluster: record stepper + status message sit together on the left. */
.page-footer .footer-left{
  display:flex;
  align-items:center;
  gap:var(--space-16);
}

/* Responsive: the footer reacts to ITS OWN width (sidebar collapse + the floating
   insets change it), not the window. Same graceful degradation as the bulk-bar:
   1) wide   → status text + full-label buttons, one row;
   2) narrow → buttons collapse to ICONS (labels hidden, icon + title remain);
   3) tiny   → status text takes its own row, the icon buttons drop below it.
   (An element can't @container-query itself, hence flex-wrap on the parent +
   flex-basis on the children rather than flipping the parent's flex-direction.) */
/* The footer is its own container; its CHILDREN query its width (an element can't
   @container-query itself, so we drive layout via the children + flex-wrap on the
   parent, never by flipping the parent's own flex-direction). */
.page-footer{ container-type:inline-size; flex-wrap:wrap }
/* Step 2 — collapse the action buttons to icon-only when space gets tight (one
   row still: the status text wraps within its own cell, the icon buttons hold
   their place on the right). */
@container (max-width:620px){
  .page-footer .actions .btn{ padding:var(--space-8); gap:0 }
  .page-footer .actions .btn .btn-label{ display:none }
}
/* Step 3 — even icon buttons + the status text don't fit on one line: two rows.
   The status takes the top row; the buttons get their labels back and stack UNDER
   each other at full width (stacked = room for text again). */
@container (max-width:400px){
  .page-footer .status-msg{ flex:1 1 100% }
  .page-footer .actions{
    flex:1 1 100%;
    flex-direction:column;
    align-items:stretch;
  }
  .page-footer .actions .btn{
    width:100%;
    justify-content:center;
    padding:var(--space-8) var(--space-14);   /* full padding again */
    gap:var(--space-8);
  }
  .page-footer .actions .btn .btn-label{ display:inline }   /* labels back */
}


/* -------------------------------------------------------------------------
   Avatar colors (deterministic)
   ------------------------------------------------------------------------- */
.avatar-blue{ background:var(--avatar-blue) }
.avatar-violet{ background:var(--avatar-violet) }
.avatar-pink{ background:var(--avatar-pink) }
.avatar-green{ background:var(--avatar-green) }
.avatar-amber{ background:var(--avatar-amber) }
.avatar-slate{ background:var(--text-faint) }   /* pozvaný / ještě neaktivní účet */
.avatar-rose{ background:var(--avatar-rose) }
/* Standalone avatar sizes (circle + centered white initials) — used outside the
   table, e.g. detail-panel head (md) and the edit-page title (lg). */
.avatar-md,
.avatar-lg{
  border-radius:50%;
  display:grid;
  place-items:center;
  color:var(--on-accent);
  font-weight:600;
  flex-shrink:0;
}
.avatar-md{ width:30px; height:30px; font-size:var(--font-sm) }
.avatar-lg{ width:36px; height:36px; font-size:var(--font-md) }
/* Ikonový avatar v brand tónu (kroužek s ikonou, ne iniciály) — např. hlavička
   pravého panelu u pravidel / tagů. */
.avatar--brand{ background:var(--brand-soft); color:var(--brand-dark); }
/* Extra-large avatar for the profile/settings header. */
.avatar-xl{
  width:72px; height:72px; border-radius:50%;
  display:grid; place-items:center;
  color:var(--on-accent); font-weight:600; font-size:var(--font-xl);
  flex-shrink:0;
}
/* Avatar editor row — disc + change / remove actions. */
.avatar-edit{ display:flex; align-items:center; gap:var(--space-16); margin-bottom:var(--space-20); }
.avatar-edit-actions{ display:flex; flex-direction:column; gap:var(--space-6); align-items:flex-start; }
.btn-link-muted{
  border:0; background:none; cursor:pointer; padding:0;
  color:var(--text-muted); font-size:var(--font-sm); font-weight:500;
}
.btn-link-muted:hover{ color:var(--danger); text-decoration:underline; }


/* -------------------------------------------------------------------------
   Empty state
   ------------------------------------------------------------------------- */
.empty-state{
  text-align:center;
  padding:48px var(--space-24);
  color:var(--text-muted);
}
.empty-state .icon{
  width:48px; height:48px;
  margin:0 auto var(--space-14);
  border-radius:50%;
  background:var(--surface-alt);
  display:grid;
  place-items:center;
  color:var(--text-faint);
}
.empty-state h3{ font-size:var(--font-md); color:var(--text); margin:0 0 var(--space-6); }
.empty-state p{ margin:0; }
/* Metový řádek v detailu (Datum vytvoření / Vytvořil apod.) — tichý, odsazený. */
.detail-meta{ margin-top:var(--space-20); font-size:var(--font-sm); color:var(--text-faint); }

/* Themed illustration for empty states — same vector language as the error pages
   (brand-monochrome stroke + a soft tinted backdrop disc), just calmer (no status
   accents — an empty state isn't an error). Injected by components.js from a
   shared scene map keyed by the container's id / data-illu. */
.empty-illustration{
  width:140px; height:100px;
  margin:0 auto var(--space-16);
  display:block; color:var(--brand);
}
.empty-illustration svg{ width:100%; height:100%; display:block; overflow:visible }
.empty-illustration .ill-tint{ fill:var(--brand-soft) }
.empty-illustration .ill-line{ stroke:var(--brand); fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round }
.empty-illustration .ill-fill{ fill:var(--brand) }
.empty-illustration .ill-faint{ stroke:var(--border-strong); fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round }


/* -------------------------------------------------------------------------
   Sidebar pinned section (persists across modules).
   Lives at the bottom of every module's contextual sidebar. Users pin 3-5
   most-used screens across the whole ERP. At 15+ modules this prevents
   waffle-fatigue for power users.
   ------------------------------------------------------------------------- */
.sidebar-pinned{
  margin-top:auto;
  padding-top:var(--space-14);
  border-top:1px solid var(--divider);
}
.sidebar-pinned .nav-item .ic{
  width:18px; height:18px;
  display:grid;
  place-items:center;
  font-size:13px;
  border-radius:var(--radius-xs);
  flex-shrink:0;
}
.sidebar-pinned .nav-section{
  display:flex;
  align-items:center;
  justify-content:space-between;
}
.sidebar-pinned .nav-section .add-pin{
  width:22px; height:22px;
  border-radius:var(--radius-xs);
  display:grid;
  place-items:center;
  color:var(--text-faint);
  cursor:pointer;
}
.sidebar-pinned .nav-section .add-pin:hover{
  background:var(--surface-hover);
  color:var(--text);
}


/* -------------------------------------------------------------------------
   Waffle launcher button (in topbar)
   ------------------------------------------------------------------------- */
.waffle-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:36px; height:36px;
  border-radius:var(--radius-sm);
  color:var(--text-muted);
  transition:.14s ease;
}
.waffle-btn:hover{ background:var(--surface-hover); color:var(--text) }
.waffle-btn.active{ background:var(--brand-soft); color:var(--brand-dark) }


/* -------------------------------------------------------------------------
   Waffle launcher overlay (full-screen module picker)
   ------------------------------------------------------------------------- */
.launcher{
  position:fixed;
  inset:0;
  z-index:200;
  background:var(--backdrop);   /* match modal backdrop */
  backdrop-filter:blur(4px);
  -webkit-backdrop-filter:blur(4px);
  display:none;
  align-items:flex-start;
  justify-content:center;
  padding-top:80px;
}
.launcher.open{ display:flex }
.launcher .launcher-panel{ /* large overlay — uses --radius-lg below */
  width:min(960px, calc(100% - 40px));
  max-height:calc(100vh - 120px);
  display:flex;
  flex-direction:column;
  background:var(--surface-raised); /* floating surface — visible in dark */
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-lg);
  overflow:hidden;
}
/* Launcher search: an OUTER wrapper (.launcher-search) owns the row spacing +
   divider; the INNER .search (.search--lg .search--seamless) just lays out the
   magnifier + input + ESC. The launcher search is the modal's primary field
   (always active on open), so it has NO focus ring — Spotlight / ⌘K-palette
   style, just the caret. The ring is suppressed via :focus-within below.
   Alignment with the body is by the wrapper's horizontal padding (--space-24,
   matching .launcher-body padding-x); the inner search carries no side inset,
   so the magnifier / placeholder / ESC sit exactly above the section labels
   and tiles beneath. */
.launcher .launcher-search{
  padding:var(--space-12) var(--space-24);
  border-bottom:1px solid var(--divider);
}
.launcher .launcher-search .search{ padding-left:0; padding-right:0; }
.launcher .launcher-search .search:focus-within{ box-shadow:none; }
.launcher .launcher-search .kbd{
  padding:var(--space-4) var(--space-8);
  border-radius:var(--radius-xs);
  background:var(--surface-alt);
  border:1px solid var(--border);
  font-size:var(--font-xs);
  font-family:ui-monospace, monospace;
  color:var(--text-muted);
}
.launcher .launcher-body{
  flex:1;
  overflow-y:auto;
  padding:var(--space-20) var(--space-24) 28px;
}
.launcher .launcher-empty{
  padding:var(--space-20) var(--space-24);
  color:var(--text-muted);
  font-size:var(--font-md);
}
.launcher .launcher-section{
  margin-bottom:var(--space-24);
}
.launcher .launcher-section h4{
  font-size:var(--font-xs);
  font-weight:700;
  color:var(--text-muted);
  letter-spacing:.08em;
  text-transform:uppercase;
  margin-bottom:var(--space-12);
  display:flex;
  align-items:center;
  gap:var(--space-8);
}
.launcher .launcher-section h4::after{
  content:"";
  flex:1;
  height:1px;
  background:var(--divider);
}
.launcher .module-grid{
  display:grid;
  grid-template-columns:repeat(4, minmax(0,1fr));
  gap:var(--space-8);
}
@media(max-width:760px){
  .launcher .module-grid{ grid-template-columns:repeat(2, minmax(0,1fr)) }
  /* Forms: a single column once the content area gets narrow. */
  .form-grid{ grid-template-columns:1fr; }
  /* A field set to span both columns is already full-width here — neutralise
     the explicit span so it doesn't error/confuse the single track. */
  .form-grid > .form-field.span-full{ grid-column:auto; }
}
/* [hidden] must beat the display rules below so the launcher search can filter. */
.launcher .module-tile[hidden]{ display:none; }
.launcher .launcher-section[hidden]{ display:none; }
.launcher .module-tile{
  display:flex;
  align-items:flex-start;
  gap:var(--space-12);
  padding:var(--space-12);
  border-radius:var(--radius);
  background:var(--surface);
  border:1px solid var(--border);
  cursor:pointer;
  transition:.14s ease;
  text-align:left;
}
.launcher .module-tile:hover{
  background:var(--surface-hover);
  border-color:var(--brand);
  transform:translateY(-1px);
}
.launcher .module-tile .icon{
  width:36px; height:36px;
  border-radius:var(--radius-sm);
  display:grid;
  place-items:center;
  flex-shrink:0;
  font-size:18px;
}
/* Feather SVG ikona v dlaždici — barva z .cat-* (currentColor), velikost ~20px. */
.launcher .module-tile .icon svg{ width:20px; height:20px }
.launcher .module-tile .meta{
  display:flex;
  flex-direction:column;
  gap:var(--space-2);
  min-width:0;
}
.launcher .module-tile .name{
  font-size:var(--font-md);
  font-weight:600;
  color:var(--text);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.launcher .module-tile .desc{
  font-size:var(--font-xs);
  color:var(--text-muted);
  line-height:1.4;
}
/* Disabled tiles - rendered but not yet wired to a real screen. */
.launcher .module-tile.disabled{
  cursor:not-allowed;
  opacity:.55;
  position:relative;
}
.launcher .module-tile.disabled:hover{
  background:var(--surface);
  border-color:var(--border);
  transform:none;
}
.launcher .module-tile.disabled .icon{
  filter:grayscale(.4);
}
.launcher .module-tile .soon-badge{
  position:absolute;
  top:8px;
  right:8px;
  padding:1px var(--space-8);
  border-radius:var(--radius-pill);
  background:var(--surface-alt);
  border:1px solid var(--border);
  font-size:10px;
  font-weight:700;
  letter-spacing:.05em;
  text-transform:uppercase;
  color:var(--text-muted);
}

/* Module category colour accents — text via --cat-*-fg tokens (light/dark
   variants live in :root + the dark block), backgrounds stay alpha tints. */
.cat-identity{ background:rgba(167,139,250,.14); color:var(--cat-identity-fg) }
.cat-warehouse{ background:rgba(59,130,246,.14); color:var(--cat-warehouse-fg) }
.cat-transport{ background:rgba(245,158,11,.14); color:var(--cat-transport-fg) }
.cat-production{ background:rgba(251,113,133,.14); color:var(--cat-production-fg) }
.cat-reporting{ background:rgba(99,102,241,.14); color:var(--cat-reporting-fg) }   /* indigo-500 */
.cat-traceability{ background:rgba(20,184,166,.14); color:var(--cat-traceability-fg) }
.cat-assets{ background:rgba(34,197,94,.14); color:var(--cat-assets-fg) }   /* green-500 */
.cat-print{ background:rgba(148,163,184,.14); color:var(--cat-print-fg) }
.cat-design{ background:rgba(168,85,247,.14); color:var(--cat-design-fg) }   /* purple-500 */


/* -------------------------------------------------------------------------
   Home dashboard
   ------------------------------------------------------------------------- */
.dash{
  display:grid;
  grid-template-columns:minmax(0, 1fr) 340px;
  gap:var(--space-24);
}
@media(max-width:1100px){
  .dash{ grid-template-columns:1fr }
}

/* Greeting je teď fixní page-header (mimo scroll) — bez vlastního margin-bottom,
   pozici/padding řeší .page-header. */
.dash-greet h1{
  font-size:var(--font-2xl);
  font-weight:700;
  letter-spacing:-.01em;
}
.dash-greet p{
  color:var(--text-muted);
  margin-top:var(--space-4);
  font-size:var(--font-md);
}

/* Hero — operativní souhrn: 3 stavové karty hotových modulů. */
.dash-stats{
  display:grid;
  grid-template-columns:repeat(3, 1fr);
  gap:var(--space-16);
  margin-bottom:var(--space-24);
}
@media(max-width:1100px){ .dash-stats{ grid-template-columns:1fr } }
.dash-stat{
  display:flex;
  flex-direction:column;
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  background:var(--surface);
  padding:var(--space-18) var(--space-20);
  text-decoration:none;
  color:inherit;
  transition:border-color .15s, box-shadow .15s;
}
/* Karta NENÍ klikatelná jako celek (graf potřebuje tap/hover na body) — proklik
   do modulu je v hlavičce přes "Otevřít →". Hlavička má stejný vizuál jako pravé
   widgety (.widget-head): linka pod, roztažená přes celou šířku karty (záporné
   okraje vykompenzují padding karty). */
.dash-stat-head{
  display:flex; align-items:center; justify-content:space-between; gap:var(--space-8);
  margin:calc(var(--space-18) * -1) calc(var(--space-20) * -1) var(--space-16);
  padding:var(--space-14) var(--space-16);
  border-bottom:1px solid var(--divider);
}
.dash-stat-ico{
  display:inline-flex; align-items:center; justify-content:center;
  width:30px; height:30px; border-radius:var(--radius); font-size:16px;
}
.dash-stat-name{ font-size:var(--font-md); font-weight:700; color:var(--text) }
/* Větší titulek karty (bez ikony) — name jako nadpis sekce. */
.dash-stat-name--lg{ font-size:var(--font-md); font-weight:700; color:var(--text) }
/* Řádek "velké číslo + Otevřít" (karta Uživatelé bez hlavičky). */
.dash-stat-bigrow{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--space-12) }
.dash-stat-bigrow .dash-stat-open{ align-self:center }
/* "Otevřít →" vpravo v hlavičce — stejný vizuál jako u pravých widgetů
   (.widget-head .filter): šedý pill, ať je proklik napříč dashboardem jednotný. */
.dash-stat-open{
  margin-left:auto; white-space:nowrap; text-decoration:none;
  font-size:var(--font-xs); color:var(--text-muted);
  padding:var(--space-4) var(--space-8); border-radius:var(--radius-pill);
  background:var(--surface-alt);
}
.dash-stat-open:hover{ color:var(--text); background:var(--surface-muted) }
.dash-stat-big{ font-size:var(--font-2xl); font-weight:700; letter-spacing:-.01em; line-height:1.1 }
.dash-stat-unit{ font-size:var(--font-sm); font-weight:500; color:var(--text-muted) }
.dash-stat-breakdown{
  display:flex; flex-wrap:wrap; gap:var(--space-4) var(--space-14);
  margin-top:var(--space-8); font-size:var(--font-sm); color:var(--text-muted);
}
.dash-stat-breakdown strong{ color:var(--text); font-weight:600 }
.dash-stat-chart{ margin-top:auto; padding-top:var(--space-14) }
/* Graf ve stat kartě je vyšší — po odebrání footeru má prostor a vyrovná výšku
   karty se sousedními (ring/arc). */
.dash-stat-chart.chart-line{ --line-h:200px }
.dash-stat-foot{ font-size:var(--font-xs); color:var(--text-faint); margin-top:var(--space-6) }
/* Ring "stav teď" uvnitř stavové karty — velký vycentrovaný ring; legenda pod
   ním řeší variant data-legend="below". Větší střed (číslo je hlavní sdělení). */
.dash-stat-ring{ margin-top:var(--space-16); flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center }
.dash-stat-ring .chart-pie{ --pie-size:190px }
.dash-stat-ring .chart-pie .pie-center-num{ font-size:var(--font-2xl); font-weight:800 }
.dash-stat-ring .chart-pie .pie-center-cap{ font-size:var(--font-sm) }
/* Arc uvnitř stat karty — velký, vycentrovaný, dominantní číslo (jako ring). */
.dash-stat-ring .chart-arc{ --arc-size:190px }
.dash-stat-ring .chart-arc .arc-num{ font-size:var(--font-2xl); font-weight:800 }
.dash-stat-ring .chart-arc .arc-cap{ font-size:var(--font-sm) }
/* Rozpad pod grafem, vycentrovaný (arc karty nemají legendu). */
.dash-stat-breakdown--center{ justify-content:center; margin-top:var(--space-14) }

/* === Varianta "legenda/rozpad VPRAVO" (tři karty v horní řadě) === */
/* Ring/arc menší, ať se vejde graf + legenda vedle do třetiny šířky. Legenda
   zůstává v normální velikosti (kompaktní vypadala hůř). */
.dash-stat-ring--side{ flex-direction:row; align-items:center; justify-content:center; gap:var(--space-16) }
.dash-stat-ring--side .chart-pie{ --pie-size:150px }
.dash-stat-ring--side .chart-arc{ --arc-size:150px }
.dash-stat-ring--side .chart-pie .pie-center-num,
.dash-stat-ring--side .chart-arc .arc-num{ font-size:var(--font-2xl) }
/* Rozpad arc (Inventury) jako sloupec vpravo vedle gauge. */
.dash-stat-breakdown--side{
  display:flex; flex-direction:column; gap:var(--space-8);
  margin:0; font-size:var(--font-sm); color:var(--text-muted); white-space:nowrap;
}

/* === Široká karta (Uživatelé) přes celou šířku pod trojicí === */
.dash-stat--wide{ margin-bottom:var(--space-24) }
.dash-stat--wide .dash-stat-chart.chart-line{ --line-h:170px }

.dash-section{
  margin-bottom:28px;
}
.dash-section-head{
  display:flex;
  align-items:center;
  justify-content:space-between;
  margin-bottom:var(--space-12);
}
.dash-section-head h2{
  font-size:var(--font-md);
  font-weight:700;
  letter-spacing:.005em;
  display:flex;
  align-items:center;
  gap:var(--space-8);
}
.dash-section-head h2 .badge{
  background:var(--brand);
  color:var(--on-accent);
  padding:1px var(--space-8);
  border-radius:var(--radius-pill);
  font-size:var(--font-xs);
  font-weight:700;
}
.dash-section-head a{
  font-size:var(--font-sm);
  color:var(--brand);
  font-weight:600;
}
.dash-section-head a:hover{ color:var(--brand-dark) }

/* Quick action tiles */
.quick-grid{
  display:grid;
  grid-template-columns:repeat(3, minmax(0,1fr));   /* sladěno s hero kartami (3 sl.) */
  gap:var(--space-16);
}
@media(max-width:900px){
  .quick-grid{ grid-template-columns:repeat(2, minmax(0,1fr)) }
}
.quick-tile{
  position:relative;
  display:flex;
  flex-direction:column;
  gap:var(--space-8);
  padding:var(--space-18) var(--space-20);
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);   /* sjednoceno s hero stat kartami */
  cursor:pointer;
  overflow:hidden;
  transition:border-color .15s, box-shadow .15s, transform .15s;
  text-align:left;
}
/* Levý barevný accent pruh dle modulu (cat-* určuje barvu textu = accent). */
.quick-tile::before{
  content:""; position:absolute; left:0; top:0; bottom:0; width:3px;
  background:currentColor; opacity:.55;
}
.quick-tile.cat-transport{ color:var(--cat-transport-fg) }
.quick-tile.cat-assets{ color:var(--cat-assets-fg) }
.quick-tile.cat-identity{ color:var(--cat-identity-fg) }
.quick-tile:hover{
  border-color:var(--brand-ring);
  box-shadow:var(--shadow-tile-hover);
  transform:translateY(-1px);
}
/* Hlavička dlaždice: ikona vlevo + šipka „jít na" vpravo (zvýrazní se na hover). */
.quick-tile .qt-head{ display:flex; align-items:center; justify-content:space-between }
.quick-tile .qt-go{
  font-size:var(--font-lg); font-weight:600; color:var(--text-faint);
  transition:transform .15s, color .15s;
}
.quick-tile:hover .qt-go{ color:currentColor; transform:translateX(2px) }
.quick-tile .icon{
  width:34px; height:34px;
  border-radius:var(--radius);
  display:grid;
  place-items:center;
  font-size:18px;
}
.quick-tile .icon svg{ width:18px; height:18px }
.quick-tile .count{
  font-size:var(--font-2xl);
  font-weight:800;
  letter-spacing:-.01em;
  line-height:1;
  color:var(--text);
  margin-top:var(--space-4);
}
.quick-tile .label{
  font-size:var(--font-sm);
  color:var(--text);
  font-weight:600;
  line-height:1.35;
}
/* Kontext / urgence pod popiskem — tlumený, s barevným náznakem stavu. */
.quick-tile .qt-meta{
  font-size:var(--font-xs); color:var(--text-faint); line-height:1.3;
  display:inline-flex; align-items:center; gap:var(--space-4);
}
.quick-tile .qt-meta::before{
  content:""; width:6px; height:6px; border-radius:50%; background:var(--text-faint); flex:none;
}
.quick-tile .qt-meta.is-warn{ color:var(--warning-fg) }
.quick-tile .qt-meta.is-warn::before{ background:var(--warning) }
.quick-tile .qt-meta.is-danger{ color:var(--danger-fg) }
.quick-tile .qt-meta.is-danger::before{ background:var(--danger) }
.quick-tile.add{
  align-items:center;
  justify-content:center;
  border-style:dashed;
  color:var(--text-muted);
  font-weight:500;
  background:transparent;
}
.quick-tile.add:hover{ background:var(--surface-hover); border-style:solid }

/* Attention list */
.attention-list{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  overflow:hidden;
}
.attention-row{
  display:flex;
  align-items:center;
  gap:var(--space-14);
  padding:var(--space-14) var(--space-18);
  border-bottom:1px solid var(--divider);
  cursor:pointer;
  transition:.12s ease;
}
.attention-row:last-child{ border-bottom:0 }
.attention-row:hover{ background:var(--surface-hover) }
.attention-row .icon{
  width:32px; height:32px;
  border-radius:50%;
  display:grid;
  place-items:center;
  flex-shrink:0;
}
.attention-row.warn .icon{ background:var(--warning-soft); color:var(--warning-fg) }
.attention-row.error .icon{ background:var(--danger-soft); color:var(--danger) }
.attention-row.info .icon{ background:var(--brand-soft); color:var(--brand-dark) }
.attention-row .text{
  flex:1;
  display:flex;
  flex-direction:column;
  gap:var(--space-2);
}
.attention-row .text .title{
  font-size:var(--font-md);
  font-weight:600;
  color:var(--text);
}
.attention-row .text .sub{
  font-size:var(--font-sm);
  color:var(--text-muted);
}
.attention-row .time{
  font-size:var(--font-sm);
  color:var(--text-faint);
  white-space:nowrap;
}
.attention-row .chev{
  color:var(--text-faint);
}

/* Recently visited entities — list of records (not modules) */
.recent-list{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  overflow:hidden;
}
.recent-row{
  display:flex;
  align-items:center;
  gap:var(--space-14);
  padding:var(--space-12) var(--space-18);
  border-bottom:1px solid var(--divider);
  cursor:pointer;
  text-decoration:none;
  color:inherit;
  transition:.12s ease;
}
.recent-row:last-child{ border-bottom:0 }
.recent-row:hover{ background:var(--surface-hover) }
.recent-row .icon{
  width:32px; height:32px;
  border-radius:var(--radius);
  display:grid;
  place-items:center;
  font-size:16px;
  flex-shrink:0;
}
.recent-row .icon svg{ width:17px; height:17px }
.recent-row .text{
  flex:1;
  display:flex;
  flex-direction:column;
  gap:var(--space-2);
  min-width:0;
}
.recent-row .text .name{
  font-size:var(--font-md);
  font-weight:600;
  color:var(--text);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.recent-row .text .path{
  font-size:var(--font-sm);
  color:var(--text-muted);
}
.recent-row .time{
  font-size:var(--font-sm);
  color:var(--text-faint);
  white-space:nowrap;
}

/* Pinned modules grid (smaller than launcher) */
.pinned-grid{
  display:grid;
  grid-template-columns:repeat(3, minmax(0,1fr));
  gap:var(--space-10);
}
@media(max-width:900px){
  .pinned-grid{ grid-template-columns:repeat(2, minmax(0,1fr)) }
}
.pinned-tile{
  display:flex;
  align-items:center;
  gap:var(--space-10);
  padding:var(--space-12) var(--space-14);
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  cursor:pointer;
  transition:.14s ease;
}
.pinned-tile:hover{
  border-color:var(--brand);
  background:var(--surface-hover);
}
.pinned-tile .icon{
  width:30px; height:30px;
  border-radius:var(--radius-sm);
  display:grid;
  place-items:center;
  flex-shrink:0;
  font-size:14px;
}
.pinned-tile .name{
  font-size:var(--font-md);
  font-weight:500;
  color:var(--text);
}

/* Activity widget (sidebar) */
.dash-aside{
  display:flex;
  flex-direction:column;
  gap:var(--space-18);
}
.widget{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  overflow:hidden;
}
.widget-head{
  padding:var(--space-14) var(--space-16);
  border-bottom:1px solid var(--divider);
  display:flex;
  align-items:center;
  justify-content:space-between;
}
.widget-head h3{
  font-size:var(--font-md);
  font-weight:700;
}
.widget-head .filter{
  font-size:var(--font-xs);
  color:var(--text-muted);
  padding:var(--space-4) var(--space-8);
  border-radius:var(--radius-pill);
  background:var(--surface-alt);
}
.widget-body{ padding:var(--space-6) 0 }
/* Řádek statistiky ve widgetu „Stav systému" (klíč vlevo, hodnota vpravo). */
.widget-stat-row{ display:flex; justify-content:space-between; padding:var(--space-8) 0; font-size:var(--font-sm); }
.widget-stat-row + .widget-stat-row{ border-top:1px solid var(--divider); }
.widget-stat-row .k{ color:var(--text-muted); }
.widget-stat-row .v{ font-weight:600; }
.widget-body--stats{ padding:var(--space-6) var(--space-16) var(--space-12); }
.activity-row{
  display:flex;
  gap:var(--space-12);
  padding:var(--space-10) var(--space-16);
}
.activity-row .dot{
  width:8px; height:8px;
  border-radius:50%;
  background:var(--brand);
  margin-top:var(--space-6);
  flex-shrink:0;
}
.activity-row.success .dot{ background:var(--success) }
.activity-row.warn .dot{ background:var(--warning) }
.activity-row .text{ font-size:var(--font-sm); line-height:1.5; color:var(--text) }
.activity-row .text .meta{ color:var(--text-muted); font-size:var(--font-xs); margin-top:var(--space-2) }
.activity-row .text strong{ font-weight:600 }


/* -------------------------------------------------------------------------
   Workflow stepper (reusable: Doprava, Skladová příjemka, Výrobní zakázka,
   any other multi-stage lifecycle entity).
   ------------------------------------------------------------------------- */
.stepper{
  display:flex;
  align-items:flex-start;
  gap:0;
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  padding:var(--space-18) var(--space-16);
  margin-bottom:var(--space-20);
  /* The card itself never scrolls/clips — its height follows the inner track.
     Horizontal scroll lives on .stepper-track so labels are never clipped. */
  min-width:0;
}
/* Inner flex row that scrolls horizontally when the 5 steps don't fit. Its
   height is the steps' natural height (no clipping). */
.stepper .stepper-track{
  display:flex;
  align-items:flex-start;
  width:100%;
  min-width:0;
  overflow-x:auto;
  scrollbar-width:thin;   /* slim bar so it adds minimal height when scrolling */
  /* overflow-x clips vertically too — give the active dot's 4px halo room so it
     isn't cut off at the top. Negative margin keeps the visual position. */
  padding-top:var(--space-6);
  margin-top:calc(var(--space-6) * -1);
}
.stepper .step{
  flex:1;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:var(--space-6);
  position:relative;
  min-width:120px;
  padding:0 var(--space-8);
  cursor:pointer;
  text-align:center;
}
.stepper .step + .step::before{
  content:"";
  position:absolute;
  top:14px;
  left:calc(-50% + 18px);
  right:calc(50% + 18px);
  height:2px;
  background:var(--border);
  z-index:0;
}
.stepper .step.completed + .step::before,
.stepper .step.active + .step::before{ background:var(--brand) }
.stepper .step .dot{
  position:relative;
  z-index:1;
  width:28px;
  height:28px;
  border-radius:50%;
  display:grid;
  place-items:center;
  background:var(--surface);
  border:2px solid var(--border);
  color:var(--text-muted);
  font-size:var(--font-sm);
  font-weight:700;
  transition:.16s ease;
}
.stepper .step.completed .dot{
  background:var(--brand);
  border-color:var(--brand);
  color:var(--on-accent);
}
.stepper .step.active .dot{
  background:var(--surface);
  border-color:var(--brand);
  color:var(--brand-dark);
  box-shadow:0 0 0 4px var(--brand-ring);
}
.stepper .step .label{
  font-size:var(--font-sm);
  font-weight:600;
  color:var(--text-muted);
  line-height:1.3;
}
.stepper .step.completed .label{ color:var(--text) }
.stepper .step.active .label{ color:var(--brand-dark) }
.stepper .step .meta{
  font-size:var(--font-xs);
  color:var(--text-faint);
  line-height:1.4;
}
.stepper .step.completed .meta{ color:var(--text-muted) }


/* Stage form card (active step content) */
.stage-card{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  margin-bottom:var(--space-14);
  overflow:hidden;
}
.stage-card.completed{
  background:var(--surface-alt);
}
/* Active step — accent border so it's clear what to act on now (no ring; that
   reads like an input focus state). */
.stage-card.active{
  border-color:var(--brand);
}
.stage-card-head{
  display:flex;
  align-items:center;
  gap:var(--space-14);
  padding:var(--space-14) var(--space-18);
  border-bottom:1px solid var(--divider);
  cursor:pointer;
  user-select:none;
}
.stage-card.active .stage-card-head{
  background:var(--brand-soft);   /* tints with the chosen accent */
}
.stage-card-head .badge{
  width:24px;
  height:24px;
  border-radius:50%;
  display:grid;
  place-items:center;
  background:var(--border);
  color:var(--text-muted);
  font-size:var(--font-xs);
  font-weight:700;
  flex-shrink:0;
}
.stage-card.completed .stage-card-head .badge{
  background:var(--success);
  color:var(--on-accent);
}
.stage-card.active .stage-card-head .badge{
  background:var(--brand);
  color:var(--on-accent);
}
.stage-card-head h3{
  font-size:var(--font-md);
  font-weight:700;
  flex:1;
}
.stage-card-head .timestamp{
  font-size:var(--font-sm);
  color:var(--text-muted);
}
.stage-card-head .timestamp strong{
  color:var(--text);
  font-weight:600;
}
.stage-card-head .chev{
  color:var(--text-faint);
  transition:transform .18s ease;
}
.stage-card.collapsed .stage-card-head .chev{ transform:rotate(-90deg) }
.stage-card-body{
  padding:var(--space-18);
}
.stage-card.collapsed .stage-card-body{ display:none }
.stage-card.disabled{
  opacity:.55;
  pointer-events:none;
}


/* Photo grid — thumbnails for an asset's inventory photos (detail panel,
   Fotografie tab). Prototype has no real images, so each tile is a framed
   placeholder with an image glyph. */
.photo-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(96px, 1fr));
  gap:var(--space-10);
  padding:var(--space-4) 0;
}
.photo-grid[hidden]{ display:none; }
.photo-tile{
  position:relative;
  aspect-ratio:1 / 1;
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface-muted);
  display:grid;
  place-items:center;
  color:var(--text-faint);
  overflow:hidden;
  cursor:pointer;
  transition:border-color var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}
.photo-tile:hover{ border-color:var(--border-strong); color:var(--text-muted); }
.photo-tile svg{ width:28px; height:28px; }
.photo-tile .photo-idx{
  position:absolute;
  bottom:var(--space-4); right:var(--space-6);
  font-size:var(--font-xs); color:var(--text-faint);
}

/* Lightbox — fullscreen photo viewer opened from a .photo-tile. Counter + close
   on top, ‹ › arrows on the sides, a big stage in the middle, a thumbnail strip
   below. Prototype has no real images, so the stage shows a large placeholder. */
.lightbox{
  position:fixed; inset:0; z-index:1200;
  display:none;
  flex-direction:column;
  background:var(--backdrop);   /* same overlay token as launcher + modals */
  backdrop-filter:blur(4px);
  -webkit-backdrop-filter:blur(4px);
}
.lightbox.open{ display:flex; }
.lightbox-bar{
  display:flex; align-items:center; justify-content:space-between;
  padding:var(--space-16) var(--space-20);
  color:var(--on-accent);
}
.lightbox-count{ font-size:var(--font-md); font-weight:600; }
.lightbox-close{
  display:grid; place-items:center;
  width:36px; height:36px; border-radius:var(--radius-pill);
  background:rgba(255, 255, 255, .16); color:var(--on-accent);
  cursor:pointer; transition:background var(--dur-base) var(--ease);
}
.lightbox-close:hover{ background:rgba(255, 255, 255, .24); }
.lightbox-close svg{ width:20px; height:20px; }
.lightbox-stage{
  flex:1; min-height:0;
  display:flex; align-items:center; justify-content:center;
  gap:var(--space-16);
  padding:0 var(--space-16);
}
.lightbox-nav{
  flex-shrink:0;
  display:grid; place-items:center;
  width:48px; height:48px; border-radius:var(--radius-pill);
  background:rgba(255, 255, 255, .16); color:var(--on-accent);
  cursor:pointer; transition:background var(--dur-base) var(--ease);
}
.lightbox-nav:hover{ background:rgba(255, 255, 255, .24); }
.lightbox-nav:disabled{ opacity:.3; cursor:default; }
.lightbox-nav svg{ width:26px; height:26px; }
.lightbox-photo{
  flex:1; max-width:760px; height:100%;
  max-height:62vh;
  display:grid; place-items:center;
  background:var(--surface-muted);
  border-radius:var(--radius-lg);
  color:var(--text-faint);
}
.lightbox-photo svg{ width:72px; height:72px; }
.lightbox-strip{
  display:flex; align-items:center; justify-content:center;
  gap:var(--space-8); flex-wrap:wrap;
  padding:var(--space-16) var(--space-20) var(--space-24);
}
.lightbox-thumb{
  width:56px; height:56px; border-radius:var(--radius-sm);
  border:2px solid transparent;
  background:rgba(255, 255, 255, .16);
  display:grid; place-items:center; color:rgba(255, 255, 255, .6);
  cursor:pointer; transition:border-color var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}
.lightbox-thumb svg{ width:20px; height:20px; }
.lightbox-thumb:hover{ color:var(--on-accent); }
.lightbox-thumb.active{ border-color:var(--on-accent); color:var(--on-accent); }

/* Compact key-value list (used inside completed stages) */
.kv-list{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:var(--space-12) var(--space-20);
}
/* display:grid beats the UA [hidden] rule — restore it so a kv-list can be
   conditionally shown (e.g. record vs. difference field sets in one panel). */
.kv-list[hidden]{ display:none; }
.kv-list .kv-item{
  display:flex;
  flex-direction:column;
  gap:var(--space-2);
}
/* display:flex jinak přebije UA [hidden] (display:none) → schovaná položka by
   zůstala vidět. Vrať skrytí pro podmíněně zobrazené kv-item (např. Ukázka). */
.kv-list .kv-item[hidden]{ display:none; }
.kv-list .kv-item .k{
  font-size:var(--font-sm);
  color:var(--text-muted);
  font-weight:600;
  letter-spacing:.015em;
}
.kv-list .kv-item .v{
  font-size:var(--font-md);
  color:var(--text);
  font-weight:500;
}
.kv-list .kv-item .v.mono{
  font-family:ui-monospace,Menlo,monospace;
  font-size:var(--font-sm);
  font-weight:400;
  word-break:break-all;
}
/* Auto-fit variant — fills as many columns as fit (min 150px) and pads itself.
   Used by the transport hero details (replaced the old .th-details). */
.kv-list--auto{
  grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));
  gap:var(--space-14) var(--space-24);
  padding:var(--space-18) var(--space-20);
  align-content:center;
}
/* Full-width item inside a grid (kv-list / form-grid) — replaces the inline
   style="grid-column:1 / -1" pattern with a reusable utility. */
.kv-item.span-full,
.form-field.span-full{ grid-column:1 / -1; }

/* Atributy úlohy — pole Hodnoty (input/select/number/textarea) uvnitř host
   wrapperu: roztáhni na celou šířku draweru (bez form-gridu by se number field
   scvrkl). Json = víceřádková mono textarea (kód). */
#ad-value-host input,
#ad-value-host select,
#ad-value-host textarea{ width:100%; box-sizing:border-box; }
#ad-value-host textarea.mono{
  font-family:ui-monospace,Menlo,monospace;
  font-size:var(--font-sm);
  line-height:1.5;
  min-height:140px;
  resize:vertical;
}
/* Rozestupy sekcí v draweru atributu — meta i hodnota odsazené od comboboxu. */
#attr-drawer #ad-meta:not([hidden]){ margin-top:var(--space-16); }
/* Popis atributu — zachovej řádky Parametrů (běžný text, ne kód). */
#attr-drawer #ad-desc{ white-space:pre-line; }
/* Příklad = kód ke zkopírování do hodnoty: mono blok se zachovaným
   formátováním, jemné code-block pozadí. */
#attr-drawer #ad-example.mono{
  display:block;
  white-space:pre-wrap;
  font-family:ui-monospace,Menlo,monospace;
  font-size:var(--font-sm);
  line-height:1.5;
  color:var(--text);
  background:var(--surface-muted);
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  padding:var(--space-10) var(--space-12);
  margin-top:var(--space-4);
  overflow-x:auto;
}

/* Detail split layout: main content + sticky activity log on the side. */
.detail-layout{
  display:grid;
  grid-template-columns:minmax(0, 1fr) 320px;
  gap:var(--space-20);
}
/* Grid items default to min-width:auto (=min-content), which lets a wide child
   (the stepper) blow the track past the viewport. Pin them to 0 so the track
   stays within 1fr and the stepper's overflow-x:auto scrolls instead. */
.detail-layout > *{ min-width:0; }
@media(max-width:1100px){ .detail-layout{ grid-template-columns:1fr } }

/* Transport detail header card — a coloured hero (number + status) on the left,
   a details grid on the right. Gives the record a "face" vs a flat KV strip. */
.transport-hero{
  display:grid;
  grid-template-columns:minmax(220px, 280px) 1fr;
  gap:0;
  border:1px solid var(--border);
  border-radius:var(--radius);
  background:var(--surface);
  margin-bottom:var(--space-18);
  /* No overflow:hidden — as a flex child of .page-body it collapsed the card to
     ~0 height when the grid re-stacked on narrow widths. Round the inner blocks'
     outer corners instead so the hero tint still respects the card radius. */
}
.th-hero{
  display:flex; align-items:center; gap:var(--space-14);
  padding:var(--space-18) var(--space-20);
  background:var(--brand-soft);
  border-right:1px solid var(--border);
  border-radius:var(--radius) 0 0 var(--radius);   /* left corners */
}
.th-hero-ic{
  width:48px; height:48px; border-radius:var(--radius);
  display:grid; place-items:center; flex-shrink:0;
  background:var(--brand); color:var(--on-accent);
}
.th-hero-id{ display:flex; flex-direction:column; gap:var(--space-4); min-width:0; }
.th-hero-label{
  font-size:var(--font-xs); font-weight:600; letter-spacing:.04em;
  text-transform:uppercase; color:var(--brand-dark);
}
.th-hero-num{ font-size:var(--font-xl); font-weight:700; color:var(--text); line-height:1.1; }
.th-hero-status{ align-self:flex-start; margin-top:var(--space-4); }
/* Details grid uses the shared .kv-list.kv-list--auto (was .th-details). */
/* Stack the hero on top on narrow widths. */
@media(max-width:760px){
  .transport-hero{ grid-template-columns:1fr; }
  .th-hero{ border-right:0; border-bottom:1px solid var(--border); border-radius:var(--radius) var(--radius) 0 0; }  /* top corners */
}

/* Activity log — vertical timeline of events (time · action · who). */
.log{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  position:sticky;
  top:20px;
}
.log h3{
  font-size:var(--font-md);
  font-weight:700;
  padding:var(--space-14) var(--space-16);
  border-bottom:1px solid var(--divider);
}
.log-list{
  padding:6px 0;
  max-height:520px;
  overflow-y:auto;
}
.log-row{
  display:flex;
  gap:10px;
  padding:8px 16px;
  align-items:flex-start;
}
.log-row .time{
  font-size:var(--font-xs);
  color:var(--text-faint);
  font-variant-numeric:tabular-nums;
  flex-shrink:0;
  min-width:42px;
  padding-top:1px;
}
.log-row .text{
  font-size:var(--font-sm);
  line-height:1.5;
  color:var(--text);
}
.log-row .text strong{ font-weight:600 }
.log-row .text .who{ color:var(--text-muted); font-size:var(--font-xs); display:block; margin-top:1px }
/* A note entered in a step shows under the event as a quoted line — same size
   as the .who subline. */
.log-row .text .note{
  display:block; margin-top:var(--space-4);
  color:var(--text-muted); font-style:italic; font-size:var(--font-xs);
  border-left:2px solid var(--border-strong); padding-left:var(--space-8);
}

/* Read-only code / JSON block — payload viewers, schema dumps. */
.code-block{
  margin:0;
  padding:var(--space-14) var(--space-16);
  background:var(--surface-alt);
  border:1px solid var(--border);
  border-radius:var(--radius);
  overflow:auto;
  max-height:420px;
}
.code-block code{
  font-family:ui-monospace,Menlo,monospace;
  font-size:var(--font-sm);
  line-height:1.6;
  color:var(--text);
  white-space:pre;
}
/* Inline error message block (e.g. a failed outbox message). */
.error-box{
  padding:var(--space-12) var(--space-14);
  background:var(--danger-soft);
  border:1px solid var(--danger-soft);
  border-radius:var(--radius-sm);
  color:var(--danger-fg);
  font-size:var(--font-sm);
  font-family:ui-monospace,Menlo,monospace;
  word-break:break-word;
}


/* -------------------------------------------------------------------------
   Type-picker modal (Doprava: "Založení evidence dopravy")
   ------------------------------------------------------------------------- */
.modal-backdrop{
  position:fixed;
  inset:0;
  z-index:150;
  background:var(--backdrop);
  display:none;
  align-items:center;
  justify-content:center;
}
.modal-backdrop.open{ display:flex }
.modal-card{
  width:min(420px, calc(100% - 40px));
  background:var(--modal-bg);
  border:1px solid var(--modal-border);
  border-radius:var(--radius-lg);
  box-shadow:var(--modal-shadow);
  overflow:hidden;
}
/* overflow:hidden ořezává radius, ale taky vyčnívající dropdown (.ss-panel je
   position:absolute). Když je v modalu OTEVŘENÝ select-search, povol overflow,
   ať se panel vejde mimo kartu. */
.modal-card:has(.select-search.open),
.modal-card:has(.select-menu-host.open){ overflow:visible; }
/* Šířkové varianty modalu (škála): narrow 360 · default 420 · wide 720.
   --wide pro modaly s tabulkou (víc sloupců se do 420 nevejde). */
.modal-card--narrow{ width:min(360px, calc(100% - 40px)); }
.modal-card--wide{ width:min(720px, calc(100% - 40px)); }
/* Tabulka v modalu může být vyšší — povol scroll uvnitř body, ať modal nepřeteče. */
.modal-card--wide .modal-body{ max-height:60vh; overflow-y:auto; }
/* Když je otevřený dropdown v modalu (role-dropdown v pozvánce NEBO .select-menu
   v tabulce — Změna statusu/stavu palety), povol overflow, ať panel vyleze PŘES
   okno a neořízne se scrollem modal-body (max-height:60vh; overflow-y:auto výše). */
.modal-card--wide .modal-body:has([data-roles].open),
.modal-card--wide .modal-body:has(.select-menu-host.open),
.modal-card--wide .modal-body:has(.select-search.open){ overflow:visible; }

/* ===== Pozvat uživatele (modal) — řádky e-mail + role, sekce přístupu ===== */
.modal-intro{ margin:0 0 var(--space-14); color:var(--text-muted); font-size:var(--font-sm); line-height:1.5; }
.invite-rows{ display:flex; flex-direction:column; gap:var(--space-10); }
.invite-row-main{ display:flex; align-items:flex-start; gap:var(--space-8); }
.invite-email-field{ flex:1 1 55%; min-width:0; display:flex; flex-direction:column; gap:var(--space-4); }
.invite-row .invite-email{
  width:100%; min-width:0;
  padding:var(--space-8) var(--space-10);
  border:1px solid var(--border); border-radius:var(--radius-sm);
  background:var(--surface); font-size:var(--font-md); color:var(--text);
}
.invite-row .invite-email::placeholder{ color:var(--text-faint); opacity:1; }
.invite-row .invite-email:focus{ outline:none; border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-ring); }
.invite-row .invite-email.is-invalid{ border-color:var(--danger); }
.invite-row .invite-email.is-invalid:focus{ box-shadow:0 0 0 3px var(--danger-soft); }
.invite-email-error{ font-size:var(--font-xs); color:var(--danger); }
/* Řádek je flex-start (kvůli chybové hlášce pod e-mailem). E-mail, role i křížek
   mají stejnou výšku 38px → sedí přesně vedle sebe zarovnané na horní pruh.
   Křížek centruje svůj obsah na těch 38px, takže je vertikálně na střed inputu. */
.invite-row .invite-email{ min-height:38px; }
.invite-roles{ flex:1 1 45%; min-width:0; position:relative; }
.invite-roles-control{ width:100%; min-height:38px; }
.invite-roles-panel{ padding:var(--space-4); }
.invite-role-opt{
  display:flex; align-items:center; gap:var(--space-8);
  padding:var(--space-6) var(--space-8); border-radius:var(--radius-sm);
  cursor:pointer; font-size:var(--font-sm); color:var(--text);
}
.invite-role-opt:hover{ background:var(--surface-hover); }
.invite-del{ flex:none; height:38px; display:inline-flex; align-items:center; justify-content:center; }
.invite-add{ margin-top:var(--space-4); align-self:flex-start; }

/* Čárový kód v modalu (vizuální reprezentace). Proužky generuje warehouse-bins
   z názvu místa; .gap má průhledné pozadí = mezera mezi čarami. */
.barcode{
  display:flex; align-items:flex-end; justify-content:center;
  height:88px; gap:0;
  padding:var(--space-16) var(--space-12);
  /* Vždy světlý podklad + tmavé čáry (kvůli skenovatelnosti, i v dark režimu). */
  background:var(--barcode-bg); border:1px solid var(--border); border-radius:var(--radius);
}
.barcode .bar{ height:100%; background:var(--barcode-ink); }
.barcode .bar.gap{ background:transparent; }
.barcode-value{
  margin-top:var(--space-12); text-align:center;
  font-size:var(--font-md); font-weight:600; color:var(--text);
  letter-spacing:.04em; word-break:break-all;
}
.modal-head{
  padding:var(--space-18) var(--space-20) var(--space-14);
  border-bottom:1px solid var(--divider);
  display:flex;
  align-items:center;
  justify-content:space-between;
}
.modal-head h3{
  font-size:var(--font-lg);
  font-weight:700;
}
.modal-head .close{
  width:28px;
  height:28px;
  border-radius:var(--radius-sm);
  display:grid;
  place-items:center;
  color:var(--text-muted);
}
.modal-head .close:hover{ background:var(--surface-hover); color:var(--text) }
.modal-head .close:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring-strong) }
/* Search at the top of the type-picker modal — input styling from the .search
   base; this is layout-only (margin so the input fills the padded modal head). */
.type-picker-search{ margin:var(--space-12) var(--space-16) 0; }
.type-picker-empty{
  padding:var(--space-16); text-align:center;
  color:var(--text-muted); font-size:var(--font-sm);
}
.modal-body{
  padding:var(--space-14) var(--space-16) var(--space-18);
  display:flex;
  flex-direction:column;
  gap:var(--space-6);
}
/* [hidden] must beat the .modal-body .type-option{display:flex} below, otherwise
   the search filter sets the attribute but the row stays visible. */
.modal-body .type-option[hidden]{ display:none; }
.modal-body .type-option{
  display:flex;
  align-items:center;
  gap:var(--space-12);
  padding:var(--space-12) var(--space-14);
  border-radius:var(--radius);
  border:1px solid var(--border);
  background:var(--surface);
  text-align:left;
  cursor:pointer;
  transition:.14s ease;
  width:100%;
}
.modal-body .type-option:hover{
  border-color:var(--brand);
  background:var(--surface-hover);
}
.modal-body .type-option .icon{
  font-size:20px;
  width:32px;
  text-align:center;
  flex-shrink:0;
}
.modal-body .type-option .label{
  font-size:var(--font-md);
  font-weight:600;
  color:var(--text);
}


/* Doprava status colours (5 stages) — all via --stage-* tokens, so dark mode
   flips through the token overrides (no per-rule dark selectors needed). */
.status.stage-arrived{ background:var(--stage-arrived-bg); color:var(--stage-arrived-fg) }
.status.stage-arrived::before{ background:var(--stage-arrived-dot) }
.status.stage-ramp{ background:var(--stage-ramp-bg); color:var(--stage-ramp-fg) }
.status.stage-ramp::before{ background:var(--stage-ramp-dot) }
.status.stage-loading{ background:var(--stage-loading-bg); color:var(--stage-loading-fg) }
.status.stage-loading::before{ background:var(--stage-loading-dot) }
.status.stage-done{ background:var(--stage-done-bg); color:var(--stage-done-fg) }
.status.stage-done::before{ background:var(--stage-done-dot) }
.status.stage-departed{ background:var(--stage-departed-bg); color:var(--stage-departed-fg) }
/* Draft (rozpracovaná doprava) — neutral, not yet active. Dashed dot to read
   as "unfinished". */
.status.draft{ background:var(--surface-muted); color:var(--text-muted) }
.status.draft::before{ background:transparent; border:1.5px dashed var(--text-faint); }
.status.stage-departed::before{ background:var(--stage-departed-dot) }


/* -------------------------------------------------------------------------
   List patterns: side drawer (filters / columns), sticky actions, dropdowns,
   filter row, badges.

   Standard kit reused across every data table in the prototype. The drawer
   is a right-anchored slide-in panel with tabs.
   ------------------------------------------------------------------------- */

/* Drawer backdrop + panel */
/* Backdrop only dims for the MODAL drawer variant. The default drawer is a
   non-blocking preview panel — the list behind it stays visible AND clickable
   (pick row A → detail A, click row B → detail B, no close needed), so it gets
   no backdrop even when open. Add `.modal` to both drawer + backdrop to block. */
.drawer-backdrop{
  position:fixed;
  inset:0;
  background:var(--backdrop-soft);
  opacity:0;
  visibility:hidden;
  transition:opacity .22s ease, visibility .22s ease;
  z-index:80;
}
.drawer-backdrop.modal.open{ opacity:1; visibility:visible }
.drawer{
  /* Floating panel — detached from the window edge (12px inset = shell padding),
     fully rounded with a border all round, like the left sidebar.
     Stays in the DOM and slides in from the right (transform animates; display
     can't). Closed = pushed off-screen + hidden so it can't catch clicks. */
  position:fixed;
  top:12px; right:12px; bottom:12px;
  width:380px;
  max-width:calc(100vw - 24px);
  background:var(--drawer-bg);
  border:1px solid var(--drawer-border);
  border-radius:var(--radius-lg);
  box-shadow:var(--drawer-shadow);
  display:flex;
  flex-direction:column;
  overflow:hidden;          /* so children don't poke past the rounded corners */
  z-index:81;
  transform:translateX(calc(100% + 24px));   /* off-screen to the right (incl. the 12px inset) */
  visibility:hidden;
  /* visibility steps at the END when closing (delay .26s) so it doesn't vanish
     mid-slide; .open overrides the delay to 0 so it shows immediately. */
  transition:transform .26s cubic-bezier(.32,.72,0,1), visibility 0s .26s;
}
.drawer.open{ transform:translateX(0); visibility:visible; transition:transform .26s cubic-bezier(.32,.72,0,1), visibility 0s 0s }
.drawer-head{
  display:flex;
  align-items:center;
  padding:var(--space-14) var(--space-18);
  border-bottom:1px solid var(--divider);
  gap:var(--space-10);
}
.drawer-head h3{
  font-size:var(--font-lg);
  font-weight:700;
  flex:1;
}
.drawer-head .close{
  width:32px; height:32px;
  border-radius:var(--radius-sm);
  display:grid;
  place-items:center;
  color:var(--text-muted);
  cursor:pointer;
}
.drawer-head .close:hover{ background:var(--surface-hover); color:var(--text) }
.drawer-head .close:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring-strong) }
/* Same close button when it appears in a page header's actions (edit page),
   mirroring the right-panel head. */
.page-header .page-actions .close{
  width:32px; height:32px;
  border-radius:var(--radius-sm);
  display:grid;
  place-items:center;
  color:var(--text-muted);
  cursor:pointer;
}
.page-header .page-actions .close:hover{ background:var(--surface-hover); color:var(--text) }
.page-header .page-actions .close:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring-strong) }
.drawer-body{
  flex:1;
  overflow-y:auto;
  padding:var(--space-16) var(--space-18);
}
.drawer-foot{
  border-top:1px solid var(--divider);
  padding:var(--space-12) var(--space-18);
  display:flex;
  gap:var(--space-10);
  justify-content:flex-end;
}
/* display:flex above beats [hidden]'s display:none (class > attribute), so a
   hidden foot would stay visible — make [hidden] win explicitly. */
.drawer-foot[hidden]{ display:none }
/* When a record-stepper sits in the foot, push it to the left, actions stay right. */
.drawer-foot:has(.detail-nav){ justify-content:space-between }

/* Item actions bar — sits directly UNDER the drawer head (a thin strip of
   record-level actions: Smazat, Resetovat heslo, …). Kept separate from the
   form's Cancel/Save in the foot so the two don't mix. Mirrors the actions that
   live in a full-detail's page header. Scales to N buttons; wraps if needed. */
.drawer-actions{
  display:flex;
  flex-wrap:wrap;
  gap:var(--space-10);
  padding:var(--space-10) var(--space-18);
  border-bottom:1px solid var(--divider);
  justify-content:flex-end;   /* align right, like the foot's Cancel/Save */
}
/* Buttons match the footer's size (no shrink) so the two rows read as one family. */

/* Unsaved-changes status in the drawer foot — its own line above the pager/
   buttons row, matching the full-detail's footer message. Present only when the
   foot carries a .status-msg; otherwise the foot stays a single right-aligned row. */
.drawer-foot:has(.status-msg){
  flex-direction:column;
  align-items:stretch;
  gap:var(--space-10);
}
.drawer-foot .status-msg{
  display:flex; align-items:center; gap:var(--space-8);
  font-size:var(--font-md); color:var(--text-muted);
}
.drawer-foot .status-msg .pulse{
  width:8px; height:8px; border-radius:50%; flex:none;
  background:var(--warning);
  box-shadow:0 0 0 3px var(--warning-ring);
}
/* The pager + buttons keep their own row below the status. */
.drawer-foot .foot-row{
  display:flex; align-items:center; gap:var(--space-10);
  justify-content:flex-end;
}
.drawer-foot .foot-row:has(.detail-nav){ justify-content:space-between }

/* -------------------------------------------------------------------------
   Detail record stepper — prev/next arrows that walk the (filtered) list
   without leaving the detail. Lives on the left of the drawer-foot and the
   page-footer; the Cancel/Save actions stay on the right.
   ------------------------------------------------------------------------- */
.detail-nav{
  display:inline-flex;
  align-items:center;
  gap:var(--space-4);
}
.detail-nav button{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:32px;
  height:32px;
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface-raised);
  color:var(--text-muted);
  cursor:pointer;
  transition:background .12s, color .12s, border-color .12s;
}
.detail-nav button:hover:not(:disabled){
  background:var(--surface-muted);
  color:var(--text);
  border-color:var(--border-strong);
}
.detail-nav button:disabled{
  opacity:.4;
  cursor:not-allowed;
}
.detail-nav button svg{ width:16px; height:16px }
.detail-nav .pos{
  font-size:var(--font-sm);
  color:var(--text-faint);
  padding:0 var(--space-6);
  min-width:48px;
  text-align:center;
  font-variant-numeric:tabular-nums;
}
/* No counter (no selection) → collapse the gap so the arrows sit together. */
.detail-nav .pos:empty{
  padding:0;
  min-width:0;
}

/* -------------------------------------------------------------------------
   Detail view — one record, two containers chosen by a mode switch:
   • .detail--drawer  = floating side panel (right), like the column drawer
   • .detail--full    = covers the .main content area; the left sidebar stays
   ONE container, class flip (no DOM moving) so content/scroll/state survive.
   Reuses .drawer-head/-body/-foot for the internals (same visual language).
   ------------------------------------------------------------------------- */
.detail{
  position:fixed;
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-pop);
  display:flex;
  flex-direction:column;
  overflow:hidden;
  z-index:81;
  visibility:hidden;
  transition:transform .26s cubic-bezier(.32,.72,0,1), opacity .2s ease, visibility 0s .26s;
}
/* On open, make it visible immediately (delay 0); on close, hold visible until
   the slide-out finishes (delay .26s above) so it doesn't vanish mid-animation. */
.detail.open{ visibility:visible; transition:transform .26s cubic-bezier(.32,.72,0,1), opacity .2s ease, visibility 0s 0s }

/* Drawer mode — slides in from the right (same as the column drawer). */
.detail--drawer{
  top:var(--detail-inset); right:var(--detail-inset); bottom:var(--detail-inset);
  left:auto;
  width:var(--detail-drawer-w);
  max-width:calc(100vw - 2 * var(--detail-inset));
  transform:translateX(calc(100% + var(--detail-inset)));
  opacity:1;
}
.detail--drawer.open{ transform:translateX(0) }

/* Read-only hodnota pole (label nahoře, hodnota pod ním) — pro detail/side
   panely, kde se needituje. Drží stejnou výšku jako input, ať grid neposkakuje. */
.field-value{
  min-height:38px;
  display:flex;
  align-items:center;
  padding:var(--space-6) 0;
  font-size:var(--font-md);
  color:var(--text);
  line-height:1.4;
}
.field-value:empty::before{ content:"—"; color:var(--text-faint); }

/* Fullscreen mode — covers .main but leaves the left sidebar visible.
   Left edge = shell padding + sidebar width + grid gap (12 + sidebar-w + 12). */
.detail--full{
  top:var(--detail-inset); right:var(--detail-inset); bottom:var(--detail-inset);
  left:calc(var(--detail-inset) + var(--sidebar-w) + 12px);
  width:auto;
  transform:translateX(16px);   /* small offset for a gentle fade-in, not a full slide */
  opacity:0;
}
.detail--full.open{ transform:translateX(0); opacity:1 }
/* Follow the collapsed sidebar (64px) so the detail's left edge tracks the grid. */
.shell.sidebar-collapsed ~ .detail--full{
  left:calc(var(--detail-inset) + 64px + 12px);
}

/* Mode switch — segmented control in the detail head, beside the close button. */
.detail-mode{
  display:inline-flex;
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  overflow:hidden;
  margin-left:auto;   /* push it (and the close) to the right of the title */
}
.detail-mode button{
  width:30px; height:30px;
  display:grid; place-items:center;
  color:var(--text-muted);
  background:transparent;
  cursor:pointer;
}
.detail-mode button + button{ border-left:1px solid var(--border) }
.detail-mode button:hover{ background:var(--surface-hover); color:var(--text) }
.detail-mode button.is-active{ background:var(--surface-hover); color:var(--brand-dark) }
.detail-mode button:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring-strong) }
/* When the switcher sits in the head, the close button no longer needs the
   auto-margin (the switcher already took it). */
.detail .drawer-head .detail-mode + .close{ margin-left:var(--space-8) }
/* Detail-panel title — one step below the full-view page title (--font-2xl):
   the panel is a narrower context, so 22px reads better there while staying
   clearly above the 20px section heads inside it (22 title > 20 section > 16
   tool). The column-manager drawer keeps its smaller --font-lg head. */
.detail .drawer-head h3{ font-size:var(--font-xl2) }

/* Detail hero — avatar + name + status at the top of a record detail. */
.detail-hero{
  display:flex;
  align-items:center;
  gap:var(--space-14);
  padding-bottom:var(--space-16);
  margin-bottom:var(--space-4);
  border-bottom:1px solid var(--divider);
}
.detail-hero .avatar{
  width:48px; height:48px;
  border-radius:50%;
  display:grid; place-items:center;
  color:var(--on-accent);
  font-weight:600;
  font-size:var(--font-lg);
  flex-shrink:0;
}
.detail-hero-name{
  font-size:var(--font-lg);
  font-weight:700;
  color:var(--text);
  margin-bottom:var(--space-4);
}

/* Two-column section layout for a roomy FULL detail page (e.g. user: Profil 3 :
   Role 2). The drawer never uses this wrapper, so its sections stack vertically. */
.detail-cols{
  display:grid;
  grid-template-columns:3fr 2fr;
  gap:32px;
  align-items:start;
}
.detail-cols > .section + .section{ margin-top:0 }  /* columns, not stacked */
@media (max-width:1100px){
  .detail-cols{ grid-template-columns:1fr; gap:0 }
  .detail-cols > .section + .section{ margin-top:36px }  /* stack again when narrow */
}
.detail .card,
.detail .role-list{ max-height:none }
/* Edit-role form — shared between the full page (two columns) and the detail
   drawer (one column). Moved here from edit-role.html's inline <style>. */
.edit-role-layout{
  display:grid;
  grid-template-columns:minmax(0, 1fr) 300px;
  gap:var(--space-20);
}
@media (max-width:1100px){
  .edit-role-layout{ grid-template-columns:1fr }
}
.detail .edit-role-layout{ grid-template-columns:1fr; gap:var(--space-16) }
/* Administrator banner (shown when the role is flagged as administrator). */
.admin-banner{
  display:flex; align-items:center; gap:var(--space-14);
  padding:var(--space-14) var(--space-18); margin-bottom:var(--space-18);
  background:linear-gradient(90deg, rgba(239,68,68,.08), rgba(239,68,68,.02));
  border:1px solid rgba(239,68,68,.35);
  border-radius:var(--radius);
  color:var(--danger-fg);
}
.admin-banner .icon{
  width:36px; height:36px; border-radius:50%;
  background:rgba(239,68,68,.18);
  display:grid; place-items:center; flex-shrink:0;
  color:var(--danger);
}
.admin-banner .text{ flex:1 }
.admin-banner .text strong{ font-weight:700; display:block; margin-bottom:var(--space-2) }
.admin-banner .text span{ font-size:var(--font-sm); color:var(--danger-fg) }
.admin-toggle-row{
  display:flex; align-items:center; gap:var(--space-14);
  padding:var(--space-14) var(--space-18);
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  margin-bottom:var(--space-18);
  cursor:pointer;
}
.admin-toggle-row.on{
  background:rgba(239,68,68,.04);
  border-color:rgba(239,68,68,.35);
}
.admin-toggle-row .switch{
  width:36px; height:20px;
  border-radius:var(--radius-pill);
  background:var(--border-strong);
  position:relative; flex-shrink:0;
  transition:.18s ease;
}
.admin-toggle-row .switch::after{
  content:""; position:absolute; top:2px; left:2px;
  width:16px; height:16px; border-radius:50%;
  background:var(--white);
  box-shadow:var(--shadow-knob);
  transition:.18s ease;
}
.admin-toggle-row.on .switch{ background:var(--danger) }
.admin-toggle-row.on .switch::after{ left:18px }
.admin-toggle-row .meta{ flex:1 }
.admin-toggle-row .meta strong{ font-weight:700; display:block; margin-bottom:var(--space-2) }
.admin-toggle-row .meta span{ font-size:var(--font-sm); color:var(--text-muted) }
.admin-toggle-row.on .meta strong{ color:var(--danger-fg) }
.admin-toggle-row.on .meta span{ color:var(--danger-fg) }

/* Administrátor je vlastnost uživatele → v seznamu se značí malým pillem
   vedle role. Danger tón (stejná signální barva jako admin toggle). */
.admin-badge{
  display:inline-flex; align-items:center; gap:var(--space-4);
  padding:2px var(--space-8); border-radius:var(--radius-pill);
  font-size:var(--font-sm); font-weight:600; line-height:1.4;
  color:var(--danger-fg); background:var(--danger-soft);
}
.admin-badge svg{ width:13px; height:13px }

/* ===== Switch field — a reusable on/off toggle that lives in a .form-grid like
   any other field. Label on top (matches .form-field), brand-coloured pill below.
   Drives .switch (the visual pill) off a real hidden checkbox so it's keyboard-
   and form-native. In Angular = <nf-switch [(ngModel)]>. */
.switch-field{ display:flex; flex-direction:column; gap:var(--space-6) }
.switch-field > label{ font-size:var(--font-sm); font-weight:500; color:var(--text-muted) }
.switch-field .switch-control{
  display:inline-flex; align-items:center; gap:var(--space-10);
  cursor:pointer; align-self:flex-start;
}
.switch-field .switch-control input{
  position:absolute; opacity:0; width:0; height:0; margin:0;
}
.switch-field .switch{
  width:36px; height:20px; flex:none;
  border-radius:var(--radius-pill);
  background:var(--border-strong);
  position:relative;
  transition:background .18s ease;
}
.switch-field .switch::after{
  content:""; position:absolute; top:2px; left:2px;
  width:16px; height:16px; border-radius:50%;
  background:var(--white);
  box-shadow:var(--shadow-knob);
  transition:transform .18s ease;
}
.switch-field .switch-control input:checked + .switch{ background:var(--brand) }
.switch-field .switch-control input:checked + .switch::after{ transform:translateX(16px) }
.switch-field .switch-control input:focus-visible + .switch{
  box-shadow:0 0 0 3px var(--brand-ring);
}
.switch-field .switch-control .switch-label{ font-size:var(--font-md); color:var(--text) }
.switch-field .switch-control input:disabled + .switch{ opacity:.5 }
.switch-field.is-disabled .switch-control{ cursor:not-allowed }

/* Eventual-consistency hint near the save footer. */
/* Permission search bar: keeps the standard .toolbar look (sidebar-bg + border)
   in BOTH the full page and the drawer — they must stay in sync. Just make it
   sticky and add a gap before the first group. */
.perm-toolbar{
  position:sticky; top:0; z-index:5;
  margin-bottom:var(--space-16);
}
/* Role summary side panel (full page only; hidden in the narrow drawer). */
.summary-panel{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  padding:var(--space-18);
  position:sticky; top:20px;
}
.summary-panel h3{ font-size:var(--font-md); font-weight:700; margin-bottom:var(--space-14) }
.summary-stat{
  display:flex; align-items:center; justify-content:space-between;
  padding:var(--space-10) 0; border-bottom:1px solid var(--divider);
  font-size:var(--font-md);
}
.summary-stat:last-of-type{ border-bottom:0 }
.summary-stat .v{ font-weight:700; font-variant-numeric:tabular-nums }
.summary-stat.changed .v{ color:var(--brand) }
.summary-list{ margin-top:var(--space-14); padding-top:var(--space-14); border-top:1px solid var(--divider) }
.summary-list h4{
  font-size:var(--font-xs); font-weight:700; color:var(--text-muted);
  letter-spacing:.08em; text-transform:uppercase; margin-bottom:var(--space-10);
}
/* Overlapping avatar stack — reusable "kdo používá" cluster (also used in the summary panel). */
.users-using{ display:flex; align-items:center }
.users-using .av{
  width:26px; height:26px; border-radius:50%;
  border:2px solid var(--surface); margin-left:-6px;
  display:grid; place-items:center;
  color:var(--on-accent); font-size:var(--font-xs); font-weight:600;
}
.users-using .av:first-child{ margin-left:0 }
.users-using .more{ margin-left:var(--space-8); font-size:var(--font-sm); color:var(--text-muted) }
/* In the drawer the summary panel adds nothing useful — hide it. */
.detail .summary-panel{ display:none }

/* -------------------------------------------------------------------------
   Charts — a small family of data viz on plain SVG/CSS so they port cleanly (no
   charting lib), Revolut-clean (see screens/IMG_7637-7642). All driven by data
   attributes a tiny render fn reads (charts.js): a single value (arc) or a list
   of {label,value} (bar/ring/line/area). Series colours from --chart-1..6 +
   --chart-track; one rounding language via --chart-bar-radius / --chart-stroke.

   .chart-arc   — a 270° gauge for ONE share; value arc + track, number in the gap.
   .chart-bar   — thin pill columns; --bar-pct sets height, faint X baseline,
                  optional dotted reference lines (.chart-bar-ref) labelled right.
   .chart-pie   — a thin ring of filled annular segments with rounded corners and
                  gaps (charts.js draws the paths); optional centre label + legend.
   .chart-line  — a smooth (bezier) trend, no dots, faint X baseline; .is-area
                  (via the renderer) adds a vertical gradient fill to the baseline.
   ------------------------------------------------------------------------- */

/* Arc gauge — single value, 270° sweep. */
.chart-arc{ position:relative; width:var(--arc-size, 140px); height:var(--arc-size, 140px); flex:none }
.chart-arc svg{ width:100%; height:100%; transform:rotate(135deg) }   /* open the gap at the bottom */
.chart-arc .arc-track{ fill:none; stroke:var(--chart-track); stroke-width:var(--chart-stroke); stroke-linecap:round; stroke-dasharray:75 100 }
.chart-arc .arc-value{
  fill:none; stroke:var(--chart-1); stroke-width:var(--chart-stroke); stroke-linecap:round;   /* slim stroke → gentle round cap, matches bar radius */
  stroke-dasharray:calc(var(--arc-pct, 0) * .75) 100;   /* value scaled into the 270° (=75u) sweep */
}
.chart-arc.is-warn .arc-value{ stroke:var(--warning) }
.chart-arc.is-low  .arc-value{ stroke:var(--danger) }
.chart-arc.is-good .arc-value{ stroke:var(--success) }
.chart-arc .arc-value{ transition:stroke-dasharray .4s ease }
.chart-arc .arc-label{ position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; gap:var(--space-2) }
.chart-arc .arc-num{ font-size:var(--font-xl); font-weight:700; line-height:1; font-variant-numeric:tabular-nums }
.chart-arc .arc-cap{ font-size:var(--font-xs); color:var(--text-muted); font-weight:600 }

/* Bar chart — Revolut-style: thin pill bars (rounded BOTH ends), only a faint X
   baseline (no Y axis, no value-on-top). Optional dotted reference lines (max /
   average) labelled on the RIGHT — the signature Revolut touch. Structure:
   .chart-bar-wrap › .chart-bar-plot (holds bars + reference lines) › caption row. */
.chart-bar-wrap{ display:flex; flex-direction:column }
.chart-bar-plot{ position:relative; border-bottom:1px solid var(--border); flex:1 }   /* X baseline only */
/* Volitelná osa Y (data-axis="y") — měřítko vlevo, plot + osa v řádku. */
.chart-bar-plotrow{ display:flex; align-items:stretch; gap:var(--space-8) }
.chart-bar-yaxis{
  display:flex; flex-direction:column; justify-content:space-between;
  font-size:var(--font-xs); color:var(--text-faint); font-weight:600;
  text-align:right; font-variant-numeric:tabular-nums; padding-bottom:var(--space-2);
}
.chart-bar-caps.has-yaxis{ margin-left:30px }
.chart-bar{ display:flex; align-items:flex-end; gap:var(--space-16); height:var(--bar-h, 170px); position:relative; z-index:1 }
.chart-bar .bar-col{ flex:1; height:100%; display:flex; align-items:flex-end; justify-content:center; min-width:0 }
.chart-bar .bar-track{ height:100%; width:100%; max-width:var(--bar-w, 20px); display:flex; align-items:flex-end; position:relative }
.chart-bar .bar-fill{
  width:100%; height:calc(var(--bar-pct, 0) * 1%);
  background:var(--chart-1); border-radius:var(--chart-bar-radius);   /* shared chart rounding */
  transition:height .4s ease, opacity .15s ease; min-height:var(--bar-w, 20px);
}
/* Interaktivní zvýraznění (data-hover) — bublina s hodnotou nad sloupcem +
   ztlumení ostatních. Bublina sedí na vršku výplně (bottom = výška sloupce). */
.chart-bar .bar-col{ transition:opacity .15s ease }
.chart-bar .bar-col.is-dim{ opacity:.4 }
.chart-bar .bar-val{
  position:absolute; left:50%; bottom:calc(var(--bar-pct, 0) * 1%);
  transform:translate(-50%, -6px);
  background:var(--text); color:var(--surface); font-size:var(--font-xs); font-weight:700;
  line-height:1; white-space:nowrap; padding:3px 7px; border-radius:var(--radius-sm);
  font-variant-numeric:tabular-nums; opacity:0; pointer-events:none; transition:opacity .15s ease;
}
.chart-bar .bar-col.is-hot .bar-val{ opacity:1 }
/* Dotted reference lines (max / avg), value label on the right. */
.chart-bar-ref{ position:absolute; left:0; right:0; bottom:calc(var(--ref-pct, 0) * 1%); height:0; border-top:1px dotted var(--border-strong); z-index:0 }
.chart-bar-ref.is-avg{ border-top-color:var(--chart-1); opacity:.7 }
.chart-bar-ref .ref-val{ position:absolute; right:0; top:-0.85em; font-size:var(--font-xs); font-weight:600; color:var(--text-muted); background:var(--surface); padding-left:var(--space-6) }
.chart-bar-ref.is-avg .ref-val{ color:var(--chart-1) }
/* Caption row, aligned to the columns under the X axis. */
.chart-bar-caps{ display:flex; gap:var(--space-16); margin-top:var(--space-6) }
.chart-bar-caps .bar-cap{ flex:1; font-size:var(--font-xs); color:var(--text-muted); font-weight:600; text-align:center; white-space:nowrap }
/* Per-column series colour (cycles 1..6). */
.chart-bar .bar-col:nth-child(6n+1) .bar-fill{ background:var(--chart-1) }
.chart-bar .bar-col:nth-child(6n+2) .bar-fill{ background:var(--chart-2) }
.chart-bar .bar-col:nth-child(6n+3) .bar-fill{ background:var(--chart-3) }
.chart-bar .bar-col:nth-child(6n+4) .bar-fill{ background:var(--chart-4) }
.chart-bar .bar-col:nth-child(6n+5) .bar-fill{ background:var(--chart-5) }
.chart-bar .bar-col:nth-child(6n+6) .bar-fill{ background:var(--chart-6) }
/* Single-tone variant — all bars one accent (e.g. a time series). */
.chart-bar.is-mono .bar-fill{ background:var(--chart-1) !important }

/* Stacked bar — one horizontal pill split into proportional segments (shares of
   a whole), on a muted track. Used for "X of N" proportion readouts (e.g. the
   Inventura coverage panel: covered vs remaining). Segments carry --chart-N (or
   tone classes); an optional label row sits underneath. */
.chart-stack{ display:flex; flex-direction:column; gap:var(--space-6) }
.chart-stack-bar{ display:flex; height:var(--stack-h, var(--space-10)); border-radius:var(--radius-pill); overflow:hidden; background:var(--chart-track) }
.chart-stack-bar .stack-seg{ height:100%; transition:width .4s ease, opacity .15s ease }
/* Bílé linky mezi segmenty: gap na flexu udělá mezeru, ta ukáže pozadí baru
   (přepnuté na surface = bílá). 2px řez oddělí sousední hodnoty, ať nesplývají.
   Jen běžný rozpad — fill mód má 1 segment, tam žádné dělení. */
.chart-stack:not(.is-fill) .chart-stack-bar{ gap:1px; background:var(--surface) }
/* Interaktivní zvýraznění (data-hover) — aktivní segment plný, ostatní ztlumené. */
.chart-stack-bar .stack-seg.is-dim{ opacity:.35 }
.chart-stack-labels span.is-hot{ color:var(--text); font-weight:700 }
.chart-stack-bar .stack-seg:nth-child(6n+1){ background:var(--chart-1) }
.chart-stack-bar .stack-seg:nth-child(6n+2){ background:var(--chart-2) }
.chart-stack-bar .stack-seg:nth-child(6n+3){ background:var(--chart-3) }
.chart-stack-bar .stack-seg:nth-child(6n+4){ background:var(--chart-4) }
.chart-stack-bar .stack-seg:nth-child(6n+5){ background:var(--chart-5) }
.chart-stack-bar .stack-seg:nth-child(6n+6){ background:var(--chart-6) }
/* Two-tone proportion (covered vs remaining): first segment accent, rest stays track. */
.chart-stack.is-fill .stack-seg:first-child{ background:var(--brand) }
.chart-stack.is-fill .stack-seg{ background:transparent }
.chart-stack-labels{ display:flex; justify-content:space-between; gap:var(--space-12); font-size:var(--font-sm); color:var(--text-muted) }
/* Legenda pod stacked barem — VODOROVNÁ (položky vedle sebe), tečka + popisek + %.
   Vyšší specificita (obě třídy), ať přebije sloupcový .chart-pie-legend. */
.chart-pie-legend.chart-stack-legend{ flex-direction:row; flex-wrap:wrap; gap:var(--space-8) var(--space-16); margin-top:var(--space-10) }
.chart-stack-legend .legend-item{ gap:var(--space-6); flex:none }
.chart-stack-legend .legend-val{ margin-left:var(--space-2) }

/* Ring chart — Revolut-style: a clean ring of rounded, gapped segments (no full
   pie). Each segment is an SVG stroke whose dasharray length = its share of the
   circumference. Rounded caps + gaps give the signature "separate arcs" look; a
   thin stroke on a large radius keeps the caps from bulging. The JS picks the
   radius so the stroke stays inside the 36×36 viewBox. Optional centre label. */
.chart-pie-wrap{ display:flex; align-items:center; gap:var(--space-24); flex-wrap:wrap }
/* Variant: legenda POD ringem (řádek, zalamovací) místo vedle. Zapne se přes
   data-legend="below" na hostiteli grafu. Vhodí se do úzkých karet. */
[data-legend="below"] .chart-pie-wrap{ flex-direction:column; align-items:center; gap:var(--space-16) }
[data-legend="below"] .chart-pie-legend{
  flex-direction:row; flex-wrap:wrap; justify-content:center;
  gap:var(--space-8) var(--space-16);
}
[data-legend="below"] .chart-pie-legend .legend-item{ gap:var(--space-6) }
[data-legend="below"] .chart-pie-legend .legend-val{ margin-left:var(--space-2) }
.chart-pie{ position:relative; width:var(--pie-size, 150px); height:var(--pie-size, 150px); flex:none }
.chart-pie svg{ width:100%; height:100% }   /* segments start at 12 o'clock via the path angles */
.chart-pie .pie-seg{ stroke:none; transition:opacity .15s }   /* filled annular path (rounded corners drawn in charts.js) */
/* Interaktivní zvýraznění (data-hover): aktivní segment plný, ostatní ztlumené. */
.chart-pie .pie-seg.is-dim{ opacity:.28 }
.chart-pie-legend .legend-item.is-dim{ opacity:.4; transition:opacity .15s }
/* Optional centre label (ring only — a pie has no hole to put it in). */
.chart-pie .pie-center{ position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; gap:var(--space-2); pointer-events:none }
.chart-pie .pie-center-num{ font-size:var(--font-lg); font-weight:700; line-height:1; font-variant-numeric:tabular-nums }
.chart-pie .pie-center-cap{ font-size:var(--font-xs); color:var(--text-muted); font-weight:600 }
/* Shared legend dot (pie + line). One swatch size for every chart legend. */
.chart-pie-legend .legend-dot,
.chart-line .line-legend .legend-dot{ width:var(--chart-dot); height:var(--chart-dot); border-radius:var(--radius-xs); flex:none }
.chart-pie-legend{ display:flex; flex-direction:column; gap:var(--space-8); font-size:var(--font-sm) }
.chart-pie-legend .legend-item{ display:flex; align-items:center; gap:var(--space-8) }
.chart-pie-legend .legend-val{ margin-left:auto; color:var(--text-muted); font-variant-numeric:tabular-nums; font-weight:600 }

/* Line / area chart — Revolut-style: a clean SMOOTH (bezier) trend, no dots, no
   grid. The JS maps points into a 100×Hu SVG (preserveAspectRatio:none) and
   draws a smoothed path; .is-area fills a vertical gradient down to the baseline
   (fades out). A thicker rounded stroke; the final point gets a small accent dot
   to anchor "now". Captions sit below on an evenly-spaced flex row. */
.chart-line{ display:flex; flex-direction:column; gap:var(--space-8) }
.chart-line svg{ width:100%; height:var(--line-h, 150px); overflow:visible; display:block }
.chart-line .line-path{ fill:none; stroke:var(--line-stroke, var(--chart-1)); stroke-width:var(--chart-stroke); stroke-linecap:round; stroke-linejoin:round; vector-effect:non-scaling-stroke }
.chart-line .line-area{ stroke:none }   /* fill set inline to a per-chart gradient */
.chart-line .line-axis{ stroke:var(--border); stroke-width:1; vector-effect:non-scaling-stroke }
.chart-line .line-grid{ stroke:var(--border); stroke-width:1; vector-effect:non-scaling-stroke; opacity:.5 }
/* Vodorovné referenční linky (data-ref="max,avg") — stejný jazyk jako u bar grafu. */
.chart-line .line-ref{ stroke:var(--border-strong); stroke-width:1; stroke-dasharray:2 2; vector-effect:non-scaling-stroke }
.chart-line .line-ref.is-avg{ stroke:var(--chart-1); opacity:.7 }
.chart-line .line-ref-val{
  position:absolute; right:0; transform:translateY(-50%);
  font-size:var(--font-xs); font-weight:600; color:var(--text-muted);
  background:var(--surface); padding-left:var(--space-6); font-variant-numeric:tabular-nums;
}
.chart-line .line-ref-val.is-avg{ color:var(--chart-1) }
/* Popisky X jsou absolutně pozicované na X bodů (left:x(i)%), vycentrované na
   bod přes translateX(-50%); krajní zarovnané dovnitř, ať se neořežou. */
.chart-line .line-caps{ position:relative; height:1.2em; font-size:var(--font-xs); color:var(--text-muted); font-weight:600 }
.chart-line .line-caps span{ position:absolute; white-space:nowrap; transform:translateX(-50%) }
.chart-line .line-caps span.is-first{ transform:none }
.chart-line .line-caps span.is-last{ transform:translateX(-100%) }
/* Y osa (data-axis="y") — min/max vlevo, plot = osa + svg v řádku. */
.chart-line .line-plot{ display:flex; align-items:stretch; gap:var(--space-8) }
.chart-line .line-plot .line-svg-wrap{ flex:1 }
/* Marker "teď" — tečka na posledním bodu + bublina s aktuální hodnotou.
   Overlay nad SVG (kruh by se v napínaném SVG zdeformoval na elipsu). */
.chart-line .line-svg-wrap{ position:relative }
.chart-line .line-now-dot{
  position:absolute; width:var(--chart-dot); height:var(--chart-dot); border-radius:50%;
  background:var(--line-stroke, var(--chart-1));
  border:2px solid var(--surface);
  transform:translate(-50%, -50%); pointer-events:none;
  box-shadow:0 0 0 3px color-mix(in srgb, var(--line-stroke, var(--chart-1)) 18%, transparent);
}
.chart-line .line-now-val{
  position:absolute; bottom:calc(100% + 6px); left:50%; transform:translateX(-50%);
  background:var(--line-stroke, var(--chart-1)); color:var(--on-accent);
  font-size:var(--font-xs); font-weight:700; line-height:1; white-space:nowrap;
  padding:3px 7px; border-radius:var(--radius-sm); font-variant-numeric:tabular-nums;
}
/* Poslední bod je u pravého kraje — bublinu zarovnáme doprava, ať nepřeteče. */
.chart-line .line-now-dot.is-last .line-now-val{ left:auto; right:0; transform:none }
/* Interaktivní hover vrstva (data-hover="true") — neviditelné zóny nad body +
   kurzorová tečka, která skáče na bod pod myší. */
.chart-line .line-hover{ position:absolute; inset:0; display:flex; touch-action:none }
.chart-line .line-hover-zone{ flex:1; cursor:pointer }
.chart-line .line-hover-dot{
  position:absolute; width:var(--chart-dot); height:var(--chart-dot); border-radius:50%;
  background:var(--line-stroke, var(--chart-1)); border:2px solid var(--surface);
  transform:translate(-50%, -50%); pointer-events:none;
  box-shadow:0 0 0 3px color-mix(in srgb, var(--line-stroke, var(--chart-1)) 18%, transparent);
}
.chart-line .line-yaxis{
  position:relative;   /* ref hodnoty se pozicují absolutně na svou úroveň */
  display:flex; flex-direction:column; justify-content:space-between;
  font-size:var(--font-xs); color:var(--text-faint); font-weight:600;
  text-align:right; font-variant-numeric:tabular-nums;
  padding:var(--space-2) 0;
}
/* Ref hodnota (avg/max) jako součást osy — na své vertikální úrovni, vpravo. */
.chart-line .line-yaxis .ya-ref{
  position:absolute; right:0; transform:translateY(-50%);
  color:var(--text-muted);
}
.chart-line .line-yaxis .ya-ref.is-avg{ color:var(--chart-1) }
/* Když je Y osa, popisky X odsadíme o její šířku, ať sedí pod body. */
/* Odsazení popisků o šířku Y osy (margin, ne padding — absolutní děti se pozicují
   od content-boxu, takže levý kraj se posune a left:0% sedí na začátek grafu). */
.chart-line .line-caps.has-yaxis{ margin-left:30px }
/* Legend for multi-series line/area (series names + colour dots). */
.chart-line .line-legend{ display:flex; flex-wrap:wrap; gap:var(--space-16); font-size:var(--font-sm); color:var(--text-muted) }
.chart-line .line-legend .legend-item{ display:flex; align-items:center; gap:var(--space-8) }

/* -------------------------------------------------------------------------
   Coverage panel — overview card above the Inventury list. A stacked bar
   (covered vs not, in neutral/accent tones — NOT the green/red of the per-row
   dots, which mean per-location state) + period switch + a "plan the rest"
   CTA + a collapsible per-location breakdown. Surfaces how complete the asset
   picture is. All sizing on design tokens; card radius matches sibling cards.
   ------------------------------------------------------------------------- */
.coverage-panel{
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--radius); padding:var(--space-20);
  margin-bottom:var(--space-16);
}
.coverage-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:var(--space-16); flex-wrap:wrap; margin-bottom:var(--space-16) }
.coverage-head h2{ font-size:var(--font-lg); font-weight:700 }
.coverage-sub{ font-size:var(--font-sm); color:var(--text-muted); margin-top:var(--space-2) }
/* ===== Segmentovaný přepínač (JEDNA komponenta) =====
   Přepínač vzájemně výlučné volby z malé sady (období 3/6/12, měřítko osy Den/
   Standard/Detail, hustota). Šedý „pill" s rámečkem + výška 32 px (lícuje s form
   poli), aktivní segment = bílý píst se stínem. Dřív existovala duplicitní
   `.view-switch` (Měřítko dopravy) — 23.7. sjednoceno na `.seg`. */
.seg{ display:inline-flex; align-items:stretch; height:32px; background:var(--surface-muted); border:1px solid var(--border); border-radius:var(--radius-sm); padding:var(--space-2); gap:var(--space-2) }
.seg-btn{
  display:inline-flex; align-items:center; gap:var(--space-6);
  border:0; background:transparent; cursor:pointer;
  padding:0 var(--space-12); border-radius:var(--radius-xs);   /* výšku dá stretch obalu → celkem 32px */
  font-size:var(--font-sm); font-weight:600; color:var(--text-muted);
  white-space:nowrap; transition:.14s ease;
}
.seg-btn svg{ color:var(--text-faint) }
.seg-btn:hover:not(.active){ color:var(--text) }
.seg-btn.active{ background:var(--surface); color:var(--text); box-shadow:var(--shadow-sm) }
.seg-btn.active svg{ color:var(--brand) }
.seg-btn:focus-visible{ outline:none; box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--brand-ring-strong) }

/* -------------------------------------------------------------------------
   Choice cards — vizuální výběr z několika možností. Každá dlaždice = radio
   s náhledem (.cc-preview), popiskem a nápovědou; aktivní má brand rámeček +
   fajfku. Obecná komponenta (hustota tabulek, motiv, layout…).
   Markup: <div class="choice-cards"><label class="choice-card">
             <input type="radio" name=".." value=".." /><span class="cc-preview">…</span>
             <span class="cc-title">..</span><span class="cc-desc">..</span></label>…</div>
   ------------------------------------------------------------------------- */
.choice-cards{ display:grid; grid-template-columns:repeat(auto-fit, minmax(200px, 1fr)); gap:var(--space-12); }
.choice-card{
  position:relative; display:flex; flex-direction:column; gap:var(--space-8);
  padding:var(--space-12); cursor:pointer;
  border:1px solid var(--border); border-radius:var(--radius);
  background:var(--surface); transition:border-color .14s ease, box-shadow .14s ease;
}
.choice-card:hover{ border-color:var(--border-strong); }
.choice-card > input{ position:absolute; opacity:0; pointer-events:none; }
.choice-card:has(input:checked){ border-color:var(--brand); box-shadow:0 0 0 1px var(--brand); }
/* Fajfka v rohu aktivní dlaždice. */
.choice-card::after{
  content:""; position:absolute; top:var(--space-10); right:var(--space-10);
  width:18px; height:18px; border-radius:50%;
  border:1.5px solid var(--border-strong); background:var(--surface);
  transition:.14s ease;
}
.choice-card:has(input:checked)::after{
  border-color:var(--brand); background:var(--brand)
    url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>') center / 12px no-repeat;
}
.cc-title{ font-size:var(--font-md); font-weight:600; color:var(--text); }
.cc-desc{ font-size:var(--font-sm); color:var(--text-muted); }
/* Náhled — schématické řádky tabulky; hustota se řídí --cc-gap. Pevná výška,
   aby náhledy (a tím i text pod nimi) lícovaly napříč dlaždicemi bez ohledu na
   rozestup řádků; řádky vycentrované svisle. */
.cc-preview{
  display:flex; flex-direction:column; justify-content:center; gap:var(--cc-gap, 6px);
  height:96px; box-sizing:border-box;
  padding:var(--space-10); border-radius:var(--radius-sm);
  background:var(--surface-muted); pointer-events:none;
}
.cc-preview .cc-line{ height:6px; border-radius:3px; background:var(--border-strong); opacity:.55; }
.cc-preview .cc-line:first-child{ opacity:.85; }   /* „hlavička" trochu výraznější */
/* Vybraná karta obarví řádky náhledu do brand (konzistentní s mřížkovou variantou). */
.choice-card:has(input:checked) .cc-preview .cc-line{ background:var(--brand); }
.choice-card[data-density="compact"] .cc-preview{ --cc-gap:3px; }
.choice-card[data-density="comfortable"] .cc-preview{ --cc-gap:9px; }
/* Varianta náhledu s mřížkou buněk (místo řádků) — vystihuje pokrytí celku:
   vyplněné buňky = zahrnuto (Úplná = vše, Dílčí = jen část). Škáluje čistě
   (žádné tenké linky). Aktivní karta obarví vyplněné buňky do brand. */
.cc-preview--grid{ align-items:center; }
.cc-grid{ display:grid; grid-template-columns:repeat(3, 1fr); gap:4px; width:56px; height:56px; }
.cc-grid i{ border-radius:3px; background:var(--surface); box-shadow:inset 0 0 0 1px var(--border-strong); }
.cc-grid i.on{ background:var(--border-strong); box-shadow:none; }
.choice-card:has(input:checked) .cc-grid i.on{ background:var(--brand); }

/* Headline — "X z N lokací zkontrolováno" + a quiet % tag. Big number reads
   as part-to-whole better than a bare percentage (which lacks the "of N"). */
.coverage-headline{ display:flex; align-items:baseline; gap:var(--space-8); flex-wrap:wrap; margin-bottom:var(--space-12) }
.cov-big{ font-size:var(--font-2xl); font-weight:700; line-height:1; font-variant-numeric:tabular-nums }
.cov-big-unit{ font-size:var(--font-md); color:var(--text-muted) }
.cov-pct-tag{
  margin-left:auto; font-size:var(--font-sm); font-weight:600;
  color:var(--text-muted); font-variant-numeric:tabular-nums;
}
/* Stacked coverage bar — covered share (brand) on a muted track. Quiet tone:
   accent + grey, deliberately NOT red (incomplete ≠ error). */
/* The bar itself IS the chart stacked-bar (fill variant) — same shape as
   .chart-stack-bar so there's one proportion-bar implementation. The panel keeps
   its own markup (the JS sets #cov-bar width directly), it just shares the look. */
.coverage-bar{
  display:flex; height:var(--space-10); border-radius:var(--radius-pill);
  overflow:hidden; background:var(--chart-track);
}
.coverage-bar .seg-covered{ background:var(--brand); border-radius:var(--radius-pill); transition:width .4s ease }
/* Segment labels under the bar — covered (left) · remaining (right). Same as .chart-stack-labels. */
.coverage-bar-labels{
  display:flex; justify-content:space-between; gap:var(--space-12);
  margin-top:var(--space-6); font-size:var(--font-sm); color:var(--text-muted);
}
/* Action row: breakdown toggle (left) + primary action (right) on one line. */
.coverage-actions{ display:flex; align-items:center; justify-content:space-between; gap:var(--space-16); margin-top:var(--space-16); flex-wrap:wrap }
/* Collapsible breakdown toggle. */
.coverage-toggle{
  display:inline-flex; align-items:center; gap:var(--space-6);
  border:0; background:transparent; cursor:pointer;
  font-size:var(--font-sm); font-weight:600; color:var(--brand); padding:0;
}
.coverage-toggle .chev{ width:var(--space-16); height:var(--space-16); transition:transform .18s ease }
.coverage-toggle[aria-expanded="true"] .chev{ transform:rotate(180deg) }
/* Per-location breakdown — compact rows with a state dot + relative age. */
.coverage-breakdown{
  margin-top:var(--space-16); padding-top:var(--space-16);
  border-top:1px solid var(--divider);
}
.coverage-list{
  display:grid; grid-template-columns:repeat(auto-fill, minmax(260px, 1fr));
  gap:var(--space-2) var(--space-20); max-height:280px; overflow-y:auto;
}
.cov-row{ display:flex; align-items:center; gap:var(--space-8); padding:var(--space-6) 0; font-size:var(--font-sm) }
/* Binary state of a location: covered (within the period) vs not. */
.cov-dot{ width:var(--space-8); height:var(--space-8); border-radius:var(--radius-pill); flex:none }
.cov-dot.covered{ background:var(--success) }
.cov-dot.uncovered{ background:var(--danger) }
.cov-row .cov-name{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.cov-row .cov-date{ color:var(--text-muted); font-variant-numeric:tabular-nums; white-space:nowrap }
/* Breakdown header: filter (left) + legend (right). */
.coverage-bd-head{ display:flex; align-items:center; justify-content:space-between; gap:var(--space-16); margin-bottom:var(--space-14); flex-wrap:wrap }
/* Legend — explains the two dots. */
.coverage-legend{ display:flex; gap:var(--space-16); font-size:var(--font-sm); color:var(--text-muted) }
.coverage-legend .lg{ display:inline-flex; align-items:center; gap:var(--space-6) }

/* Column manager rows */
.col-list{
  display:flex;
  flex-direction:column;
  gap:var(--space-2);
}

/* Sticky right Akce column — stays visible during horizontal scroll.
   Uses border-left as the basic divider. A drop-shadow is added on the left
   side only when the table-shell is scrolled horizontally (.is-scrolled-x),
   to signal that content is hidden behind the sticky column. */
.data-table th.col-actions,
.data-table td.col-actions{
  position:sticky;
  right:0;
  background:var(--surface);
  z-index:2;
  transition:box-shadow .14s ease, border-color .14s ease, background .14s ease;
}
.table-shell:not(.is-scrolled-x-end) .data-table th.col-actions,
.table-shell:not(.is-scrolled-x-end) .data-table td.col-actions{
  box-shadow:inset 1px 0 0 0 var(--divider), -8px 0 8px -6px rgba(15,23,42,.12);
}
/* Sticky buňka Akce se při hoveru podbarví jako zbytek řádku VŽDY, i když řádek
   nemá akční ikonu (prázdné .row-actions). Jinak by prázdná buňka svítila bíle =
   díra v podbarveném řádku (řádek je klikatelný, hover má být v syncu). */
.data-table tr:hover td.col-actions{ background:var(--surface-hover) }
/* Uzamčený řádek (např. inventarizované místo — žádná akce) → bez hover na buňce
   Akce; není co spustit a řádek sám hover nemá (data-attrs tabulka). */
.data-table tr.row-locked:hover td.col-actions{ background:transparent }
.data-table tr.selected td.col-actions{ background:var(--surface-active) }
.data-table tr.row-active td.col-actions{ background:var(--surface-active) }
.data-table tr.kbd-focus td.col-actions{ background:var(--surface-active) }

/* Sticky left checkbox column — mirror of col-actions, kept visible during
   horizontal scroll. Shadow appears on the right side once the shell has
   been scrolled, to signal content hidden underneath. */
.data-table th.col-check,
.data-table td.col-check{
  position:sticky;
  left:0;
  background:var(--surface);
  z-index:2;
  transition:box-shadow .14s ease, border-color .14s ease, background .14s ease;
}
.table-shell.is-scrolled-x .data-table th.col-check,
.table-shell.is-scrolled-x .data-table td.col-check{
  box-shadow:inset -1px 0 0 0 var(--divider), 8px 0 8px -6px rgba(15,23,42,.12);
}
.data-table tr:hover td.col-check{ background:var(--surface-hover) }
.data-table tr.selected td.col-check{ background:var(--surface-active) }
.data-table tr.kbd-focus td.col-check{ background:var(--surface-active) }
/* Active-detail row: tint the sticky checkbox cell too, and carry the left brand
   bar here (the row's inset shadow is hidden behind this sticky cell's bg). */
.data-table tr.row-active td.col-check{
  background:var(--surface-active);
  box-shadow:inset 3px 0 0 var(--brand);
}

/* Sticky thead corners (top-left col-check, top-right col-actions) sit at
   the intersection of two sticky axes — give them a higher z-index than
   either single-axis sticky so they don't get covered by either. */
.data-table thead th.col-check,
.data-table thead th.col-actions{
  background:var(--surface-alt);
  z-index:4;
}

/* Sort indicator in table header */
.data-table thead th.sortable{
  cursor:pointer;
  user-select:none;
}
.data-table thead th.sortable:hover{ color:var(--brand-dark) }
.data-table thead th.sortable .sort-icon{
  display:inline-block;
  margin-left:var(--space-4);
  opacity:.35;
  vertical-align:-2px;
  transition:.14s ease;
}
.data-table thead th.sortable.sort-asc .sort-icon,
.data-table thead th.sortable.sort-desc .sort-icon{
  opacity:1;
  color:var(--brand);
}
.data-table thead th.sortable.sort-desc .sort-icon{ transform:rotate(180deg) }


/* Sdílený drag úchyt (6-tečková mřížka) — jediný zdroj pravdy pro všechna
   přetahovatelná místa (Atributy tříd šarží, Správce sloupců, Kroky dopravy).
   SVG jako maska, takže dědí barvu z `color`. Použití: <span class="drag-grip">. */
.drag-grip{
  display:inline-flex; width:14px; height:14px; flex-shrink:0;
  cursor:grab; color:var(--text-faint);
  background-color:currentColor;
  -webkit-mask:var(--drag-grip-svg) center / 14px 14px no-repeat;
          mask:var(--drag-grip-svg) center / 14px 14px no-repeat;
}
.drag-grip:active{ cursor:grabbing; }

/* Column manager row: grip · name · eye-toggle */
.col-row{
  display:flex;
  align-items:center;
  gap:var(--space-10);
  padding:var(--space-8) var(--space-10);
  border-radius:var(--radius-sm);
  background:var(--surface);
}
.col-row:hover{ background:var(--surface-hover) }
.col-row.dragging{ opacity:.5 }
/* Indikátor cíle = rovná linka (ne inset shadow, který by kopíroval oblé rohy
   řádku). Pseudoelement ignoruje border-radius rodiče → rovné konce. */
.col-row{ position:relative }
.col-row.drag-over::before{
  content:""; position:absolute; left:0; right:0; top:-1px; height:2px;
  background:var(--brand);
}
.col-row:hover .drag-grip{ color:var(--text-muted); }
.col-row .name{
  flex:1;
  font-size:var(--font-md);
  color:var(--text);
}
.col-row .eye-toggle{
  width:28px;
  height:28px;
  border-radius:var(--radius-sm);
  display:grid;
  place-items:center;
  color:var(--text-muted);
  background:transparent;
}
.col-row .eye-toggle:hover{ background:var(--surface-hover); color:var(--text) }
.col-row.hidden{ opacity:.5 }
.col-row.hidden .eye-toggle{ color:var(--text-faint) }
.col-row.hidden .name{ text-decoration:line-through; color:var(--text-muted) }

/* -------------------------------------------------------------------------
   Transport-type STEPS — two side-by-side panels (assigned sequence | all
   available steps). Rows drag from "all" into "assigned" and reorder there.
   Type icon: start (green) / mid (brand) / end (dark). Used on edit-type.html.
   ------------------------------------------------------------------------- */
.step-panels{
  display:grid; grid-template-columns:1fr 1fr; gap:var(--space-20);
  align-items:start;
}
.step-panel{
  border:1px solid var(--border); border-radius:var(--radius); background:var(--surface);
  overflow:hidden;
}
.step-panel-head{
  display:flex; align-items:center; gap:var(--space-8);
  padding:var(--space-12) var(--space-16); border-bottom:1px solid var(--divider);
}
.step-panel-head h3{ font-size:var(--font-lg); font-weight:600; color:var(--text); }
.step-count{
  font-size:var(--font-xs); font-weight:600; color:var(--text-muted);
  background:var(--surface-muted); border-radius:var(--radius-pill); padding:1px var(--space-8);
}
/* Row grid: handle · name · code · status — shared by head + rows. Padding /
   gap / weight match the .role-item list convention for consistency. */
.step-row-head, .step-row{
  display:grid; grid-template-columns:16px 1.4fr 1fr 1.2fr; align-items:center;
  gap:var(--space-8); padding:var(--space-10) var(--space-16);
}
.step-row-head{
  font-size:var(--font-xs); font-weight:600; letter-spacing:.03em; text-transform:uppercase;
  color:var(--text-faint); border-bottom:1px solid var(--divider);
}
.step-list{ min-height:120px; max-height:440px; overflow-y:auto; }
.step-row{ border-bottom:1px solid var(--divider); cursor:grab; font-size:var(--font-sm); transition:.12s ease; }
.step-row:last-child{ border-bottom:0; }
.step-row:hover{ background:var(--surface-hover); }
.step-row.dragging{ opacity:.5; }
.step-row.drag-over{ box-shadow:inset 0 2px 0 0 var(--brand); }       /* vloží PŘED */
.step-row.drag-over-below{ box-shadow:inset 0 -2px 0 0 var(--brand); } /* vloží ZA */
.step-row:hover .drag-grip{ color:var(--text-muted); }
.step-row .s-name{ display:flex; align-items:center; gap:var(--space-10); color:var(--text); font-weight:400; font-size:var(--font-sm); }
.step-row .s-code{ color:var(--text-muted); font-family:ui-monospace,Menlo,monospace; font-size:var(--font-sm); }
.step-row .s-status{ color:var(--text-muted); font-size:var(--font-sm); }
/* Step-type icon — same disc as the standalone avatar (.avatar-md: 30px circle,
   centred white glyph), just with the step's SEMANTIC colour instead of an
   avatar-palette hue. Inline SVG centred via its viewBox. */
.step-ic{
  width:30px; height:30px; border-radius:50%; flex-shrink:0;
  display:grid; place-items:center;
  color:var(--on-accent);
}
.step-ic svg{ width:16px; height:16px; display:block; }
.step-ic-start{ background:var(--success); }      /* počáteční — zelená */
.step-ic-mid{ background:var(--text-muted); }     /* běžný — neutrální šedá */
.step-ic-end{ background:var(--danger); }         /* poslední — červená (stopka) */
.step-empty{
  padding:var(--space-20) var(--space-14); text-align:center;
  color:var(--text-muted); font-size:var(--font-sm);
}
.step-legend{ display:flex; gap:var(--space-16); margin-top:var(--space-16); flex-wrap:wrap; }
.step-leg{ display:inline-flex; align-items:center; gap:var(--space-6); font-size:var(--font-xs); color:var(--text-muted); }
/* Legend swatches are smaller than the in-row icons (they're just a key). */
.step-leg .step-ic{ width:18px; height:18px; }
.step-leg .step-ic svg{ width:12px; height:12px; }
@media (max-width:900px){ .step-panels{ grid-template-columns:1fr; } }

/* ===========================================================================
   Vizualizace linky (Řízení linky → Schema) — ORIENTOVANÝ GRAF toku. Uzly
   (stroje/snímače) v automatických sloupcích (dle nejdelší cesty), spojené
   SVG hranami. Uzel může mít víc vstupů i výstupů → rozdělení a slévání větví.
   Editace: přidat/odebrat uzel, spoj přes „napojit na", odebrat klikem na hranu.
   =========================================================================== */
.line-schema-bar{ display:flex; align-items:center; gap:var(--space-16); flex-wrap:wrap; margin-bottom:var(--space-16); }
.line-schema-hint{ margin:0; font-size:var(--font-sm); color:var(--text-muted); }

/* Plátno grafu: sloupce vedle sebe, mezi nimi SVG vrstva se spoji. Na úzku
   scrolluje vodorovně (uzly se nemačkají). */
.line-graph{ position:relative; display:flex; align-items:flex-start; gap:56px; overflow-x:auto;
  border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--surface);
  padding:var(--space-24) var(--space-24); min-height:160px; }
/* V editaci větší pravý odstup, ať výstupní port posledního uzlu není u kraje. */
.line-graph.is-editable{ padding-right:calc(var(--space-24) + var(--space-12)); }
.line-graph.is-empty{ display:block; }

/* SVG vrstva hran — pod uzly, přes celé plátno. */
.line-edges{ position:absolute; inset:0; width:100%; height:100%; pointer-events:none; overflow:visible; z-index:0; }
.line-edge{ fill:none; stroke:var(--border-strong); stroke-width:2; }
/* Šipka dědí barvu čáry, ke které patří (context-stroke) → špička sedí k barvě
   hrany (šedá/amber split/teal join), ne natvrdo šedá. Fallback pro staré
   prohlížeče = --border-strong (šedá). */
.line-edges marker path{ fill:var(--border-strong); fill:context-stroke; }
/* Hrany u míst, kde se tok dělí (split = amber) nebo slévá (join = brand).
   Když je hrana obojí, join (cíl) vyhrává — čtenáře zajímá, kam se sbíhá. */
.line-edge.is-split{ stroke:var(--warning); }
.line-edge.is-join{ stroke:var(--line-join); }
/* Editace: skupina hrany = široká neviditelná HIT ZÓNA (snadné trefení myší) +
   viditelná tenká čára + křížek uprostřed. Hover na kteroukoli část zvýrazní celou. */
.line-edge-g{ cursor:pointer; }
.line-edge-hit{ fill:none; stroke:transparent; stroke-width:18; pointer-events:stroke; }
.line-edge-cut{ pointer-events:none; opacity:0; transition:opacity .12s ease; }
.line-edge-cut circle{ fill:var(--danger); }
.line-edge-cut path{ stroke:var(--on-accent); stroke-width:2; stroke-linecap:round; }
.line-edge-g:hover .line-edge{ stroke:var(--danger); stroke-width:3; }
.line-edge-g:hover .line-edge-cut{ opacity:1; }

/* Sloupec = uzly na stejné topologické úrovni (pod sebou). */
.line-col{ position:relative; z-index:1; display:flex; flex-direction:column; gap:var(--space-16); justify-content:center; }

/* Uzel = karta stroje/snímače. */
.line-node{ position:relative; display:flex; align-items:center; gap:var(--space-8); width:220px;
  border:1px solid var(--border); border-radius:var(--radius-sm); background:var(--surface); padding:var(--space-10) var(--space-12); }
/* V editaci širší, ať se text vejde vedle úchytu + nástrojů (jinak se ořezával). */
.line-node.is-editable{ width:272px; }
.line-node-led{ flex:none; width:10px; height:10px; border-radius:50%; }
.line-node-led.is-online{ background:var(--success); box-shadow:0 0 0 3px var(--success-soft); }
.line-node-led.is-offline{ background:var(--danger); box-shadow:0 0 0 3px var(--danger-soft); }

.line-node-body{ display:flex; flex-direction:column; gap:2px; min-width:0; flex:1; }
.line-node-name{ font-size:var(--font-sm); font-weight:600; color:var(--text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.line-node-meta{ display:flex; align-items:center; gap:var(--space-8); font-size:var(--font-xs); }
.line-node-code{ color:var(--text-muted); font-family:ui-monospace,Menlo,monospace; }
.line-node-counts{ color:var(--text-faint); white-space:nowrap; }

/* Odlišení míst, kde se tok dělí (split) / slévá (join). Levý barevný proužek +
   štítek s počtem větví. Split = amber (rozvětvení), Join = brand (sbíhání). */
/* Proužek na straně DLE SMĚRU TOKU: split (tok se dělí a vytéká VPRAVO) = amber
   proužek vpravo; join (tok se slévá a přitéká ZLEVA) = teal proužek vlevo.
   Uzel co je obojí má teal vlevo (příchod) + amber vpravo (odchod). */
.line-node.is-split{ border-right:3px solid var(--warning); }
.line-node.is-join{ border-left:3px solid var(--line-join); }
.line-node.is-split.is-join{ border-left:3px solid var(--line-join); border-right:3px solid var(--warning); }

/* Nástroje uzlu v editaci: napojit na (řetěz) + odebrat (koš). */
.line-node-tools{ flex:none; display:inline-flex; align-items:center; gap:2px; }
.line-node-link, .line-node-del{ display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; padding:0;
  border:0; background:transparent; color:var(--text-faint); border-radius:var(--radius-sm); cursor:pointer; }
.line-node-link svg, .line-node-del svg{ width:14px; height:14px; }
.line-node-link:hover{ background:var(--surface-hover); color:var(--brand); }
.line-node-del:hover{ background:var(--danger-soft); color:var(--danger); }

/* Úchyt pro přeskládání uzlu ve sloupci (vlevo). */
.line-node-grip{ flex:none; cursor:grab; }
.line-node:hover .line-node-grip{ color:var(--text-muted); }
.line-node.dragging{ opacity:.45; }
/* Indikátor cíle při přeskládání ve sloupci (linka nad/pod uzlem). */
.line-node.drag-over{ box-shadow:inset 0 3px 0 0 var(--brand); }
.line-node.drag-over-below{ box-shadow:inset 0 -3px 0 0 var(--brand); }

/* Výstupní port (vpravo) — tažením z něj vzniká spoj. */
.line-node-port{ position:absolute; right:-7px; top:50%; transform:translateY(-50%);
  width:14px; height:14px; border-radius:50%; background-color:var(--surface); border:2px solid var(--border-strong);
  cursor:crosshair; z-index:2; transition:border-color .12s ease, background-color .12s ease; }
.line-node-port:hover{ border-color:var(--brand); background-color:var(--brand); box-shadow:0 0 0 3px var(--brand-ring); }
/* Během kreslení spoje: ztlum ostatní, zvýrazni platné cíle, zašeď neplatné. */
.line-graph.is-linking .line-node-port{ opacity:0; }             /* schovej porty, ať nepřekáží dropu */
.line-node.is-link-target{ border-color:var(--brand); box-shadow:0 0 0 2px var(--brand-ring); }
.line-node.is-link-invalid{ opacity:.4; }

/* Přidat uzel = samostatná lišta POD grafem (na novém řádku), oddělená od plátna
   toku. Tlačítko s textem, ať je jasné, že jde o samostatnou akci (ne přidání do řady). */
.line-add-bar{ margin-top:var(--space-12); }

/* Prázdné schéma. */
.line-empty{ display:flex; flex-direction:column; align-items:center; text-align:center; gap:var(--space-8); padding:var(--space-24) var(--space-16); }
.line-empty-icon{ color:var(--text-faint); }
.line-empty-icon svg{ width:40px; height:40px; }
.line-empty h3{ margin:0; font-size:var(--font-md); color:var(--text); }
.line-empty p{ margin:0; font-size:var(--font-sm); color:var(--text-muted); }
.line-empty .btn{ margin-top:var(--space-4); }

/* Nabídka strojů/cílů (popover u tlačítka + nebo řetězu). */
.line-menu{ position:absolute; z-index:60; min-width:240px; max-height:300px; overflow-y:auto;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-sm); box-shadow:var(--shadow-menu); padding:var(--space-4); }
.line-menu-item{ display:flex; align-items:center; justify-content:space-between; gap:var(--space-12); width:100%;
  border:0; background:transparent; text-align:left; padding:var(--space-8) var(--space-10); border-radius:var(--radius-sm); cursor:pointer; }
.line-menu-item:hover{ background:var(--surface-hover); }
.line-menu-name{ font-size:var(--font-sm); color:var(--text); }
.line-menu-code{ font-size:var(--font-xs); color:var(--text-muted); font-family:ui-monospace,Menlo,monospace; }
.line-menu-empty{ font-size:var(--font-sm); color:var(--text-muted); padding:var(--space-10) var(--space-12); }
/* In the narrow right-panel drawer the two panels stack vertically. Lists are
   taller here (more rows visible) since vertical space is the only constraint. */
.detail .step-panels{ grid-template-columns:1fr; gap:var(--space-16); }
.detail .step-list{ max-height:340px; }

/* Header filter icon (next to sort indicator) — 16×16 SVG + 4px padding =
   24×24 hit area, meeting WCAG 2.5.5 target size guidance. */
.data-table thead th .filter-icon{
  margin-left:var(--space-6);
  padding:var(--space-4);
  opacity:.5;
  cursor:pointer;
  border-radius:var(--radius-xs);
  transition:.14s ease;
  vertical-align:middle;
}
.data-table thead th .filter-icon:hover{
  opacity:1;
  background:var(--surface-hover);
}
.data-table thead th.filter-active .filter-icon{
  opacity:1;
  color:var(--brand);
}

/* Per-column filter popover — appended to <body>, positioned via JS, so it
   escapes the table-shell overflow clipping. */
.col-filter-pop{
  position:fixed;
  min-width:240px;
  max-width:320px;
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  box-shadow:var(--shadow-pop);
  padding:0;
  display:none;
  z-index:90;
  font-weight:400;
  color:var(--text);
  letter-spacing:normal;
  text-transform:none;
}
.col-filter-pop.open{ display:block }
/* Column-filter popover search: the .search .search--sm base supplies the
   overlaid icon + compact input; only the popover's padded, divided header
   row lives here. */
.col-filter-pop .pop-search{
  padding:var(--space-8) var(--space-10);
  border-bottom:1px solid var(--divider);
}
.col-filter-pop .pop-text-input{
  padding:var(--space-10);
  border-bottom:1px solid var(--divider);
}
.col-filter-pop .pop-text-input input{
  width:100%;
  padding:var(--space-6) var(--space-8);
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface);
  color:var(--text);
  font-size:var(--font-sm);
}
.col-filter-pop .pop-text-input input:focus-visible{
  outline:none;
  border-color:var(--brand);
  box-shadow:0 0 0 3px var(--brand-ring);
}
/* Date-range filtr: dvě pole Od / Do (naše .with-date komponenta) pod sebou. */
.col-filter-pop .pop-daterange{
  padding:var(--space-10);
  border-bottom:1px solid var(--divider);
  display:flex; flex-direction:column; gap:var(--space-8);
}
.col-filter-pop .pop-dr-field{ gap:var(--space-4); }
.col-filter-pop .pop-dr-cap{ font-size:var(--font-xs); color:var(--text-muted); }
.col-filter-pop .pop-options{
  max-height:240px;
  overflow-y:auto;
  padding:var(--space-4);
}
.col-filter-pop .pop-option{
  display:flex;
  align-items:center;
  gap:var(--space-8);
  padding:var(--space-6) var(--space-8);
  border-radius:var(--radius-sm);
  font-size:var(--font-md);
  cursor:pointer;
}
.col-filter-pop .pop-option:hover{ background:var(--surface-hover) }
.col-filter-pop .pop-option .label{ flex:1 }
.col-filter-pop .pop-option .num{
  color:var(--text-faint);
  font-size:var(--font-sm);
  font-variant-numeric:tabular-nums;
}
.col-filter-pop .pop-foot{
  display:flex;
  justify-content:space-between;
  padding:var(--space-8) var(--space-10);
  border-top:1px solid var(--divider);
  gap:var(--space-8);
}
.col-filter-pop .pop-foot .btn-link{
  background:transparent;
  color:var(--text-muted);
  font-size:var(--font-sm);
  font-weight:500;
}
.col-filter-pop .pop-foot .btn-link:hover{ color:var(--brand-dark) }
.col-filter-pop .pop-foot .btn-primary{
  padding:var(--space-4) var(--space-12);
  font-size:var(--font-sm);
}

/* Filter chip in toolbar (dynamic, replaces static quick-filter chips) */
.filter-chips-active{
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  gap:var(--space-6);
}
.filter-chips-active:empty{ display:none }
.filter-chip{
  display:inline-flex;
  align-items:center;
  gap:var(--space-6);
  padding:var(--space-4) var(--space-6) var(--space-4) var(--space-10);
  border-radius:var(--radius-pill);
  background:var(--brand-soft);
  border:1px solid var(--brand);
  color:var(--brand-dark);
  font-size:var(--font-sm);
  font-weight:500;
  position:relative;
}
.filter-chip:hover{ background:var(--surface-active) }
/* Two nested buttons (label = open the filter, ✕ = remove it) so both are
   keyboard-focusable on their own. They inherit the chip's look via a reset. */
.filter-chip .chip-label,
.filter-chip .chip-x{
  font:inherit;
  color:var(--brand-dark);
  background:transparent;
  border:0;
  padding:0;
  margin:0;
  cursor:pointer;
}
.filter-chip .chip-label{ user-select:none }
.filter-chip .chip-x{
  display:grid;
  place-items:center;
  width:18px;
  height:18px;
  border-radius:50%;
  flex-shrink:0;
}
.filter-chip .chip-x:hover{ background:var(--brand); color:var(--on-accent) }
.filter-chip .chip-label:focus-visible,
.filter-chip .chip-x:focus-visible{
  outline:none;
  box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--brand-ring-strong);
  border-radius:var(--radius-pill);
}

/* „Vyčistit vše" — neutrální link-tlačítko za čipy (jen při ≥2 filtrech). */
.filter-clear-all{
  border:0;
  background:transparent;
  color:var(--text-muted);
  font-size:var(--font-sm);
  font-weight:600;
  padding:var(--space-4) var(--space-8);
  border-radius:var(--radius-sm);
  cursor:pointer;
  text-decoration:underline;
  text-underline-offset:2px;
}
.filter-clear-all:hover{ color:var(--danger-fg); text-decoration:none }
.filter-clear-all:focus-visible{
  outline:none;
  box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--brand-ring-strong);
}

/* Počet výsledků při aktivním filtru („18 z 24") — jemný kontext u chip baru. */
.filter-count{
  font-size:var(--font-sm);
  font-weight:600;
  color:var(--text-muted);
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
  padding-left:var(--space-4);
}
.filter-count[hidden]{ display:none }

/* Row hidden by active filter — JS toggles this class. */
.data-table tbody tr.row-hidden{ display:none }
/* Row hidden because it falls outside the current page (still matches filters). */
.data-table tbody tr.row-paged{ display:none }

/* ===== Detail-page tables (detail-table.js) ==========================
   Reuses the full list-page .toolbar (search + chips + spacer + button
   group) above each .data-table[data-detail-table] (e.g. Inventura detail).
   Only tweak: spacing below it, since the detail page has no page-toolbar
   wrapper of its own. Right-hand actions are a read-only subset (refresh +
   Export / Zrušit filtry). */
.detail-table-toolbar{ margin-bottom:var(--space-12); }
/* Empty-filtered hint row injected into tbody when nothing matches. */
.data-table tbody tr.detail-table-empty td{
  text-align:center;
  color:var(--text-muted);
  font-size:var(--font-sm);
  padding:var(--space-24) var(--space-12);
}

/* Empty-state when filtering yields no results */
.table-empty-filtered{
  padding:48px var(--space-24);
  text-align:center;
  color:var(--text-muted);
}
.table-empty-filtered .icon{
  width:48px; height:48px;
  margin:0 auto var(--space-14);
  border-radius:50%;
  background:var(--surface-alt);
  display:grid;
  place-items:center;
  color:var(--text-faint);
}
.table-empty-filtered h3{
  font-size:var(--font-md);
  color:var(--text);
  margin-bottom:var(--space-6);
}
.table-empty-filtered p{ font-size:var(--font-sm) }
.table-empty-filtered .actions{ margin-top:var(--space-14) }

/* Generic utility: hide element regardless of its display mode. */
.is-hidden{ display:none !important }

/* Emoji icon cell in tables (e.g. transport types). */
.data-table td.type-icon{ font-size:var(--space-18) }

/* Hint paragraph used at the top of drawer/dialog panes. */
.pane-hint{
  font-size:var(--font-sm);
  color:var(--text-muted);
  margin-bottom:var(--space-10);
}
.data-table th.col-hidden,
.data-table td.col-hidden{ display:none !important }

/* Toolbar icon-only button with optional dot badge */
.btn-icon-tool{
  width:32px;
  height:32px;
  border-radius:var(--radius-sm);
  display:grid;
  place-items:center;
  color:var(--text-muted);
  background:var(--surface);
  border:1px solid var(--border);
  cursor:pointer;
  position:relative;
}
/* Constrain the glyph so the button doesn't depend on inline width/height on
   the SVG (a 24-viewBox SVG with no size would otherwise fill the 32px box). */
.btn-icon-tool svg{ width:16px; height:16px }
.btn-icon-tool:hover{
  background:var(--surface-hover);
  border-color:var(--border-strong);
  color:var(--text);
  z-index:1;
}
.btn-icon-tool:focus-visible{
  outline:none;
  border-color:var(--brand);
  box-shadow:0 0 0 3px var(--brand-ring-strong);
  z-index:1;
}

/* Button group: visually merges adjacent icon buttons into one unit.
   Used for table-level actions (Sloupce / Refresh / ⋮). */
.btn-group{
  display:inline-flex;
}
.btn-group > .btn-icon-tool,
.btn-group > .dropdown > .btn-icon-tool{
  border-radius:0;
  margin-left:-1px;
}
.btn-group > :first-child .btn-icon-tool,
.btn-group > .btn-icon-tool:first-child{
  border-top-left-radius:var(--radius-sm);
  border-bottom-left-radius:var(--radius-sm);
  margin-left:0;
}
.btn-group > :last-child .btn-icon-tool,
.btn-group > .btn-icon-tool:last-child{
  border-top-right-radius:var(--radius-sm);
  border-bottom-right-radius:var(--radius-sm);
}
.btn-icon-tool .dot{
  position:absolute;
  top:-3px;
  right:-3px;
  min-width:16px;
  height:16px;
  padding:0 var(--space-4);
  border-radius:var(--radius-pill);
  background:var(--brand);
  color:var(--on-accent);
  font-size:10px;
  font-weight:700;
  display:grid;
  place-items:center;
}
.btn-icon-tool .dot{ z-index:2 }              /* nad sousední tlačítka ve skupině (margin-left:-1px je překrývá) */
.btn-icon-tool .dot[hidden]{ display:none }   /* display:grid přebíjí UA [hidden] → vynutit */

/* ===== Uložené pohledy (saved views) — dropdown v toolbaru ===== */
.views-dropdown{ position:relative }
.views-dropdown[hidden]{ display:none }   /* position:relative přebíjí UA [hidden] → vynutit */
/* Trigger sladěný s ostatními tool tlačítky: výška 32px, font toolbaru. */
.views-trigger{
  display:inline-flex; align-items:center; gap:var(--space-6);
  height:32px; padding:0 var(--space-10);
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface);
  color:var(--text-muted);
  font-size:var(--font-md); font-weight:500;   /* stejný font jako search a menu */
  cursor:pointer; white-space:nowrap;
}
.views-trigger:hover{ background:var(--surface-hover); border-color:var(--border-strong); color:var(--text) }
.views-trigger:focus-visible{ outline:none; box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--brand-ring-strong) }
.views-trigger svg{ flex:none; color:var(--text-muted) }
.views-current{ max-width:180px; overflow:hidden; text-overflow:ellipsis }

/* Tlačítko Filtry = ikonová akce v btn-group (vzhled z .btn-icon-tool), odznak
   počtu přes sdílený .dot. Jen pozicování dropdownu je vlastní.
   POZOR: z-index NEDÁVAT na obal (.filters-dropdown) — vytvořil by stacking
   context, ve kterém by uvízlo rozbalené menu (z-index:30) POD sticky hlavičkou
   tabulky. Badge trčící nad sousedy řešíme z-indexem na samotném tlačítku. */
.filters-dropdown{ position:relative; display:inline-flex }
.filters-dropdown[hidden]{ display:none }
/* Tlačítko Filtry nad sousední tlačítka skupiny (margin-left:-1px je jinak
   překrývá a badge/roh je uříznutý) — jen tlačítko, ne obal s menu. */
.filters-trigger{ z-index:1 }
.filters-dropdown.open .filters-trigger{ z-index:auto }   /* při otevřeném menu nech stacking na menu */
/* Menu Filtry — seznam filtrovatelných polí. */
.filters-menu{ min-width:200px }
.filters-field{
  display:flex; align-items:center; justify-content:space-between; gap:var(--space-8);
  width:100%; padding:var(--space-8) var(--space-12); border:0; background:none;
  color:var(--text); font-size:var(--font-md); text-align:left; cursor:pointer;
}
.filters-field:hover{ background:var(--surface-hover) }
.filters-field-on{ font-size:var(--font-xs); font-weight:600; color:var(--brand-dark); background:var(--brand-soft); padding:1px var(--space-6); border-radius:var(--radius-pill) }
.filters-menu-foot{ border-top:1px solid var(--border); padding:var(--space-8) var(--space-12) }
.filters-menu-foot .btn{ width:100% }
/* Menu se otvírá vlevo (trigger je v levé části toolbaru). z-index nad tabulkou
   (sticky thead/sloupce mají vlastní stacking) — jinak popover mizí za obsahem. */
.views-menu{ right:auto; left:0; min-width:236px; max-width:300px; z-index:60 }
.views-dropdown.open .views-menu{ display:block }

/* Sladěno s .dropdown-menu button (kebab) — stejný font, gap, padding, radius. */
.view-item{
  display:flex; align-items:center; gap:var(--space-10);
  width:100%; text-align:left;
  padding:var(--space-8) var(--space-10);
  border:0; background:transparent; color:var(--text);
  border-radius:var(--radius-sm);
  font-size:var(--font-md); cursor:pointer;
}
.view-item:hover{ background:var(--surface-hover) }
.view-item.is-active{ font-weight:600 }
.view-item .view-check{ width:16px; flex:none; display:grid; place-items:center; color:var(--brand) }
.view-item .view-name{ flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.view-item .view-del{
  flex:none; width:24px; height:24px; display:grid; place-items:center;
  border-radius:var(--radius-xs); color:var(--text-faint); opacity:0;
}
.view-item:hover .view-del{ opacity:1 }
.view-item .view-del:hover{ background:var(--danger-soft); color:var(--danger-fg) }
.view-item.view-action{ color:var(--text-muted); font-weight:600 }
.view-item.view-action .view-check{ color:var(--text-muted); font-weight:700 }
.view-item.is-disabled{ opacity:.45; cursor:default }
.view-item.is-disabled:hover{ background:transparent }
.views-sep{ height:1px; background:var(--border); margin:var(--space-4) 0 }

/* Dropdown menu (used for the Reset split, future use as well) */
.dropdown{ position:relative; display:inline-block }
.dropdown-menu{
  position:absolute;
  top:calc(100% + 4px);
  right:0;
  min-width:200px;
  background:var(--dropdown-bg);
  border:1px solid var(--dropdown-border);
  border-radius:var(--radius-sm);
  box-shadow:var(--dropdown-shadow);
  padding:var(--space-4);
  display:none;
  z-index:30;
}
.dropdown.open .dropdown-menu{ display:block }
.dropdown-menu button{
  display:flex;
  align-items:center;
  gap:var(--space-10);
  width:100%;
  padding:var(--space-8) var(--space-10);
  border-radius:var(--radius-sm);
  font-size:var(--font-md);
  color:var(--text);
  text-align:left;
}
.dropdown-menu button:hover{ background:var(--surface-hover) }
.dropdown-menu button svg{ flex-shrink:0; color:var(--text-muted) }

/* Pagination collapsed variant: page-size stays visible (user may want to
   change it even on small datasets), only the page navigation is hidden. */
.pagination.count-only .nav{ display:none }


/* -------------------------------------------------------------------------
   Destructive confirm modal + toast with undo. Reused across destructive
   bulk actions (delete users, delete roles, ...). Variants by count:
     1 item        → simple confirm
     2–4 items     → confirm with list preview
     5+ items      → type-to-confirm ("SMAZAT")
   ------------------------------------------------------------------------- */

/* Modal variant for destructive confirms */
.modal-card.destructive .modal-head{ border-bottom:0; padding-bottom:0 }
.modal-card.destructive .modal-head h3{
  font-size:var(--font-lg);
  font-weight:700;
  color:var(--text);
}
.modal-card.destructive .destructive-icon{
  width:44px; height:44px;
  border-radius:50%;
  background:var(--danger-soft);
  color:var(--danger);
  display:grid;
  place-items:center;
  margin:var(--space-18) var(--space-20) var(--space-6);
}
.modal-card.destructive .modal-body{
  padding:var(--space-6) var(--space-20) 0;
  color:var(--text-muted);
  font-size:var(--font-md);
  line-height:1.5;
}
.modal-card.destructive .modal-body strong{ color:var(--text); font-weight:600 }
.modal-card.destructive .modal-body p{ margin:0 }
.modal-card.destructive .preview-list{
  margin:var(--space-12) 0 0;
  padding:var(--space-10) var(--space-12);
  background:var(--surface-alt);
  border-radius:var(--radius-sm);
  list-style:none;
  font-size:var(--font-sm);
  color:var(--text);
  display:flex;
  flex-direction:column;
  gap:var(--space-4);
  max-height:160px;
  overflow-y:auto;
}
.modal-card.destructive .preview-list li{
  display:flex;
  align-items:center;
  gap:var(--space-8);
}
.modal-card.destructive .preview-list .dot{
  width:6px; height:6px; border-radius:50%;
  background:var(--text-faint);
  flex-shrink:0;
}
.modal-card.destructive .confirm-typer{
  margin-top:var(--space-14);
}
.modal-card.destructive .confirm-typer label{
  display:block;
  font-size:var(--font-sm);
  color:var(--text-muted);
  margin-bottom:var(--space-6);
}
.modal-card.destructive .confirm-typer input{
  width:100%;
  padding:var(--space-8) var(--space-10);
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface);
  font-size:var(--font-md);
  color:var(--text);
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing:.05em;
}
.modal-card.destructive .confirm-typer input:focus{
  outline:none;
  border-color:var(--brand);
}
.modal-card.destructive .confirm-typer input:focus-visible{
  outline:none;
  border-color:var(--brand);
  box-shadow:0 0 0 3px var(--brand-ring);
}
/* Patička modalu — akce vpravo. Obecné (ne jen destructive confirm dialog), aby
   fungovala i u vlastních modalů (např. Přiřazení kódu). */
.modal-foot{
  display:flex;
  justify-content:flex-end;
  gap:var(--space-10);
  padding:var(--space-18) var(--space-20);
  margin-top:var(--space-14);
  border-top:1px solid var(--divider);
}

/* Toast container (bottom-right stacks) */
.toast-stack{
  position:fixed;
  bottom:24px;
  right:24px;
  display:flex;
  flex-direction:column-reverse;
  gap:var(--space-10);
  z-index:200;
  pointer-events:none;
  transition:bottom .2s ease;
}
/* Plovoucí spodní lišta (page-footer ve velkém detailu / drawer-foot v malém)
   sedí dole vpravo — zvedni toast nad ni, ať nepřekrývá Zrušit/Uložit.
   ~32px inset + ~58px výška lišty + 16px mezera ≈ 108px. */
body:has(.page-footer:not([hidden])) .toast-stack,
body:has(.bulk-bar:not(.is-hidden)) .toast-stack,
body.detail-open .toast-stack{
  bottom:108px;
}
.toast{
  background:var(--toast-bg);
  color:var(--toast-fg);
  border:1px solid var(--toast-border);
  border-radius:var(--radius-lg);   /* same floating-bar language as .bulk-bar */
  padding:var(--space-8) var(--space-8) var(--space-8) var(--space-16);   /* 2× left padding so the text sits in from the rounded edge */
  display:flex;
  align-items:center;
  gap:var(--space-8);
  min-width:300px;
  max-width:420px;
  box-shadow:var(--shadow-pop);
  pointer-events:auto;
  animation:toast-in .22s ease;
  position:relative;
  overflow:hidden;
}
@keyframes toast-in{
  from{ transform:translateY(8px); opacity:0 }
  to  { transform:none; opacity:1 }
}
.toast .msg{
  flex:1;
  font-size:var(--font-md);
  color:var(--toast-fg);
}
/* Odkaz v toastu (např. „Otevřít aktivaci") — zvýrazněný, podtržený. */
.toast-link{
  display:inline-block; margin-left:var(--space-6);
  color:var(--toast-fg); font-weight:700; text-decoration:underline; white-space:nowrap;
}
.toast-link:hover{ opacity:.85 }
.toast .undo{
  color:var(--toast-accent);
  font-weight:600;
  font-size:var(--font-md);
  background:transparent;
  padding:var(--space-4) var(--space-8);
  border-radius:var(--radius-sm);
}
.toast .undo:hover{ background:var(--toast-hover) }
.toast .close-x{
  width:24px; height:24px;
  border-radius:var(--radius-sm);
  display:grid;
  place-items:center;
  color:var(--toast-subtle);
  background:transparent;
}
.toast .close-x:hover{ color:var(--toast-fg); background:var(--toast-hover) }
/* Timer bar bottom */
.toast .timer{
  position:absolute;
  left:0; bottom:0;
  height:2px;
  background:var(--toast-accent);
  width:100%;
  animation:toast-timer 5s linear forwards;
}
@keyframes toast-timer{
  from{ width:100% }
  to  { width:0% }
}


/* -------------------------------------------------------------------------
   Skeleton row used while a table is fetching data. Apply by adding
   <tr class="skeleton-row"> with N <td>s containing <span class="skel"></span>.
   ------------------------------------------------------------------------- */
.skeleton-row{ pointer-events:none }
.skeleton-row td{ padding:var(--row-pad-td-y) var(--row-pad-x) }
.skel{
  display:block;
  height:12px;
  background:linear-gradient(90deg, var(--surface-alt) 0%, var(--surface-hover) 50%, var(--surface-alt) 100%);
  background-size:200% 100%;
  border-radius:var(--radius-xs);
  animation:skel-shimmer 1.2s infinite linear;
}
.skel.skel-sm{ width:60% }
.skel.skel-md{ width:80% }
.skel.skel-lg{ width:100% }
@keyframes skel-shimmer{
  from{ background-position:200% 0 }
  to  { background-position:-200% 0 }
}
/* Reduced motion: vypnout běžící shimmer, nechat jen statickou plochu (jemný
   puls opacity je akceptovatelný, ale i ten držíme pomalý a nenápadný). */
@media (prefers-reduced-motion: reduce){
  .skel{ animation:none; background:var(--surface-hover) }
}

/* -------------------------------------------------------------------------
   Accessibility: visually-hidden text for screen readers.
   ------------------------------------------------------------------------- */
.sr-only{
  position:absolute;
  width:1px; height:1px;
  padding:0;
  margin:-1px;
  overflow:hidden;
  clip:rect(0,0,0,0);
  white-space:nowrap;
  border:0;
}

/* -------------------------------------------------------------------------
   Data table — responsive adjustments below 1024 / 768 / 560 px.
   ------------------------------------------------------------------------- */
/* Tablet: tighten paddings, allow horizontal scroll. */
@media (max-width:1024px){
  /* Tablet tightens the comfortable rows via the density vars, so a user's
     compact choice (html[data-density="compact"]) still wins over this. */
  :root{
    --row-pad-th-y:var(--space-10);
    --row-pad-td-y:var(--space-10);
    --row-pad-x:var(--space-12);
  }
  .pagination{ padding:var(--space-10) var(--space-12) }
  .toolbar{ flex-wrap:wrap; gap:var(--space-8) }
  .toolbar .search{ min-width:0; flex:1 }
}
/* Smaller tablet / large phone: stack toolbar, smaller drawer. */
@media (max-width:768px){
  .drawer{ width:320px }
  .modal-card{ width:min(420px, calc(100% - 24px)) }
  .filter-chips-active{ width:100% }
}
/* Bulk bar reacts to ITS OWN width, not the window — the sidebar collapse and the
   detail panel both shrink the available space. Akce nikdy nesmí přetéct vpravo:
   1) když je málo místa, tlačítka se zúží na icon-only (16px SVG, font-size:0 skryje
      label) — breakpoint počítá s víc akcemi (až 4), proto 760px;
   2) pojistka: tlačítka se mohou zalomit na další řádek (flex-wrap) místo ořezu. */
.bulk-bar{ container-type:inline-size }
/* Práh počítá s nejhorším případem (4 akce + chip „× N vybráno"): plné labely
   se vejdou na jeden řádek jen nad ~820px šířky lišty; pod tím icon-only. Tím se
   akce NIKDY nezalomí ani nepřetečou (žádný flex-wrap = žádné osamocené tlačítko). */
@container (max-width:820px){
  .bulk-bar .btn{ font-size:0; padding:var(--space-8); gap:0 }
}
/* Phone: collapse the rightmost columns by default — user can re-enable
   via the Columns drawer if needed. */
@media (max-width:560px){
  .pagination .page-size label{ display:none }
  .data-table tbody tr{ font-size:var(--font-sm) }
}



/* -------------------------------------------------------------------------
   Design system — icon catalogue (design-icons.html)
   ------------------------------------------------------------------------- */
.col-icon-preview{ width:64px; text-align:center }
.icon-preview{
  display:inline-grid;
  place-items:center;
  width:40px; height:40px;
  border-radius:var(--radius-sm);
  background:var(--surface-alt);
  color:var(--text);
  border:1px solid var(--border);
}
.icon-preview svg{ width:22px; height:22px }
.data-table tbody tr:hover .icon-preview{
  border-color:var(--brand);
  color:var(--brand-dark);
}
.icon-key{
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size:var(--font-sm);
  background:var(--surface-alt);
  border:1px solid var(--border);
  border-radius:var(--radius-xs);
  padding:var(--space-2) var(--space-8);
  color:var(--text);
}
td[data-col="group"]{ color:var(--text-muted) }

/* -------------------------------------------------------------------------
   Design system — colour catalogue (design-colors.html)
   ------------------------------------------------------------------------- */
.col-color-swatch{ width:64px; text-align:center }
.color-swatch{
  display:inline-block;
  width:40px; height:40px;
  border-radius:var(--radius-sm);
  vertical-align:middle;
}
.color-hex{
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size:var(--font-sm);
  color:var(--text-muted);
  text-transform:uppercase;
}

/* -------------------------------------------------------------------------
   Design system — Typography & Shadows (visual cards)
   ------------------------------------------------------------------------- */
.ds-grid{
  display:grid;
  gap:var(--space-14);
  padding:var(--space-4) 0 var(--space-24);
}
.ds-card{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  padding:var(--space-20) 22px;
}
.ds-card .ds-meta{
  display:flex;
  align-items:center;
  gap:var(--space-10);
  flex-wrap:wrap;
  margin-top:var(--space-14);
  padding-top:var(--space-14);
  border-top:1px dashed var(--border);
}
.ds-card .ds-meta code{
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size:var(--font-sm);
  background:var(--surface-alt);
  border:1px solid var(--border);
  border-radius:var(--radius-xs);
  padding:var(--space-2) var(--space-8);
  color:var(--text);
}
.ds-card .ds-meta .ds-use{
  color:var(--text-muted);
  font-size:var(--font-sm);
  margin-left:auto;
}
.ds-card .ds-meta .ds-count{
  color:var(--text-faint);
  font-size:var(--font-xs);
}

/* Typography sample line */
.ds-type-sample{
  color:var(--text);
  line-height:1.25;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}

/* Weights row */
.ds-weights{ display:flex; flex-wrap:wrap; gap:var(--space-10) }
.ds-weight{
  flex:1 1 160px;
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  padding:var(--space-16) var(--space-18);
}
.ds-weight .big{ font-size:24px; color:var(--text); line-height:1 }

/* Shadow swatch cards: a floating tile so the shadow is visible */
.ds-shadows{ grid-template-columns:repeat(auto-fill, minmax(240px, 1fr)) }
.ds-shadow-tile{
  height:96px;
  background:var(--surface);
  border-radius:var(--radius);
  margin-bottom:var(--space-18);
  display:grid;
  place-items:center;
  color:var(--text-faint);
  font-size:var(--font-sm);
}
.ds-section-label{
  font-size:var(--font-xs);
  font-weight:700;
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--text-faint);
  /* Horní mezera odděluje od předchozí sekce; dolní drží label u JEHO obsahu. */
  margin:var(--space-24) 0 var(--space-6);
}
/* První section-label na stránce nemá odsazovat od úvodu tolik jako mezisekční. */
.section-intro + .ds-section-label,
.ds-section-label:first-child{ margin-top:var(--space-16); }

/* Spacing scale catalogue — one row per token, the bar width = the token value
   so the steps are directly comparable. */
.ds-space-scale{
  display:flex;
  flex-direction:column;
  gap:var(--space-2);
  border:1px solid var(--border);
  border-radius:var(--radius);
  padding:var(--space-8) var(--space-16);
  background:var(--surface);
}
.ds-space-row{
  display:flex;
  align-items:center;
  gap:var(--space-16);
  padding:var(--space-8) 0;
}
.ds-space-row + .ds-space-row{ border-top:1px solid var(--border) }
.ds-space-name{ width:120px; flex-shrink:0 }
.ds-space-name code{
  font-size:var(--font-sm);
  background:var(--surface-alt);
  border:1px solid var(--border);
  border-radius:var(--radius-xs);
  padding:2px 7px;
  color:var(--text);
}
.ds-space-bar{
  height:16px;
  background:var(--brand);
  border-radius:var(--radius-xs);
  flex-shrink:0;
}
.ds-space-val{ width:42px; flex-shrink:0; font-size:var(--font-sm); font-weight:600; color:var(--text) }
.ds-space-use{ color:var(--text-muted); font-size:var(--font-sm) }

/* -------------------------------------------------------------------------
   Design system — Elements catalogue (buttons, pills)
   ------------------------------------------------------------------------- */
/* Catalogue demo row — two layouts (design-system rule):
   • default = SMALL components: demo 50% | description 50% (side by side)
   • .stack  = WIDE components: demo 100% on top, description below */
.ds-el-row{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:var(--space-20);
  align-items:center;
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  padding:var(--space-18) 22px;
}
.ds-el-row + .ds-el-row{ margin-top:var(--space-12) }
.ds-el-row.stack{ grid-template-columns:1fr; align-items:stretch }
.ds-el-row.stack .ds-el-demo{ display:block }
/* Component with states — vertical layout: description (full row) → component
   (full row) → states (3 columns). Info is second in the DOM but ordered first. */
.ds-el-row.has-states{
  display:flex; flex-direction:column; align-items:stretch; gap:var(--space-14);
}
.ds-el-row.has-states .ds-el-info{ order:0; }
.ds-el-row.has-states .ds-el-demo{ order:1; display:block; }
.ds-el-row.has-states .ds-el-info .use{ margin-top:var(--space-2); }
.ds-el-demo{ display:flex; flex-wrap:wrap; gap:var(--space-10); align-items:center }
.ds-el-info .name{ font-size:var(--font-md); font-weight:600; color:var(--text) }
/* Malý uppercase popisek uvnitř demo ukázky (např. „Komfortní / Kompaktní"). */
.ds-demo-label{ font-size:var(--font-xs); font-weight:600; color:var(--text-muted); text-transform:uppercase; letter-spacing:.06em; margin:0 0 var(--space-8); }
/* Druhý a další popisek v ukázce (např. „Kompaktní" pod první tabulkou) dýchá shora. */
.ds-demo-label--gap{ margin-top:var(--space-20); }
.ds-el-info code{
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size:var(--font-sm);
  background:var(--surface-alt);
  border:1px solid var(--border);
  border-radius:var(--radius-xs);
  padding:1px var(--space-6);
  color:var(--text);
}
.ds-el-info .use{ color:var(--text-muted); font-size:var(--font-sm); margin-top:var(--space-4) }
/* Trailing class-name snippet (direct child) sits on its own line, set off from
   the .use text above it — otherwise the code chip glues to the description. */
.ds-el-info > code{ display:inline-block; margin-top:var(--space-8) }
/* State matrix: a component shown in default / disabled / read-only side by side.
   Each cell has a small caption above the live control. */
.ds-states{
  display:grid;
  grid-template-columns:repeat(2, minmax(0,1fr));   /* Disabled / Read-only — default state IS the live demo above */
  gap:var(--space-20);
  width:100%;
}
.ds-state-col{ display:flex; flex-direction:column; gap:var(--space-8); }
.ds-state-cap{
  font-size:var(--font-xs); font-weight:600; letter-spacing:.04em;
  text-transform:uppercase; color:var(--text-faint);
}
/* States shown directly under a component's main demo: a divider + the 3-state
   grid, so "component + its states" live together in one ds-el-row. */
.ds-el-demo .ds-states{ margin-top:var(--space-14); padding-top:var(--space-14); border-top:1px dashed var(--divider); }
@media (max-width:720px){
  .ds-el-row{ grid-template-columns:1fr; gap:var(--space-12) }
  .ds-states{ grid-template-columns:1fr; }
}

/* -------------------------------------------------------------------------
   Confirm dialog (confirm.js) — neutral variant just recolours the icon.
   Everything else reuses the existing .modal-card.destructive layout.
   ------------------------------------------------------------------------- */
.modal-card.destructive.is-neutral .destructive-icon{
  background:var(--brand-soft);
  color:var(--brand);
}

/* -------------------------------------------------------------------------
   Design system — primitive colour scales (design-colors.html "Škály")
   ------------------------------------------------------------------------- */
.ds-scales{ margin:var(--space-4) 0 22px }
.ds-scales h2{
  font-size:var(--font-sm); font-weight:700; letter-spacing:.04em;
  text-transform:uppercase; color:var(--text-faint); margin:0 0 var(--space-10);
}
.ds-scale-row{ display:flex; align-items:center; gap:var(--space-12); margin-bottom:var(--space-6) }
.ds-scale-name{ width:64px; font:600 var(--font-sm)/1 system-ui; color:var(--text); text-transform:capitalize }
.ds-scale-swatches{ display:flex; flex:1; gap:var(--space-4) }
.ds-scale-sw{
  flex:1; height:40px; border-radius:var(--radius-xs);
  display:flex; align-items:flex-end; justify-content:center;
  padding-bottom:var(--space-4); font:600 9px ui-monospace,monospace;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.04);
}

/* Tag barvy tab — 16 barev jako reálné .tag pilulky (OKLCH-vyrovnané, #27). */
.ds-tags{ margin:var(--space-4) 0 22px }
.ds-tags h2{
  font-size:var(--font-sm); font-weight:700; letter-spacing:.04em;
  text-transform:uppercase; color:var(--text-faint); margin:0 0 var(--space-10);
}
.ds-note{ font-size:var(--font-sm); color:var(--text-muted); line-height:1.55; max-width:70ch; margin:0 0 var(--space-16) }
.ds-tag-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:var(--space-10) }
.ds-tag-cell{ display:flex; align-items:center; gap:var(--space-8) }
.ds-tag-cell .tag{ text-transform:capitalize }
.ds-tag-cell .color-hex{ font-size:11px; color:var(--text-faint) }

/* =========================================================================
   AUTH / LOGIN — the only full-viewport, sidebar-less screen. Split layout:
   a coloured brand panel (left) + the form column (right). Reuses .form-field,
   .btn, .checkbox-row, the .reveal password toggle and all tokens; the .auth-*
   rules below are only the things the shell itself needs. Stacks to one column
   (form only, compact brand header) under 720px.
   ------------------------------------------------------------------------- */
.auth{
  min-height:100vh;
  color:var(--text);
}

/* Full-bleed brand gradient with a FLOATING form card on top — the card matches
   the app's other panels (surface + radius-lg + shadow-pop). The brand content
   sits to the left, centred in the leftover space; the card is fixed-width on the
   right. Collapses to one white column on phones (see the media query). */
.auth-shell{
  position:relative;
  overflow:hidden;                 /* clip the decorative rings — no page scroll */
  min-height:100vh;
  display:flex;
  align-items:center;
  justify-content:center;          /* brand + card form one centred group */
  gap:clamp(var(--space-24), 5vw, 80px);
  padding:clamp(var(--space-24), 6vw, 96px);
  background:linear-gradient(150deg, var(--brand) 0%, var(--brand-dark) 100%);
}
/* Decorative concentric rings on the gradient backdrop. */
.auth-shell::before,
.auth-shell::after{
  content:""; position:absolute; border-radius:50%;
  border:1px solid rgba(255,255,255,.10); pointer-events:none;
}
.auth-shell::before{ width:620px; height:620px; right:-160px; top:-200px; box-shadow:inset 0 0 0 70px rgba(255,255,255,.05); }
.auth-shell::after{ width:440px; height:440px; left:-160px; bottom:-160px; box-shadow:inset 0 0 0 50px rgba(255,255,255,.05); }

/* ---- Left: brand content (dynamic width), centred in its space ---- */
.auth-brand{
  position:relative; z-index:1;
  flex:0 1 460px; min-width:0;
  display:flex; flex-direction:column; align-items:flex-start;
  gap:44px;   /* generous breathing room between the logo and the claim */
  color:var(--on-accent);
  text-align:left;
}
.auth-brand .brand,
.auth-brand .pitch{ width:100%; max-width:380px }

.auth-brand .brand{
  display:inline-flex; align-items:center; gap:var(--space-12);
  text-decoration:none; color:inherit;
}
.auth-brand .logo{
  width:48px; height:48px; border-radius:var(--radius);
  display:grid; place-items:center; flex-shrink:0;
  background:rgba(255,255,255,.16);
  backdrop-filter:blur(2px);
  font-size:22px; font-weight:800; color:var(--on-accent);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.25);
}
.auth-brand .brand .name{ font-size:var(--font-xl); font-weight:800; letter-spacing:-.01em; display:block }
.auth-brand .brand .sub{ font-size:var(--font-sm); font-weight:600; color:rgba(255,255,255,.78) }

.auth-brand .pitch h1{
  font-size:var(--font-2xl); font-weight:800; line-height:1.2;
  letter-spacing:-.02em; margin:0 0 var(--space-12);
}
.auth-brand .pitch p{ font-size:var(--font-lg); color:rgba(255,255,255,.82); margin:0; line-height:1.5 }

/* Feature list — centred block, each row left-aligned to its tick so the list
   reads cleanly while the whole group stays centred under the claim. */
.auth-features{
  list-style:none; margin:var(--space-24) 0 0; padding:0;
  display:flex; flex-direction:column; gap:var(--space-12);
  text-align:left;
}
.auth-features li{ display:flex; align-items:center; gap:var(--space-12); font-size:var(--font-md); font-weight:500 }
.auth-features .tick{
  width:24px; height:24px; border-radius:50%; flex-shrink:0;
  display:grid; place-items:center;
  background:rgba(255,255,255,.16);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.22);
}
.auth-features .tick svg{ width:14px; height:14px }

/* Footer pinned to the gradient's bottom-left corner. */
.auth-shell .foot{
  position:absolute; z-index:1;
  left:clamp(var(--space-24), 6vw, 96px); bottom:var(--space-24);
  font-size:var(--font-sm); color:rgba(255,255,255,.66);
}

/* ---- Right: form — a floating card like the app's other panels ---- */
.auth-main{
  position:relative; z-index:1;
  flex:none; width:440px; max-width:100%;
  display:flex; align-items:center; justify-content:center;
  padding:clamp(var(--space-24), 3vw, 44px);
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-pop);
}
.auth-card{ width:100%; max-width:380px }
.auth-card h2{ font-size:var(--font-2xl); font-weight:800; letter-spacing:-.02em; margin:0 0 var(--space-6) }
.auth-card .lede{ font-size:var(--font-md); color:var(--text-muted); margin:0 0 var(--space-24) }
.auth-form{ display:flex; flex-direction:column; gap:var(--space-16) }
.auth-form[hidden]{ display:none }   /* display:flex přebíjí UA [hidden] → vynutit (kroky aktivace) */
/* Fields fill the card width (inputs otherwise carry a ~20ch intrinsic width). */
.auth-form .form-field input:not([type=checkbox]):not([type=radio]){ width:100%; min-width:0 }

/* Inline link row (e.g. "Heslo" label + "Zapomněli jste?" on the right) */
.auth-label-row{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--space-8) }
.auth-link{
  background:none; border:0; padding:0; cursor:pointer;
  font-size:var(--font-sm); font-weight:600; color:var(--brand);
}
.auth-link:hover{ color:var(--brand-dark); text-decoration:underline }
.auth-link:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--brand-ring); border-radius:var(--radius-xs) }

.auth-row{ display:flex; align-items:center; justify-content:space-between; gap:var(--space-12) }
.auth-submit{ width:100%; margin-top:var(--space-4) }

/* "nebo" divider between password login and SSO */
.auth-divider{ display:flex; align-items:center; gap:var(--space-12); color:var(--text-faint); font-size:var(--font-sm) }
.auth-divider::before,.auth-divider::after{ content:""; flex:1; height:1px; background:var(--border) }

.auth-foot{ margin-top:var(--space-24); font-size:var(--font-sm); color:var(--text-faint); text-align:center }

/* Summary alert (invalid credentials, reset sent, …) */
.auth-alert{
  display:flex; gap:var(--space-10); align-items:flex-start;
  padding:var(--space-10) var(--space-12);
  border-radius:var(--radius-sm); font-size:var(--font-sm); line-height:1.45;
  border:1px solid transparent;
}
.auth-alert svg{ width:16px; height:16px; flex-shrink:0; margin-top:1px }
.auth-alert.is-error{ background:var(--danger-soft); border-color:var(--danger); color:var(--btn-danger-fg) }
.auth-alert.is-success{ background:var(--success-soft); border-color:var(--success); color:var(--text) }
.auth-alert[hidden]{ display:none !important }

/* Inline field error — pairs with .form-field; red border + a small message. */
.form-field.has-error input:not([type=checkbox]):not([type=radio]){
  border-color:var(--danger);
}
.form-field.has-error input:focus{ box-shadow:0 0 0 3px var(--danger-ring) }
.field-error{ font-size:var(--font-sm); color:var(--btn-danger-fg); font-weight:500 }
.field-error[hidden]{ display:none !important }

/* ---- Aktivace účtu (activate.html) — širší karta pro víc polí ---- */
.auth-main--wide{ width:520px }
.auth-card--wide{ max-width:460px }
/* Dvousloupcové řádky polí (Jméno/Příjmení, Iniciály/Username, Město/PSČ). */
.auth-grid-2{ display:grid; grid-template-columns:1fr 1fr; gap:var(--space-16) }
/* Zámek u readonly e-mailu (z pozvánky). */
.form-field .input-lock{
  position:absolute; right:var(--space-10); top:50%; transform:translateY(-50%);
  display:grid; place-items:center; color:var(--text-faint); pointer-events:none;
}
.form-field .input-lock svg{ width:15px; height:15px }
.form-field.is-readonly .input-wrap{ position:relative }
.form-field.is-readonly input{ padding-right:34px; background:var(--surface-muted); color:var(--text-muted) }

/* Krokový indikátor (1 Účet · 2 Kontakt). */
.auth-steps{ list-style:none; display:flex; gap:var(--space-8); margin:0 0 var(--space-24); padding:0 }
.auth-step{
  flex:1; display:flex; align-items:center; gap:var(--space-8);
  font-size:var(--font-sm); font-weight:600; color:var(--text-faint);
  padding-bottom:var(--space-8); border-bottom:2px solid var(--border);
}
.auth-step-num{
  display:grid; place-items:center; width:22px; height:22px; flex:none;
  border-radius:50%; background:var(--surface-muted); color:var(--text-muted);
  font-size:var(--font-xs); font-weight:700;
}
.auth-step.is-active{ color:var(--text); border-bottom-color:var(--brand) }
.auth-step.is-active .auth-step-num{ background:var(--brand); color:var(--on-accent) }
.auth-step.is-done{ color:var(--text-muted); border-bottom-color:var(--brand) }
.auth-step.is-done .auth-step-num{ background:var(--brand-soft); color:var(--brand-dark) }

/* Poznámka „nepovinné" nad krokem 2. */
.auth-optional-note{ margin:0; font-size:var(--font-sm); color:var(--text-muted) }
.auth-step2-actions{ margin-top:var(--space-4) }

/* Ukazatel síly hesla. */
.pwd-strength{ display:flex; align-items:center; gap:var(--space-10); margin-top:var(--space-4) }
.pwd-strength[hidden]{ display:none }
.pwd-bar{ flex:1; height:6px; border-radius:var(--radius-pill); background:var(--surface-muted); overflow:hidden }
.pwd-bar span{ display:block; height:100%; width:0; border-radius:var(--radius-pill); transition:width .18s ease, background .18s ease }
.pwd-bar span.is-weak{ background:var(--danger) }
.pwd-bar span.is-medium{ background:var(--warning) }
.pwd-bar span.is-strong{ background:var(--success) }
.pwd-level{ font-size:var(--font-xs); font-weight:600; color:var(--text-muted); min-width:44px; text-align:right }

/* Živé požadavky na heslo (odškrtávají se). */
.pwd-reqs{ list-style:none; margin:var(--space-8) 0 0; padding:0; display:flex; flex-direction:column; gap:var(--space-4) }
.pwd-reqs li{ display:flex; align-items:center; gap:var(--space-8); font-size:var(--font-sm); color:var(--text-muted) }
.pwd-reqs .pwd-check{
  display:grid; place-items:center; width:16px; height:16px; flex:none;
  border-radius:50%; border:1.5px solid var(--border); color:transparent;
  transition:.15s ease;
}
.pwd-reqs li.is-ok{ color:var(--text) }
.pwd-reqs li.is-ok .pwd-check{ background:var(--success); border-color:var(--success); color:var(--on-accent) }
.pwd-reqs li.is-ok .pwd-check::after{ content:"✓"; font-size:10px; font-weight:700 }

/* Corner controls (theme toggle) — top-right of the form column. */
/* Small theme toggle in the gradient's bottom-right corner (opposite copyright). */
.auth-theme{
  position:absolute; z-index:2;
  right:clamp(var(--space-24), 6vw, 96px); bottom:var(--space-24);
  width:26px; height:26px; padding:0;
  display:grid; place-items:center;
  border-radius:var(--radius-sm); border:0; cursor:pointer;
  background:rgba(255,255,255,.14); color:rgba(255,255,255,.82);
  transition:.16s ease;
}
.auth-theme:hover{ background:rgba(255,255,255,.24); color:var(--on-accent) }
.auth-theme:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(255,255,255,.3) }
.auth-theme svg{ width:15px; height:15px }

/* State machine: show the panel matching the active mode, hide the others. */
.auth-pane[hidden]{ display:none !important }

/* Mobile brand mark — hidden on desktop (the gradient panel carries the brand);
   shown only on phones, on the white surface, above the form. */
.auth-logo-mobile{ display:none }

/* ---- Responsive: phones & narrow tablets — keep the brand gradient + floating
   white card (same language as desktop), but drop the claim panel entirely. Just
   the logo (centred, white, on the gradient) above the form card. ---- */
@media (max-width:900px){
  .auth-shell{
    /* stack the (hidden) brand + the logo + the card, centred on the gradient */
    flex-direction:column;
    justify-content:center;
    gap:var(--space-20);
    padding:clamp(var(--space-20), 5vw, 40px);
  }
  /* Claim panel + corner footer gone on mobile. */
  .auth-brand,.auth-shell .foot{ display:none }

  /* Brand logo above the card, centred, white-on-gradient. */
  .auth-logo-mobile{
    display:inline-flex; align-items:center; gap:var(--space-10);
    text-decoration:none; color:var(--on-accent);
    order:-1;                 /* above the card in the column */
  }
  .auth-logo-mobile .logo{
    width:40px; height:40px; border-radius:var(--radius); flex-shrink:0;
    display:grid; place-items:center;
    background:rgba(255,255,255,.16);
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.25);
    color:var(--on-accent); font-size:18px; font-weight:800;
  }
  .auth-logo-mobile .brand-text{ display:flex; flex-direction:column; line-height:1.2 }
  .auth-logo-mobile .brand-text .name{ font-size:var(--font-lg); font-weight:800; color:var(--on-accent); letter-spacing:-.01em }
  .auth-logo-mobile .brand-text .sub{ font-size:var(--font-sm); font-weight:500; color:rgba(255,255,255,.78) }

  /* The form stays a floating white card, now full-width up to a comfortable max. */
  .auth-main{
    width:100%; max-width:420px;
    padding:clamp(var(--space-24), 6vw, 36px);
  }
}

/* =========================================================================
   ERROR PAGES (404 / 403 / 500) — full-viewport, sidebar-less, same language
   as the login: brand gradient backdrop + a centred white card. Reuses .btn,
   tokens, and the auth brand mark. .error-* are only the bits the card needs.
   NOTE: wrapper is `.error-page` (not `.error`) — `error` alone collides with
   the dashboard's `.attention-row.error` status variant.
   ------------------------------------------------------------------------- */
.error-page{
  min-height:100vh;
  display:flex; align-items:center; justify-content:center;
  padding:clamp(var(--space-24), 5vw, 48px);
  position:relative; overflow:hidden;
  background:linear-gradient(150deg, var(--brand) 0%, var(--brand-dark) 100%);
  color:var(--text);
}
/* Decorative concentric rings on the gradient (same as the auth shell). */
.error-page::before,
.error-page::after{
  content:""; position:absolute; border-radius:50%;
  border:1px solid rgba(255,255,255,.10); pointer-events:none;
}
.error-page::before{ width:620px; height:620px; right:-160px; top:-200px; box-shadow:inset 0 0 0 70px rgba(255,255,255,.05); }
.error-page::after{ width:440px; height:440px; left:-160px; bottom:-160px; box-shadow:inset 0 0 0 50px rgba(255,255,255,.05); }

/* Brand mark — centred above the card, white on the gradient. */
.error-brand{
  position:absolute; top:clamp(var(--space-20), 4vw, 40px); left:0; right:0;
  display:flex; justify-content:center;
}
.error-brand a{
  display:inline-flex; align-items:center; gap:var(--space-10);
  text-decoration:none; color:var(--on-accent);
}
.error-brand .logo{
  width:36px; height:36px; border-radius:var(--radius); flex-shrink:0;
  display:grid; place-items:center;
  background:rgba(255,255,255,.16);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.25);
  color:var(--on-accent); font-size:16px; font-weight:800;
}
.error-brand .name{ font-size:var(--font-lg); font-weight:800; letter-spacing:-.01em; color:var(--on-accent) }
.error-brand .sub{ font-size:var(--font-sm); font-weight:500; color:rgba(255,255,255,.78) }
.error-brand .brand-text{ display:flex; flex-direction:column; line-height:1.2 }

/* The card. */
.error-card{
  position:relative; z-index:1;
  width:100%; max-width:480px;
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-pop);
  padding:clamp(var(--space-24), 4vw, 44px);
  text-align:center;
}
/* Themed icon badge above the code. Colour set per status (see modifiers). */
/* Themed SVG illustration above the code. Monochrome brand-stroke scene with a
   soft tinted fill behind it; the accent (stroke + glyph) shifts per status. */
.error-illustration{
  width:168px; height:120px; margin:0 auto var(--space-12);
  display:block; color:var(--brand);
}
.error-illustration svg{ width:100%; height:100%; display:block; overflow:visible }
/* Soft backdrop disc / tint elements in the scene. */
.error-illustration .ill-tint{ fill:var(--brand-soft) }
.error-illustration .ill-line{ stroke:var(--brand); fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round }
.error-illustration .ill-fill{ fill:var(--brand) }
.error-illustration .ill-faint{ stroke:var(--border-strong); fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round }
.error-page.is-403 .error-illustration{ color:var(--warning) }
.error-page.is-403 .error-illustration .ill-tint{ fill:var(--warning-soft) }
.error-page.is-403 .error-illustration .ill-line{ stroke:var(--warning) }
.error-page.is-403 .error-illustration .ill-fill{ fill:var(--warning) }
.error-page.is-500 .error-illustration{ color:var(--danger) }
.error-page.is-500 .error-illustration .ill-tint{ fill:var(--danger-soft) }
.error-page.is-500 .error-illustration .ill-line{ stroke:var(--danger) }
.error-page.is-500 .error-illustration .ill-fill{ fill:var(--danger) }

.error-code{
  font-size:68px; font-weight:800; line-height:1; letter-spacing:-.03em;
  color:var(--text); margin:0 0 var(--space-12);
  font-variant-numeric:tabular-nums;
}
.error-card h1{
  font-size:var(--font-xl); font-weight:700; letter-spacing:-.01em;
  color:var(--text); margin:0 0 var(--space-8);
}
.error-card p{
  font-size:var(--font-md); color:var(--text-muted); line-height:1.5;
  margin:0 auto var(--space-24); max-width:42ch;
}
/* Actions row (Domů + Zpět). */
.error-actions{
  display:flex; gap:var(--space-10); justify-content:center; flex-wrap:wrap;
}
/* Optional technical detail (500) — error id / support hint under the actions. */
.error-meta{
  margin-top:var(--space-24); padding-top:var(--space-16);
  border-top:1px solid var(--divider);
  font-size:var(--font-sm); color:var(--text-faint); line-height:1.5;
}
.error-meta code{
  font-family:ui-monospace,Menlo,monospace; font-size:var(--font-xs);
  color:var(--text-muted); background:var(--surface-alt);
  padding:1px var(--space-6); border-radius:var(--radius-xs);
}
.error-meta a{ color:var(--brand); font-weight:500; text-decoration:none }
.error-meta a:hover{ color:var(--brand-dark); text-decoration:underline }

@media (max-width:560px){
  .error-actions .btn{ width:100% }
  .error-code{ font-size:56px }
  .error-illustration{ width:148px; height:104px }
}

/* =========================================================================
   Icon gallery (design system › Ikony) — a tile grid, mirroring the colour
   catalogue's tile language: each icon is a square card (glyph + key below),
   grouped by category. Search filters tiles in place; empty groups hide.
   ------------------------------------------------------------------------- */
.ds-icon-group{ margin:0 0 var(--space-24) }
.ds-icon-group > h2{
  font-size:var(--font-sm); font-weight:700; letter-spacing:.04em;
  text-transform:uppercase; color:var(--text-faint);
  margin:0 0 var(--space-12);
}
.ds-icon-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(108px, 1fr));
  gap:var(--space-10);
}
.ds-icon-tile{
  display:flex; flex-direction:column; align-items:center; gap:var(--space-8);
  padding:var(--space-16) var(--space-10) var(--space-12);
  border:1px solid var(--border); border-radius:var(--radius);
  background:var(--surface); cursor:default;
  transition:.14s ease;
}
.ds-icon-tile:hover{ border-color:var(--brand); box-shadow:var(--shadow-sm) }
.ds-icon-tile svg{ width:24px; height:24px; color:var(--text); flex:none }
.ds-icon-tile .ds-icon-key{
  font-family:ui-monospace,Menlo,monospace; font-size:var(--font-xs);
  color:var(--text-muted); text-align:center; line-height:1.3;
  max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.ds-icon-tile[hidden]{ display:none }
/* Defined but never rendered — shown dimmed so the catalogue stays honest. */
.ds-icon-tile.ds-icon-unused{ opacity:.5 }
.ds-icon-tile.ds-icon-unused .ds-icon-key::after{ content:" · nepoužito"; color:var(--text-faint) }
.ds-icon-group[hidden]{ display:none }
.ds-icon-empty{ padding:var(--space-16); color:var(--text-muted); font-size:var(--font-sm) }
.ds-icon-empty[hidden]{ display:none }

/* ===================================================================
   MOBILNÍ LAYOUT (≤768px) — sidebar off-canvas
   -------------------------------------------------------------------
   Nad 768px platí desktopový grid (sidebar | main), sbalení na ikony.
   Na ≤768px sidebar VYPADNE z toku a stane se překryvem zleva, který
   ovládá hamburger v hlavičce stránky. Backdrop ztmaví obsah. Stav drží
   třída .mobile-nav-open na .shell (řídí launcher.js).
   =================================================================== */

/* Hamburger — jen na mobilu; injektuje se do .page-header (components.js). */
.page-hamburger{
  display:none;
  flex:none;
  width:40px; height:40px;
  align-items:center; justify-content:center;
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  background:var(--surface);
  color:var(--text);
  cursor:pointer;
}
.page-hamburger:hover{ background:var(--surface-muted) }

/* Backdrop pro mobilní sidebar (sourozenec .shell, přidán JS jednou). */
.mobile-nav-backdrop{
  position:fixed; inset:0;
  background:var(--backdrop);
  opacity:0; visibility:hidden;
  transition:opacity .22s var(--sb-ease), visibility .22s var(--sb-ease);
  z-index:190;
}

@media (max-width:768px){
  /* Shell = jeden sloupec; sidebar už nezabírá místo v toku. Přebíjíme i
     .sidebar-collapsed (desktopový sbalený stav 64px|1fr), aby na mobilu
     obsah dostal PLNOU šířku bez ohledu na uložené sbalení z localStorage. */
  .shell,
  .shell.sidebar-collapsed{
    grid-template-columns:1fr;
    grid-template-areas:"main";
    padding:var(--space-8);
    gap:0;
  }

  /* Sidebar = překryv zleva. Ve sbaleném i rozbaleném stavu má PLNOU šířku
     (mobilní menu není „ikonový pruh"), skrytý mimo obrazovku. */
  .shell .sidebar{
    position:fixed;
    top:0; left:0; bottom:0;
    width:min(84vw, 300px);
    margin:0; border-radius:0;
    transform:translateX(-100%);
    transition:transform .24s var(--sb-ease);
    z-index:200;
    box-shadow:var(--shadow-drawer);
  }
  .shell.mobile-nav-open .sidebar{ transform:translateX(0) }
  .shell.mobile-nav-open .mobile-nav-backdrop{ opacity:1; visibility:visible }

  /* Sbalení (ikonový pruh) je na mobilu vypnuté už v JS (launcher.js
     applySidebarState neaplikuje sidebar-collapsed pod 768px), takže sidebar
     je vždy rozbalený a nemusíme tu nic „přestavovat". Jen skryjeme tlačítko
     sbalit — na mobilu nedává smysl. */
  .sidebar > .sidebar-collapse-btn{ display:none }

  /* Hlavička na mobilu = JEDNOTNÝ app-bar vzor napříč všemi stránkami (seznam
     i detail stejně): řádek 1 = [hamburger .......... ikony akcí vpravo],
     řádek 2 = drobečky + nadpis přes celou šířku. Akce se zbalí na IKONY
     (skryjeme text), protože jich může být víc a text by přetékal. DOM pořadí
     je hamburger, textblok, page-actions → přeskládáme přes order + flex-basis. */
  .page-hamburger{ display:inline-flex; order:0; width:36px; height:36px }  /* stejně velký jako ikony akcí */
  .page-header{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:var(--space-8) var(--space-12);
    padding:var(--space-12);
  }
  .page-header .page-actions{
    order:1;                 /* řádek 1, hned za hamburgerem */
    flex:1;                  /* vyplní zbytek prvního řádku → ikony k pravému kraji */
    justify-content:flex-end;
    flex-wrap:nowrap;
    gap:var(--space-4);
  }
  .page-header > div:first-of-type{ order:2; flex-basis:100%; min-width:0 }  /* nadpis = celý řádek 2 */

  /* Akční tlačítka → jen ikony (skryjeme text). Přepínač panel/plocha (detail)
     na mobilu skryt - je stejně jen jedno zobrazení. */
  .page-actions .detail-mode{ display:none }
  .page-actions .btn{
    font-size:0;              /* skryje textový uzel tlačítka, ikona zůstává */
    gap:0; padding:0;
    width:36px; height:36px;
    justify-content:center;
    flex:none;
  }
  .page-actions .btn svg{ width:18px; height:18px }
  .page-actions .close{ width:36px; height:36px; flex:none }

  /* Formuláře i detailové 2sloupce → 1 sloupec (obsah má teď plnou šířku). */
  .form-grid,
  .detail-cols,
  .detail-layout,
  .edit-role-layout{ grid-template-columns:1fr }

  /* Plovoucí patičky a bulk bary se drží šířky obsahu (už ne odsazené o sidebar). */
  .page-header, .page-body{ max-width:100% }

  /* Boční okraje kolem obsahu jsou na mobilu zbytečně velké (desktop 28px na
     každé straně = 56px ukradených). Zúžit, ať seznamy/karty dostanou víc šířky. */
  .page-body{ padding-left:var(--space-12); padding-right:var(--space-12) }
  .page-header{ padding-left:var(--space-12); padding-right:var(--space-12) }

  /* Plovoucí lišty (page-footer, bulk-bar) počítaly left s šířkou sidebaru;
     na mobilu sidebar v toku není → přichytit k okrajům viewportu. */
  .page-footer,
  .shell.sidebar-collapsed ~ .page-footer,
  .bulk-bar,
  .shell.sidebar-collapsed ~ .bulk-bar{
    left:var(--space-8);
    right:var(--space-8);
  }
}

/* Velmi úzké telefony — hlavička ať nepřetéká. */
@media (max-width:420px){
  .page-header h1{ font-size:var(--font-lg) }
  .page-actions{ gap:var(--space-6) }
}

/* ===== Dock/rampa Gantt (časová osa) ===== */
.dock-timeline[hidden]{ display:none }
.dock-scroll{
  overflow-x:auto; border:1px solid var(--border); border-radius:var(--radius);
  background:var(--surface);
}
.dock-inner{ min-width:100% }
/* Osa hodin nahoře. Levý sloupec = popisek rampy (lepený). */
.dock-axis{ display:flex; height:34px; border-bottom:1px solid var(--border); position:sticky; top:0; background:var(--surface); z-index:2 }
.dock-axis-spacer{ width:120px; flex:none; border-right:1px solid var(--border); position:sticky; left:0; background:var(--surface); z-index:3 }
.dock-axis-hours{ position:relative; flex:none }
.dock-hour{
  position:absolute; top:9px; font-size:var(--font-xs); color:var(--text-muted);
  font-variant-numeric:tabular-nums; transform:translateX(-50%); white-space:nowrap;
}
.dock-hour::before{ content:""; position:absolute; top:-9px; left:50%; width:1px; height:8px; background:var(--border) }

/* Měřítko osy — uvnitř pravé zóny toolbaru (jen v režimu Časová osa).
   Segmentovaný přepínač sladěný na 32px = výška ostatních toolbar prvků
   (search, tlačítka), aby se panel při přepínání view neposouval na výšku. */
.dock-zoom{ display:flex; align-items:center; gap:var(--space-6) }
.dock-zoom[hidden]{ display:none }
.dock-zoom .seg{ margin-bottom:0 }
.dock-zoom .seg-btn{ padding:0 var(--space-10) }   /* užší horizontální padding v toolbaru */
.dock-zoom-label{ font-size:var(--font-sm); color:var(--text-muted); font-weight:500; white-space:nowrap }

/* Lanes wrapper drží čáru „teď" přes všechny rampy (position:relative v JS). */
.dock-lanes{ position:relative }
.dock-lane{ display:flex; border-bottom:1px solid var(--surface-muted) }
.dock-lane:last-child{ border-bottom:0 }
.dock-lane-head{
  width:120px; flex:none; display:flex; align-items:center; padding:0 var(--space-12);
  font-size:var(--font-sm); font-weight:600; color:var(--text);
  border-right:1px solid var(--border); position:sticky; left:0; background:var(--surface); z-index:1;
}
.dock-lane-track{
  position:relative; flex:none;
  /* jemné svislé hodinové linky přes celou dráhu; šířka hodiny = --dock-hour-w
     (nastavuje JS dle zoomu). */
  background-image:repeating-linear-gradient(90deg, var(--surface-muted) 0 1px, transparent 1px var(--dock-hour-w, 132px));
  background-position:0 0;
}
/* Blok dopravy — barva dle stavu (stejné tokeny jako .status pilulky).
   Pozice (left/top/width) i výška řídí JS (top = podřádek, width = trvání).
   Víceřádkový obsah: čas+trvání (r1) · dopravce · druh·SPZ — řádků je málo,
   tak ukážeme víc info na první pohled bez tooltipu. */
.dock-block{
  position:absolute; height:54px;
  border:0; border-left:3px solid var(--text-muted);
  border-radius:var(--radius-xs);
  padding:var(--space-6) var(--space-8); overflow:hidden; cursor:pointer; text-align:left;
  display:flex; flex-direction:column; justify-content:flex-start; gap:2px;
  background:var(--surface-muted); color:var(--text);
  transition:box-shadow .12s ease, transform .12s ease;
}
.dock-block:hover{ box-shadow:var(--shadow-block-hover); transform:translateY(-1px); z-index:4 }
.dock-block:focus-visible{ outline:none; box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--brand-ring-strong); z-index:4 }
/* Řádek 1: čas vlevo, trvání vpravo. */
.dock-block-r1{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--space-6); line-height:1 }
.dock-block-time{ font-size:11px; font-weight:700; font-variant-numeric:tabular-nums; flex:none }
.dock-block-dur{ font-size:10px; font-weight:600; opacity:.6; font-variant-numeric:tabular-nums; flex:none; white-space:nowrap }
/* Řádek 2: dopravce (hlavní identifikace). */
.dock-block-carrier{ font-size:var(--font-xs); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; line-height:1.25 }
/* Řádek 3: druh · SPZ (tlumené). */
.dock-block-meta{ font-size:10px; opacity:.7; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; line-height:1.2 }
/* Kolize (blok musel uhnout do dalšího podřádku kvůli překryvu na rampě) —
   jemný výstražný okraj, ať dispečer vidí souběh, ale osa nekřičí. */
.dock-block.is-collision{ box-shadow:inset 0 0 0 1px var(--danger) }
/* stavové varianty bloku */
.dock-block.stage-arrived{ background:var(--stage-arrived-bg); color:var(--stage-arrived-fg); border-left-color:var(--stage-arrived-fg) }
.dock-block.stage-ramp{    background:var(--stage-ramp-bg);    color:var(--stage-ramp-fg);    border-left-color:var(--stage-ramp-fg) }
.dock-block.stage-loading{ background:var(--stage-loading-bg); color:var(--stage-loading-fg); border-left-color:var(--stage-loading-fg) }
.dock-block.stage-departed{background:var(--stage-departed-bg);color:var(--stage-departed-fg);border-left-color:var(--stage-departed-fg) }
.dock-block.stage-done{    background:var(--stage-done-bg);    color:var(--stage-done-fg);    border-left-color:var(--stage-done-fg) }
.dock-block.draft{ background:var(--surface-muted); color:var(--text-muted); border-left-style:dashed; border-left-color:var(--text-faint) }

.dock-empty{ padding:var(--space-24); text-align:center; color:var(--text-muted) }

/* Legenda pod osou. */
.dock-legend{ display:flex; flex-wrap:wrap; gap:var(--space-8) var(--space-16); padding:var(--space-12) var(--space-4) 0 }
.dock-leg{ display:inline-flex; align-items:center; gap:var(--space-6); font-size:var(--font-sm); color:var(--text-muted) }
.dock-swatch{ width:18px; height:18px; border-radius:var(--radius-xs); border-left:4px solid var(--text-muted); flex:none }
.dock-swatch.stage-arrived{ background:var(--stage-arrived-bg); border-left-color:var(--stage-arrived-fg) }
.dock-swatch.stage-ramp{    background:var(--stage-ramp-bg);    border-left-color:var(--stage-ramp-fg) }
.dock-swatch.stage-loading{ background:var(--stage-loading-bg); border-left-color:var(--stage-loading-fg) }
.dock-swatch.stage-departed{background:var(--stage-departed-bg);border-left-color:var(--stage-departed-fg) }
.dock-swatch.stage-done{    background:var(--stage-done-bg);    border-left-color:var(--stage-done-fg) }
.dock-swatch.draft{ background:var(--surface-muted); border-left-color:var(--text-faint) }
.dock-swatch.is-collision{ background:transparent; border:0; box-shadow:inset 0 0 0 1.5px var(--danger); }
/* Oddělovač v legendě před položkou „Kolize". */
.dock-leg--sep{ margin-left:var(--space-8); padding-left:var(--space-16); border-left:1px solid var(--border) }

/* Čára „teď" — svislá linka přes všechny rampy, se štítkem času nahoře. */
.dock-now{ position:absolute; top:0; bottom:0; width:2px; background:var(--danger); z-index:3; pointer-events:none }
.dock-now-flag{
  position:absolute; top:-1px; left:50%; transform:translateX(-50%);
  font-size:10px; font-weight:700; font-variant-numeric:tabular-nums;
  color:var(--on-accent); background:var(--danger);
  padding:1px var(--space-6); border-radius:var(--radius-xs); white-space:nowrap;
}
