/* ============================================================
   Airine Design System — design-system.css
   Jediný sdílený CSS soubor. Načítá se po inline <style> → vždy vyhraje.

   OBSAH — čísla sekcí jdou průběžně podle pořadí v souboru, bez písmen
   a bez duplicit (přečíslováno 27. 9. 2026, audit designu ds-08; do té
   doby 0a–0e, 7a, 32a a zdvojená 22, 31–36). Odkaz „sekce N" v kódu,
   testech i v docs/design-system.md míří na číslo odsud. Nová sekce
   dostane další volné číslo na konci, ne písmeno.

    0  CSS proměnné (:root)            33  Legacy button aliases
    1  Night — tmavý režim             34  Navigační hlavička
    2  Papír, tisk a viditelnost       35  Form inputs
    3  Fonty                           36  Stat cards
    4  Ikony (Material Symbols)        37  Sub-navigation
    5  Reset & base                    38  Plocha boxu
    6  Roviny                          39  Shared settings
    7  Checkbox                        40  Row hover
    8  Buttons                         41  Loading skeleton
    9  Rec dot                         42  Unified data table
   10  Glass card                      43  KPI detail modal
   11  Typography                      44  KPI rank row
   12  Button sizes                    45  Hover — tři recepty
   13  Button secondary                46  gs-switcher
   14  Záře okraje za kurzorem         47  Modal navigation
   15  Section box                     48  gs-cb (zaškrtávací pole)
   16  Search button (zrušeno)         49  gs-field-unit
   17  Sort button                     50  Finance item utilities
   18  Dashboard card                  51  gs-avatar
   19  Dashboard layout grids          52  gs-chip (štítek)
   20  Chart tooltip                   53  gs-prio
   21  Donut chart                     54  gs-clp (checklist)
   22  Dashboard panel                 55  gs-view
   23  Dash item list                  56  Části modalu na plátně
   24  Form group                      57  Popover, Toolbar, Prop Grid
   25  Modal                           58  gs-tabs
   26  Pay badge (smazáno)             59  gs-dash (bloky přehledu)
   27  Fakturoid subject picker        60  gs-obd + gs-kal (období)
   28  Profit                          61  Responsivita
   29  Ico-btn                         62  gs-cas + gs-osa (čas)
   30  Entity pill                     63  Domů: ukazatele z čárek
   31  Filter bar (+ search)           64  Lišta výběru a stav bloku
   32  Settings modal                  65  Přístupnost
   ============================================================ */

/* ── 0. CSS PROMĚNNÉ ─────────────────────────────────────────
   Jeden zdroj pravdy pro všechny tokeny. Sloučeno z původního
   style.css (Apple hodnoty) a :root bloků z HTML stránek. */

:root {
  /* Značka „design systém je na stránce načtený". Čte ji `shared.js`
     (gsDesignSystem) — vrstvy, které si kreslí vlastní plovoucí panely
     (nabídka místo systémového `<select>`, sekce 57), se bez pravidel
     odsud nesmí spustit. `invoice.html` a `report.html` DS záměrně
     nenačítají, jsou to dokumenty, ne obrazovky appky. Nemazat. */
  --gs-ds: 1;

  /* Prohlížeči řekne, v jakém režimu kreslí SVOJE prvky — posuvníky, nabídku
     systémového `<select>`, zaškrtávátka, autofill. Bez toho zůstane
     v tmavé appce bílý posuvník a bílá rozbalovací nabídka. */
  color-scheme: light;

  /* ══ PALETA — 16 hodnot, víc jich appka nemá ═══════════════════════════
     14. 9. 2026, na přání: „minimalizovat rozsah barev … max do 16 druhů".
     Měření před zásahem našlo 135 různých barev — 60 tokenů nesoucích
     46 různých hodnot, 56 hexů mimo :root a 33 barevných rgba(). Tenhle
     blok je celá paleta; všechno ostatní v souboru je z něj odvozené
     přes color-mix() nebo je to alias, ne nová barva.

     Co zmizelo a proč: SEKČNÍ BARVY MODULŮ (--green a spol.).
     Sedm barev jen na to, aby se moduly poznaly od sebe — ale moduly se
     poznají názvem a ikonou. Barva v appce od teď znamená STAV nebo
     OZNAČENÍ, nikdy „kde jsem". Aktivní záložka, focus pole i ikony ve
     Spotlightu jsou proto modré všude stejně.

     Pravidlo pro každou další barvu: nejdřív dolož, že ji nejde namíchat
     z téhle palety. Strop je 16, od 27. 9. 2026 je obsazeno 15. Hlídá test/barvy.test.js. */

  /* ── Modrá — jediná akční barva (2 hodnoty) ──────────────── */
  /* --blue-brand je hodnota, --blue role. Den je má shodné; Night (sekce 1) roli
     zesvětlí na odstín z Figmy (node 5154:6567), a protože se token nemůže
     namíchat sám ze sebe, potřebuje k tomu značkovou modrou pod jiným jménem.
     Mimo tenhle soubor se --blue-brand nepíše — komponenta chce roli. */
  --blue-brand: #1265FF;   /* Primary Blue — značka */
  --blue-brand-dk: #0E52D4;   /* Hover značkové modré. Není odvozená: značková hodnota. */
  --blue:    var(--blue-brand);   /* akce, odkazy, aktivní stav, focus */
  --blue-dk: var(--blue-brand-dk);   /* hover --blue */
  /* Modrý TEXT na modrém podkladu. V Day totéž co --blue-dk, v Night světlejší (sekce 1). */
  --blue-txt: oklch(from var(--blue-brand) 0.546 0.219 h);

  /* ── Krajní hodnoty (2) ──────────────────────────────────────
     --white NENÍ totéž co --surface, i když je hodnota stejná. --surface je
     „plocha, na které appka leží"; --white je „popředí na plné barvě" —
     text na modrém tlačítku, na červeném badge. Kdyby se povrch někdy
     posunul do krémové, tyhle dva se rozejdou. Proto dva tokeny. */
  --ink:   #030305;   /* Značkový inkoust — nejtmavší hodnota appky. Je to barva
                         loga (Brand/Logo, docs/brand.md), ne obecná černá: dlaždice
                         loga v hlavičce a na výkazu, podklad app ikony. Čistá
                         #000000 se 18. 9. 2026 zrušila — appka neměla dvě černé,
                         měla jednu a ta patří značce. */
  --white: #FFFFFF;

  /* ── Šedá škála (7) ──────────────────────────────────────────
     Jediná neutrální osa appky. Číslo = tmavost, ne pořadí použití.
     Do 14. 9. 2026 vedle sebe žily tři paralelní šedé sady (--t*, --bg*,
     --border*, --gray*, --gray-4, --gray-9) se sedmi duplicitními
     hodnotami; tohle je jejich průnik. */
  --gray-9: #111827;   /* nejtmavší — text i tmavé plochy (tooltip, aktivní segment) */
  --gray-7: #4B5563;
  --gray-6: #6B7280;
  --gray-4: #9CA3AF;
  --gray-2: #E5E7EB;
  --gray-1: #F3F4F6;
  --gray-0: #F9FAFB;   /* nejsvětlejší */

  /* ── Stavové barvy (4) ───────────────────────────────────────
     Význam, ne identita. Zelená = hotovo/příjem, žlutá = čeká/pozor,
     červená = chyba/výdaj, fialová = označení (nabídka, štítek).
     Víc významů než tyhle čtyři appka nemá — když se objeví pátý,
     patří sem, ne do nové barvy. */
  /* 27. 9. 2026 (audit vlna 2, verze 3 náhledu, schválil Ondra): zelená
     a červená jsou syté odstíny se stejnou světlostí jako značková modrá
     (OKLCH L 0,53 a 0,56). Dřívější #32B237, mentolová #7BFFAB a #F55454
     z palety vypadly — noční odstín se odvozuje z denního přes
     oklch(from …), stejný tón, jiná světlost. Paleta má teď 15 hodnot.
     --*-den je hodnota, --green/--red role: Night roli přepíše a plocha
     tlačítka (--plocha-*) potřebuje denní hodnotu pod jménem, které Night
     nepřepisuje. */
  --green-den: #06823B;
  --green:  var(--green-den);
  --amber:  #FFC812;
  --red-den: #DB0118;
  --red:    var(--red-den);
  --purple: #8B5CF6;
  /* --amber SE NIKDY NEPÍŠE JAKO BARVA TEXTU. Na bílé má kontrast 1,7 : 1,
     tedy nečitelný; je to barva ploch — tečka, pruh, výplň, rámeček. Text
     v „žluté" bere --amber-txt (Day 5,06 : 1, viz role textu níž). Do 14. 9. 2026 to appka obcházela
     tím, že si na 44 místech vedla vlastní tmavší oranžovou (#F59E0B,
     #EA580C, #D97706, #B45309…) — pět barev navíc kvůli jednomu pravidlu,
     které nikde nebylo napsané. Hlídá test/barvy.test.js. */

  /* ══ ODVOZENÉ ODSTÍNY — žádná nová barva ═══════════════════════════════
     Každý světlý podklad je ta samá barva pod bílou, každý tmavý text ta
     samá barva pod --gray-9. Procenta nejsou od oka: vznikla zpětným
     výpočtem z hodnot, které v appce byly natvrdo, takže vizuální posun
     je nanejvýš 1/255 v kanálu. Kdo bude chtít jiný odstín, mění
     procento, ne barvu — paleta se tím nezvětší. */
  /* Podklady stavů (verze 3): tentýž tón jako sytá barva, světlost 0,96. */
  --blue-lt:   oklch(from var(--blue-brand) 0.966 0.016 h);
  --green-lt:  oklch(from var(--green-den) 0.960 0.031 h);
  --amber-lt:  oklch(from var(--amber) 0.966 0.041 h);
  --red-lt:    oklch(from var(--red-den) 0.961 0.018 h);
  /* 24. 9. 2026 z 8 % na 14 %. Při 8 % vycházelo #F6F2FE, což bylo 3,45 ΔE od
     --blue-lt (#EEF4FF) — dvě různá sdělení (modrá = nový/info, fialová =
     nabídka, barter, admin) stojí vedle sebe ve stejných výpisech a lišila se
     míň, než člověk pozná. V Night se rozcházejí o 12,4, takže se to pletlo jen
     v jednom režimu. 14 % dá 7,66, tedy stejný odstup, jaký mají --red-lt
     a --amber-lt (7,73). */
  --purple-lt: oklch(from var(--purple) 0.964 0.019 h);
  /* Tmavé varianty — čitelný text na světlém podkladu téže barvy.
     Samotné --amber a --green jsou na bílé pod prahem kontrastu.
     27. 9. 2026 (pristupnost-12) přepočítáno na AA i na podkladu téže barvy:
     zelená 75 → 65 % (5,23 : 1 na bílé, 4,65 na --green-lt), amber 55 → 48 %
     (5,06 / 4,89). Dřív tu u amber stálo „5,0 : 1", ve skutečnosti 4,20.
     V Night jsou -dk neutrální (--t1). Nový kód nepíše -dk, ale roli
     --*-txt níž; -dk je jen denní stavební kámen. */
  --green-dk:  var(--green-txt);
  --amber-dk:  var(--amber-txt);
  --red-dk:    var(--red-txt);

  /* ══ ROLE TEXTU A POPŘEDÍ (27. 9. 2026, audit vlna 2) ════════════════════
     Stavová barva jako TEXT se nepíše paletou (--green 2,78 : 1, --red 3,34,
     --purple 4,23, --amber 1,7 na bílé), ale rolí. Role má v každém režimu
     hodnotu, která projde AA 4,5 : 1 na --surface, --bg, --bg-2 i na podkladu
     téže barvy (--*-lt). Hlídá test/vlna2-jadro.test.js, tabulka je
     v docs/design-system.md §3.
     Mapa stav → barva (rozhodnutí 2a) platí v OBOU režimech, proto role
     v Night barvu drží (mentolová, světlejší červená, amber, světlejší
     fialová) — stupnice „v pořádku / blíží se / problém" nesmí v tmě přijít
     o prostřední stupeň (night-04). Plochy, tečky a pruhy dál berou paletu. */
  /* Verze 3: jeden sytý odstín na stav — text, tečka, hrana chyby i plocha
     tlačítka. Zelená a červená jsou přímo paleta (4,9 a 5,2 : 1 na bílé),
     amber a fialová se odvozují přes oklch na stejnou světlost (≈ 0,54). */
  --green-txt:  var(--green);
  --red-txt:    var(--red);
  --amber-txt:  oklch(from var(--amber) 0.541 0.132 calc(h - 32.9));
  --purple-txt: oklch(from var(--purple) 0.540 0.209 h);
  /* Plná zelená a červená plocha pod bílým písmem (tlačítko, oznámení,
     štítek Urgentní). V obou režimech denní sytá hodnota — varianta B. */
  --plocha-green: var(--green-den);
  --plocha-red:   var(--red-den);
  /* Plná modrá plocha pod bílým písmem (tlačítko, avatar, toast, plný blok).
     V Day totéž co --blue; Night --blue zesvětluje a bílá by na ní měla
     3,12 : 1, proto plocha zůstává značková (4,85 : 1) — pristupnost-10. */
  --blue-plocha: var(--blue);
  /* Popředí na plné zelené (tlačítko úspěchu, fajfka). Od verze 3 bílá
     v obou režimech — plné plochy berou --plocha-green. */
  --na-green:   var(--white);
  /* Papír: náhled toho, co dostane klient (logo faktury, list dokladu).
     Podložka loga (logo klienta je kreslené na bílou) a plocha tisku.
     V obou režimech bílá; doklad sám je od 27. 9. 2026 v Night tmavý. */
  --papir:      var(--white);

  /* ══ SÉMANTICKÁ VRSTVA — jen jména, ne barvy ═══════════════════════════
     Aliasy existují, aby kód říkal ROLI („text sekundární"), ne odstín
     („šedá 7"). Na pravé straně smí stát výhradně token z palety výš. */

  /* ── Text ───────────────────────────────────────────────── */
  --t1: var(--gray-9);   /* text-primary */
  --t2: var(--gray-7);   /* text-secondary */
  /* --t3 27. 9. 2026 o kus tmavší (pristupnost-11): --gray-6 měl na --bg
     4,39 : 1 a nesl 10–11px štítky. Teď 5,00 na --bg, 4,60 na --bg-3. */
  --t3: color-mix(in srgb, var(--gray-6) 70%, var(--gray-7));   /* text-tertiary */

  /* ── Povrchy ────────────────────────────────────────────── */
  --bg:        var(--gray-1);   /* background-tertiary */
  --bg-2:      var(--gray-0);   /* background-secondary */
  --surface:   var(--white);    /* background-primary */
  --border:    var(--gray-2);   /* border-default */
  --border-md: var(--gray-4);   /* border-strong */
  /* Hrana ovladače (vlna 3, rozhodnutí 10a; pristupnost-15, ds-19): rámeček
     pole mimo okno, dráha vypnutého přepínače, rámeček zaškrtávátka. WCAG
     1.4.11 chce 3 : 1 proti sousední ploše — --border má na bílé 1,24 : 1,
     takže vypnutý přepínač skoro nebyl vidět. Spočítáno (test/vlna2-jadro):
     Day 3,68 na --surface, 3,35 na --bg, 3,52 na --bg-2, 3,08 na --bg-3;
     bílý jezdec na ní 3,68. Plochy karet zůstávají klidné (--border), silnější
     je jen hrana toho, na co se kliká. */
  --border-pole: color-mix(in srgb, var(--gray-4) 73%, var(--gray-2));
  /* Plocha pole v okně (okna-10): pole je vždy o stupeň světlejší než tělo
     okna (--bg-2). V Day bílá karta = --surface, v Night přepsané níž. */
  --pole-bg: var(--surface);
  /* Vnořený podklad: kontejner, do kterého se kladou karty --surface (sloupec
     kanbanu, dráha segmentu, tělo auth stránky). V Day --bg; v Night musí být
     TMAVŠÍ než karta, jinak karta vypadá jako díra (night-06). */
  --plocha-vnor: var(--bg);
  /* Podložky prvků hlavičky (ikonová tlačítka, pilulka časovače, avatar).
     V Night mají --surface přesně barvu lišty a kolečka zmizí (night-12). */
  --hd-podlozka: var(--surface);
  --hd-inicialy: var(--ink);   /* kolečko s iniciálami workspace */

  /* ── Tři role, které drží tmavý režim (19. 9. 2026, sekce 1) ───────────
     Bez nich by Night znamenal přepsat desítky pravidel; s nimi stačí
     přebarvit tokeny. Každá odpovídá na jednu otázku, kterou `--white`
     do té doby zodpovídalo třikrát najednou:

       --mix-bg   „do čeho se míchá světlý podklad" — základ každého
                  color-mix(), který dělá jemný odstín plochy. V Day je to
                  bílá, v Night inkoust, takže tentýž zápis dá tam i tam
                  sotva znatelný nádech místo svítící skvrny.
       --inv-*    „plocha obrácená proti zbytku appky" — toast, aktivní
                  segment, tooltip. Nejde o černou a bílou, jde o opak
                  toho, na čem to leží; v Night se tedy obě otočí.
       --glass-*  sklo plovoucích ploch. Bílý závoj s rozostřením je v Night
                  mléčná skvrna, potřebuje vlastní hodnotu. */
  --mix-bg:   var(--white);
  --inv-bg:   var(--gray-9);
  --inv-fg:   var(--white);
  --glass-bg: rgba(255, 255, 255, 0.75);
  --glass-br: color-mix(in srgb, var(--ink) 8%, transparent);
  /* Průhledný hover — potemnění plochy, na které leží. V Night musí naopak
     prosvětlit, jinak není vidět nic. Do 19. 9. 2026 se token `--hover` četl na
     dvou místech, ale NIKDE nebyl definovaný: v DS s fallbackem (fungovalo
     náhodou), v crm.css bez něj (hover tlačítek fází nešel vidět vůbec).
     Hover, který se dá vidět jen v jednom režimu, je tatáž chyba o patro výš. */
  --hover: color-mix(in srgb, var(--ink) 4%, transparent);
  /* Řádek výpisu pod kurzorem (29. 9. 2026, návrh „Výpis bez výplně", Ondra:
     „u den bude 5 % a noc tedy 10 %"). Modrá jako záře, ale světlejší než
     `--blue-lt`: ta patří vybranému řádku, hover ho nesmí přebít. Vržená záře
     řádku má ve dne polovinu noci — na bílé modrá svítí víc než na tmavé. */
  --blue-hover:  color-mix(in srgb, var(--blue) 5%, transparent);
  --radek-zare:  color-mix(in srgb, var(--blue) 10%, transparent);

  /* ── Navigace a datové plochy (22. 9. 2026, Figma 5154:6926 / 5154:6567) ──
     Role, ve kterých se Day a Night neliší jen odstínem, ale i volbou:
     neaktivní záložka je v Day plný text, v Night poloviční bílá; aktivní
     ikona je v Day modrá, v Night bílá; tlumený proužek je v Day světle modrý,
     v Night bílý. Kdyby to nesly šedé tokeny, musely by se kvůli jedné liště
     přebarvit všude. Čtou: .nav-tab, .sub-tab (sekce 34 a 37), .gs-dash-pruh,
     .gs-graf* (sekce 59), cesta peněz ve Financích (finance.css). */
  --nav-t:      var(--t1);   /* neaktivní záložka hlavní lišty */
  --subnav-t:   var(--t1);   /* neaktivní záložka podnavigace */
  --nav-akcent: var(--blue); /* ikona aktivní záložky */
  /* Dráha ukazatele = žlábek POD náplní (--pruh-plny / --pruh-tlumeny), ne ta
     náplň. Čtou ji .gs-dash-pruh (sekce 59) i .proj-pruh (projects.css); do
     24. 9. 2026 měl každý z nich vlastní token a tím i jinak tmavý žlábek
     (#F3F4F6 × #E5E7EB). Night override netřeba — --bg-3 se přepíná sám. */
  --pruh-bg:    var(--bg-3);
  /* Plná modrá je na ČELE náplně, ne na začátku (Vercel 12. 10. 2026: „gradient
     jde naopak… není vidět, že tam něco zbývá"). Světlé čelo splývalo se žlábkem. */
  --pruh-plny:  linear-gradient(90deg, color-mix(in srgb, var(--blue) 58%, var(--white)) 0%, var(--blue) 100%);
  --pruh-tlumeny: linear-gradient(90deg,
    color-mix(in srgb, var(--blue) 40%, var(--white)) 0%,
    color-mix(in srgb, var(--blue) 20%, var(--white)) 100%);
  /* Přijato ke spodku zesvětluje do bílé v obou režimech (Figma 5154:6567). */
  --graf-in: linear-gradient(180deg, var(--blue) 0%, color-mix(in srgb, var(--blue) 55%, var(--white)) 100%);
  --graf-out: linear-gradient(180deg,
    color-mix(in srgb, var(--blue) 34%, var(--white)) 0%,
    color-mix(in srgb, var(--blue) 14%, var(--white)) 100%);
  --graf-teck-out: color-mix(in srgb, var(--blue) 24%, var(--white));
  /* Cesta peněz: tři sytosti jedné modré, popisky všech tří v --blue-dk. */
  --cesta-k: var(--blue-txt);
  --cesta-1: linear-gradient(90deg,
    color-mix(in srgb, var(--blue) 28%, var(--white)) 0%,
    color-mix(in srgb, var(--blue) 17%, var(--white)) 100%);
  --cesta-2: linear-gradient(90deg,
    color-mix(in srgb, var(--blue) 61%, var(--white)) 0%,
    color-mix(in srgb, var(--blue) 46%, var(--white)) 100%);
  --cesta-3: linear-gradient(90deg, var(--blue) 0%, var(--blue-dk) 100%);

  /* ── Focus ──────────────────────────────────────────────────
     Jedna barva pro celou appku. Token zůstává kvůli pravidlům s vyšší
     specificitou, která ho čtou jako var(--focus, var(--blue)). */
  --focus: var(--blue);

  /* Stav platby tu do 16. 9. 2026 měl vlastní trojici (--pay-k / --pay-u /
     --pay-n). Nečetlo ji ani jedno pravidlo a ani jedna stránka: badge stavu
     platby se kreslí chipem (.gs-chip-green a spol., sekce 52), který si barvu
     bere z palety sám. Byly to tři jména bez uživatele, takže padla — role bez
     použití není sémantika, je to slovník navíc. */

  /* ── CRM stav leadu ─────────────────────────────────────────
     Pět stavů, čtyři barvy palety + šedá pro „ztraceno". Do 14. 9. 2026
     měl každý stav vlastní hex (#3B82F6, #F59E0B, #10B981, #9CA3AF) —
     čtyři barvy navíc jen proto, že vznikly jinde než paleta. */
  --s-novy:       var(--blue);
  /* Barva IDENTITY (avatar, tečka), ne text: proto ne -dk, který Night
     neutralizuje na bílou (night-03). Hodnota = denní --amber-dk, pod bílými
     iniciálami 5,06 : 1. Text štítku stavu bere --amber-txt. */
  --s-rozjednano: color-mix(in srgb, var(--amber) 48%, var(--gray-9));
  --s-nabidka:    var(--purple);
  --s-klient:     var(--green);
  --s-ztraceno:   var(--gray-4);

  /* ── Priorita ───────────────────────────────────────────────
     Záměrně stejné barvy jako stavy: nízká je neutrální, střední akční,
     vysoká chybová. Kdo je chce odlišit, mění tvar nebo ikonu, ne barvu. */
  --p-nizka:   var(--gray-4);
  --p-stredni: var(--blue);
  --p-vysoka:  var(--red);

  /* ── Hvězdička hodnocení ────────────────────────────────────
     Jediné místo, kde plný --amber jde do vlastnosti `color`, a je to
     v pořádku: hvězda je vyplněný tvar, ne text ke čtení. Vlastní token proto,
     aby pravidlo „--amber není barva textu" zůstalo bez výjimek a aby se
     odsud nekopíroval --amber do popisků. Čte crm.css (.star-btn). */
  --star: var(--amber);

  /* ── Pořadí (žebříčky v KPI) ────────────────────────────────
     Zlatá/stříbrná/bronzová byly tři vlastní hexy (#F59E0B, #94A3B8, #B45309).
     Pořadí se ale nemusí říkat třemi barvami — stačí klesající důraz:
     teplá a tmavá → střední šedá → světlá šedá. Čte finance.css
     (.kpi-rank-num). Zlatá je --amber-dk, ne --amber: je to ČÍSLO ke čtení. */
  --rank-gold:   var(--amber-txt);
  --rank-silver: var(--gray-6);
  --rank-bronze: var(--gray-4);

  /* ── Roviny aplikace — „Vzduch“ (2026-09-08) ─────────────────
     Airine je od air. Roviny proto nejsou tři plné šedivé, ale tři závoje
     bílé nad jednou modrobílou oblohou: čím výš v žebříku, tím víc bílé
     mlhy mezi divákem a oblohou. Pod tím vším prosvítá pořád stejný
     gradient, takže se plochy nedají „rozstříhat“ — nikde nevzniká hrana
     dvou nezávislých barev.

       obloha  --sky      gradient na <body>, nehýbe se
       rovina 1 .pl-1     leží na obloze         → za hlavní navigací
       rovina 2 .pl-2     leží na rovině 1       → lišta podstránek
       rovina 3 .pl-3     leží na rovině 2       → panel obsahu

     Vrstvy jsou samostatné fixed elementy (viz sekce 6), každá vede až
     ke spodní hraně okna a začíná o stupínek níž než ta předchozí. Proto
     žádná nemá viditelný konec — vidět je jen její horní hrana.

     Klíč k neviditelnému spoji: závoje se skládají, takže záložka spojující
     se do roviny pod sebou nesmí nést cílovou průhlednost, ale rozdíl proti
     tomu, co už pod ní leží:  a = 1 − (1 − a_cíl) / (1 − a_pod).
     Odtud --a1/--a2/--a3 níž — dávají viditelný žebřík .10 / .38 / .68.
     Nesahat na ně po jedné; buď se přepočítají všechny, nebo žádná.

     Bez backdrop-filter: za rovinami není nic než hladký gradient (rozmazání
     gradientu je zas ten samý gradient) a filtry se navíc neskládají lineárně,
     což by tuhle rovnici rozbilo. Skutečné sklo patří plovoucím panelům
     (modály, Spotlight, Nastavení), ne rovinám samotným. */
  --sky:
    radial-gradient(115% 85% at 78% -20%, rgba(255,255,255,.80) 0%, rgba(255,255,255,0) 55%),
    /* Šest zastávek oblohy byly hexy, ale nikdy to nebylo šest barev:
       zpětný výpočet ukázal, že všechny do jedné jsou --blue pod bílou
       na 40 / 28 / 16 / 8 / 4 / 1 %. Zápis to teď říká nahlas. Posun
       proti původním hodnotám je 1/255 v kanálu, tedy žádný. */
    linear-gradient(177deg,
      color-mix(in srgb, var(--blue) 40%, var(--white))   0%,
      color-mix(in srgb, var(--blue) 28%, var(--white))  18%,
      color-mix(in srgb, var(--blue) 16%, var(--white))  42%,
      color-mix(in srgb, var(--blue)  8%, var(--white))  66%,
      color-mix(in srgb, var(--blue)  4%, var(--white))  85%,
      color-mix(in srgb, var(--blue)  1%, var(--white)) 100%);
  --a1: .10;    /* výsledek nad oblohou:  .10 */
  --a2: .311;   /* výsledek nad rovinou 1: .38 */
  --a3: .484;   /* výsledek nad rovinou 2: .68 */
  --veil-1: rgba(255,255,255, var(--a1));
  --veil-2: rgba(255,255,255, var(--a2));
  --veil-3: rgba(255,255,255, var(--a3));
  /* O kolik je panel obsahu užší než rovina pod ním. Drží dojem samostatné
     desky položené na tu spodní, ne jen další barvy odshora dolů. */
  --plane-inset: 5px;

  /* Surface/bg-3 v knihovně Airine DS. Role: **zapuštěná plocha** — žlábek, do
     kterého je něco vsazené. Čtyři čtenáři: --pruh-bg (dráha ukazatele),
     .gs-switcher (DS sekce 46), plocha stránky /admin a --cesta-3 v Night.
     Čtvrtá příčka plošného žebříku, mezi --bg a --border.

     24. 9. 2026 zpátky na vlastní hodnotu. Mezitím tu stálo var(--gray-2), čímž
     byl --bg-3 v Day na bit přesně --border: plocha a hrana stejné barvy znamená,
     že hrana na té ploše zmizí a nikdo si nevšimne, když se jedna z nich pohne.
     V Night se nekryly (#262628 × #2E2E30), takže to bylo vidět jen v jednom
     režimu. Výsledek #E9EBEE leží mezi --bg (#F3F4F6) a --border (#E5E7EB).
     Žádná gray-N tam není, ale literál by byl 17. barva palety — a strop 16 se
     podle test/barvy.test.js nesmí zvedat, odstín se míchá z toho, co už je. */
  --bg-3: color-mix(in srgb, var(--gray-2) 71%, var(--gray-1));

  /* Výšky pruhů navigace. Pevné, protože podle nich se počítá, kde končí
     jedna rovina a začíná další. Změna výšky hlavičky = změna téhle
     proměnné, nikde jinde. */
  --hd-h:     72px;
  --subnav-h: 48px;
  /* Odsazení záložek od horní hrany jejich pruhu. Bez něj by se záložka
     dotkla roviny nad sebou a stupínek žebříku by opticky zmizel — proto
     je to jedna hodnota pro .hd i .sub-nav, ne dvě nezávislá čísla. */
  --nav-inset: 10px;
  /* Zub propojení: o kolik aktivní záložka „přeteče“ do stran, aby roh
     mezi ní a rovinou pod ní byl vydutý místo ostrého. Mezera mezi
     záložkami musí být aspoň 2× tolik, jinak by zub zasahoval do sousedky. */
  --joint: 10px;

  /* ── Gradient (sdílený pro primární tlačítka) ───────────── */
  /* Obě zastávky jsou --blue: horní o ždibec vysvětlená (4 % bílé), dolní
     je rovnou hover token. Žádná třetí modrá tu není. */
  --btn-gradient: linear-gradient(180deg,
    color-mix(in srgb, var(--blue) 96%, var(--white)) 0%, var(--blue-dk) 100%);
  /* Zelený protějšek pro .gs-btn-success (Ondra 12. 10. 2026: „zelený gradient
     pro fakturu"). Plocha --plocha-green je i v Night denní, proto stačí tady. */
  --btn-gradient-green: linear-gradient(180deg,
    color-mix(in srgb, var(--plocha-green) 92%, var(--white)) 0%,
    color-mix(in srgb, var(--plocha-green) 88%, var(--ink)) 100%);
  --btn-shadow:   0 1px 3px rgba(0,0,0,.18), inset 0 1px 0 rgba(255,255,255,.18);

  /* Gradients */
  --gradient-blue: linear-gradient(135deg, var(--blue) 0%,
    color-mix(in srgb, var(--blue) 72%, var(--white))  55%,
    color-mix(in srgb, var(--blue) 36%, var(--white)) 100%);
  --gradient-blue-modal: linear-gradient(155deg, var(--blue) 0%,
    color-mix(in srgb, var(--blue) 72%, var(--white)) 30%,
    color-mix(in srgb, var(--blue) 42%, var(--white)) 60%,
    color-mix(in srgb, var(--blue) 18%, var(--white)) 85%, var(--blue-lt) 100%);

  /* ── Stíny (Apple) ──────────────────────────────────────── */
  --sh:    0 2px 8px  rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
  --sh-md: 0 4px 12px rgba(0,0,0,.08), 0 2px 4px rgba(0,0,0,.04);
  --sh-lg: 0 8px 32px rgba(0,0,0,.12), 0 2px 8px rgba(0,0,0,.06);
  /* Vrstvy (ds-13, 29. 9. 2026). Jediná stupnice pro všechno, co plave nad
     stránkou. Lokální pořadí uvnitř komponenty (0–3, jezdec pod textem) se
     píše číslem; cokoli, co se překrývá s jinou komponentou, jde přes token.
     Okno nad oknem (--z-modal-nad) jsou okna, která se otevírají z .modal
     nebo z panelu: vlastní okna stránek, KPI detail, Fakturoid. Popover je nad
     všemi okny, protože se z nich otevírá; potvrzení nad ním, protože se ptá
     na okno pod sebou. Hláška po akci (--z-confirm) nemá pointer-events.
     Nad potvrzením je pásmo celé appky: provozní banner (--z-banner) a widgety
     injektované do každé stránky (--z-widget: feedback, spotlight, lightbox
     adminu), které se otevírají i nad otevřeným oknem. */
  --z-tip: 20;
  --z-hd: 30;
  --z-lista: 50;
  --z-panel: 90;
  --z-modal: 100;
  --z-modal-nad: 200;
  --z-popover: 400;
  --z-potvrd: 500;
  --z-banner: 9000;
  --z-widget: 9500;
  --z-toast: 9999;
  --z-confirm: 10000;
  /* Závoj pod oknem (jazyk-14). Jedna sytost pro každé okno i panel; do
     29. 9. 2026 byly tři (.35/.4/.45). Night má .6. Výjimku má jen lightbox
     obrázku v adminu (.72), kde je fotka a ne formulář. */
  --scrim: rgba(0,0,0,.4);
  /* Stín boxu (13. 9. 2026). Jediné, co po sjednocení odděluje bílý box od
     plochy pod ním — rámeček ani druhá bílá už tam nejsou (sekce 38). Je
     modrý, ne šedý: plocha appky je do modra (--bg-3 / .pl-*), takže šedý
     stín na ní čte jako špína. Barva je --blue (18,101,255) ve dvou vrstvách:
     těsná pod hranou, aby box držel tvar, a široká, aby se rozplynul.
     Krytí je nízké schválně — má to být „lehký, velmi světle modrý až bílý".
     27. 9. 2026 (rozhodnutí 1b: „--sh-box jako jemný prstenec") je z něj
     vlasová linka po obvodu, modrá 12 %: box drží tvar hranou, ne mrakem
     pod sebou, a vedle linek uvnitř přehledů mluví týmž jazykem. */
  --sh-box: 0 0 0 1px color-mix(in srgb, var(--blue) 12%, transparent);

  /* ── Poloměry (Apple standard) ──────────────────────────── */
  /* PRAVIDLO (2026-09-01, na přání): největší zaoblení u boxů/karet je var(--r)
     10px. Tlačítka a pill prvky (badge, entity-pill, date-btn…) smí mít větší
     nebo plně kulaté rohy — to je výjimka, ne box.
     13. 9. 2026: „retroaktivní úprava čeká na schválení" skončila — všechny
     primární boxy jedou přes sekci 38 a mají var(--r). --r-lg zůstává jen
     pro modaly a overlaye (plovoucí plocha, ne box v obsahu). */
  --r:    10px;
  --r-sm:  8px;
  --r-cb:  5px;  /* zaškrtávátko .gs-cb (Figma Checkbox 4693:131); kopíruje ho login.html */
  --r-lg: 14px;
  /* --r-pill (2026-09-02, design audit): plně oválný roh pro badge/tag/pill
     prvky — přesně ta "výjimka" zmíněná výše. Dřív bylo natvrdo 20px na 29
     místech napříč design-system.css i page-specific styly (.pay-badge,
     .entity-pill, .gs-badge, .tag-btn, .freq-badge, .ci-bdg…) —
     sjednoceno do jednoho tokenu, ať se to dá měnit na jednom místě. */
  --r-pill: 20px;
  /* --r-ctrl (2026-09-13, na přání): tvar OVLÁDACÍCH prvků — tlačítka, ikonová
     tlačítka, segmenty, přepínače, jednořádková pole, selecty, stránkování.
     Zadání bylo „tlačítka a podobně více zakulacovat jako search"; search
     (.gs-search-lg input) měl 22px na 39px vysokém poli, což je plný pill —
     tak je pill výchozí tvar všech ovládacích prvků. Do 13. 9. 2026 jich bylo
     deset různých (5, 6, 7, 8, 9, 10, 11, 12, 20, 22, 999px) a nesedělo to ani
     mezi sourozenci (.gs-seg 7px vs .gs-seg-btn 5px, .gs-btn 10px vs
     .gs-btn-sm 8px). 999px, ne 50%: pill musí držet tvar i na širokém prvku.
     VĚDOMĚ VEN: checkbox a radio (z kolečka by byl radio button), záložky
     (.nav-tab/.sub-tab/.gs-tab — drží se obsahu pod sebou), textarey
     a víceřádková pole, .gs-hero-num (0px), boxy (sekce 38 → var(--r))
     a badge/štítky, které nejsou ovládací prvky (--r-pill).
     Hlídá test/typografie.test.js. */
  --r-ctrl: 999px;
  /* --r-field (2026-09-17, na zadání): tvar FORMULÁŘOVÉHO pole — input, select
     a textarea ve formuláři nebo modalu. Do dneška měla pole týž plný pill jako
     tlačítka a Ondra na tom našel chybu: „text je oříznutý, jako kdyby ve fieldu
     byl vnitřní rádius". Není to iluze — prohlížeč obsah pole ořezává tvarem
     jeho rámečku (`overflow: clip` v UA stylu `<select>`), takže při poloměru
     999px zakulacení ukouslo první písmeno (na produkci „To invoice" → „ſo
     invoice"). Pill zůstává tomu, co se mačká a přepíná — tlačítka, segmenty,
     filtrační lišta, hledání, štítky; pole, do kterého se píše, má 10px.
     Hlídá test/typografie.test.js a test/pole-tvar.test.js. */
  --r-field: 10px;
  /* --h-ctrl (2026-09-16, na přání): VÝŠKA jednořádkových ovládacích prvků
     ve filtrační liště — hledání, select, filtr s víc volbami, segmenty,
     rozsah datumů. Do dneška si každý z nich výšku skládal z vlastního
     svislého odsazení, takže vedle sebe stály tři různě vysoké prvky
     (~30 / ~26,5 / ~28,5 px, nález Ondry na Tiketech). Výška je proto pevná
     a odsazení svisle nulové: text si uvnitř vycentruje prohlížeč, což je
     zároveň odpověď na „ve Figmě je auto, v appce sedí text nahoře" — tam to
     dělalo svislé odsazení plus metrika písma, ne line-height.
     Hlídá test/vyska-filtru.test.js. */
  --h-ctrl: 32px;
  /* --tx-center (2026-09-16): srovnání textu na OPTICKÝ střed ovladače.
     Odsazení shora o dvojnásobek rozdílu mezi středem řádkového boxu a optickým
     středem velkých písmen (účaří mínus půl capHeight); zdola nula. V `em`, aby
     platilo pro každou velikost. Hodnota patří písmu — při změně písma
     přepočítat z jeho metriky.

     Geist (od 21. 9. 2026, public/fonts/Geist-Regular.woff2, USE_TYPO_METRICS
     zapnuté, typo = hhea):

       ascent 1005 · descent 295 · lineGap 0 · capHeight 710 (na 1000 em)

     Řádkový box 1,300 em, účaří 1,005 em, střed boxu 0,650 em, optický střed
     velkých písmen 1,005 − 0,355 = 0,650 em → posun **0**. Geist je vyvážený,
     token proto stojí na nule. Nechává se jako jedno místo pro případ dalšího
     písma. Za Helvetiky Neue LT Pro (714/286/200/714) byl 0,286em —
     text tehdy seděl o 0,143 em výš (nález Ondry na segmentovém filtru).
     Hlídá test/vyska-filtru.test.js. */
  --tx-center: 0em;

  /* ── Typografická škála ──────────────────────────────────── */
  /* 27. 9. 2026 (audit designu jazyk-12, rozhodnutí 9a): přibylo --fs-md 13px —
     nejčastější velikost v appce (hustý text řádků a tabulek), do té doby
     psaná 73× natvrdo, protože ve škále chyběla. A tři display tokeny pro
     velká čísla, která dřív žila jen jako literál (26 / 34 / 72 px).
     Minimum je 11 px (--fs-xs): menší písmo appka nemá, ani u popisků os
     grafu. Mezihodnoty 10,5 / 11,5 / 12,5 px se zaokrouhlily na škálu.
     Mimo :root se font-size píše jen tokenem; stránkové CSS, které ještě
     mají px, jsou na seznamu výjimek v test/vlna5-tokeny.test.js a ten
     seznam smí jen ubývat. */
  --fs-xs:   11px;   /* Labely (uppercase), meta, badges      */
  --fs-sm:   12px;   /* Sekundární meta, tooltips             */
  --fs-md:   13px;   /* Hustý text řádků, tabulek a výpisů    */
  --fs-base: 14px;   /* Body text, formuláře                  */
  --fs-lg:   16px;   /* Podnadpisy (h5)                       */
  --fs-xl:   18px;   /* KPI hodnoty, h4                       */
  --fs-2xl:  20px;   /* Sekční nadpisy                        */
  --fs-num-sm: 26px; /* Menší hlavní číslo (dlaždice, rozpad) */
  --fs-num:    34px; /* Hlavní číslo bloku přehledu           */
  --fs-hero:   72px; /* Jediné hero číslo na plátně           */

  /* ── Škála mezer (27. 9. 2026, jazyk-21, rozhodnutí 9a) ─────
     Mřížka 4/8. Padding, margin a gap se v novém kódu píšou tokenem;
     stávajících ~1 300 hodnot v px se převádí postupně, sekce po sekci,
     jen tam, kde hodnota na mřížku přesně padne (vzhled se nemění). */
  --sp-1:  4px;
  --sp-2:  8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-7: 32px;
  --sp-8: 48px;
  /* Obal obsahu záložky (7. 10. 2026, Ondra: „paddingy ve stránkách a na
     stránkách záložek, které objímají vnitřní obsah, jsou všude konzistentní").
     --pad-view = okraj od kraje plochy k prvnímu boxu, --gap-view = mezera
     mezi boxy pod sebou. Čtou: .pv-wrap, .fin-wrap, .cv-wrap, .c-main,
     .domu-podhled, .tk-wrap, obaly Sales, .kpi-filter-card (Výkazy)
     a časová osa Výkazů. Do té doby 22/20/18/16 px podle stránky.
     --pad-view-x = totéž do stran. Měří se od kraje panelu .pl-3, který je
     od kraje okna o --plane-inset, proto se k okraji přičítá; modul bez
     podnavigace panel nemá a bere čisté --pad-view (níž u .pl-3). Do 13. 10. 2026
     to bylo jedno číslo a box měl od panelu nahoře 22 px, ale vlevo jen 17
     (Ondra: „bude tam 20 px všude"). */
  --pad-view: 20px;
  --pad-view-x: calc(var(--pad-view) + var(--plane-inset));
  --gap-view: 12px;

  /* ── Font weights ───────────────────────────────────────── */
  /* PRAVIDLO (2026-09-13, na přání): Regular a Medium jsou základ, BOLD SMÍ
     BÝT JEN NA TEXTU ≥ 18px (--fs-xl a výš) — sekční nadpisy, KPI hodnoty.
     Do té doby bylo v appce 296 pravidel s váhou ≥ 600, ale jen 16 z nich na
     textu ≥ 18px; zbytek byl Bold na 9–14px (labely, hlavičky tabulek, badge,
     jména v řádcích) a dělal appku hustou místo přehledné. Hierarchie se staví
     velikostí a prostorem, ne tím, že se ztuční všechno malé.
     --fw-semibold (600) je od 13. 9. 2026 zrušený: tehdejší Helvetica Neue LT
     Pro neměla SemiBold řez, takže 600 a 700 kreslily týž Bold soubor. Geist
     SemiBold má, ale pravidlo tří vah platí dál — Bold soubor proto pokrývá
     600–700 (sekce 3) a 600 se na obrazovce dál kreslí jako Bold. Grep před smazáním našel
     11 inline použití v crm.js a spotlight-widget.js — všechna převedena.
     Čte i login.html / login-otp.html, které mají vlastní kopii těchto tří
     tokenů (DS nenačítají) — hodnoty se mění spolu.
     Hlídá test/typografie.test.js. */
  --fw-regular:  400;
  --fw-medium:   500;
  --fw-bold:     700;

  /* ── Line heights ───────────────────────────────────────── */
  /* POZOR: tyhle tři tokeny jsou k 13. 9. 2026 mrtvé — v žádném public/*.css
     nejsou použité ani jednou, zato v CSS žije 12 různých hodnot napsaných
     natvrdo (1, 1.1, 1.2, 1.25, 1.3, 1.35, 1.4, 1.5, 1.55, 1.6, 1.65, 1.7).
     Sjednocení řádkování je samostatný krok, viz docs/design-audit-swiss.md §8. */
  --lh-tight:   1.2;   /* Tlačítka, kompaktní UI  */
  --lh-normal:  1.5;   /* Body text               */
  --lh-relaxed: 1.8;   /* Dlouhé texty, textarea  */

  /* ── Písmo ──────────────────────────────────────────────── */
  /* --ff-mono (2026-09-13): do té doby tři různé monospace stacky na pěti
     místech (ui-monospace… / 'SF Mono','Menlo'… / jen `monospace`). Čte
     .input-secret, .fak-picker-id, .tx-id-badge, .podklad-pre, .bulk-textarea. */
  --ff-mono: 'Geist Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
  /* --ff (14. 9. 2026): stejný důvod jako --ff-mono. Stack byl napsaný natvrdo
     na `body` (sekce 3) a jinde se nepsal vůbec — feedback widget i středový
     text v donutu jezdily na -apple-system, tedy systémovém písmu, ne našem.
     Čte: body, .fw-* (feedback-widget.js), drawDonutSVG a barChart v shared.js
     a projects.js. Kdo píše font-family, bere ho odsud. */
  --ff: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;

  /* ── Velikosti ikon (14. 9. 2026) ───────────────────────── */
  /* Ikony byly do té doby inline SVG s `width`/`height` psanými na místě
     použití — devatenáct různých hodnot (10, 11, 12, 13, 14, 15, 16, 18, 22,
     24…), z toho 64× třináctka. Se sjednocením na Material Symbols (sekce 4)
     je velikost ikony `font-size`, a ten má čtyři kroky podle ROLE, ne podle
     toho, co kdo tehdy napsal:
       xs  chipy, štítky, ikona uvnitř malého tlačítka       (dřív 10–12)
       sm  výchozí — akce v řádku, pole, toolbar             (dřív 13–14)
       md  hlavička sekce, prázdný stav, větší tlačítko      (dřív 15–18)
       lg  navigace                                          (dřív 22)
     Čte je `.ms` a per-komponentní pravidla, která dřív cílila na `svg`
     (.nav-tab, .gs-toolbar .gs-btn, .gs-pop-h, .gs-search…). */
  --ms-xs: 12px;
  --ms-sm: 14px;
  --ms-md: 16px;
  --ms-lg: 22px;
}

/* ── 1. NIGHT — tmavý režim (19. 9. 2026, na zadání) ─────────
   Dvě barevné kombinace: Day (vše výš) a Night (tenhle blok). Přepínač je
   v Nastavení → Účet a umí i „podle systému"; volbu drží prohlížeč
   (`localStorage['airine-tema']`), protože je to vlastnost zařízení, ne účtu —
   tentýž člověk chce na noutbuku v noci něco jiného než na monitoru v kanceláři.
   Atribut `data-tema` na <html> nastavuje inline skript v <head> (`temaScript()`
   v server.js) ještě před prvním vykreslením, takže tmavá stránka nikdy
   neproblikne bíle. Volba „podle systému" se sem nepromítá druhým blokem
   v `@media (prefers-color-scheme: dark)` — skript si systém přečte sám a zapíše
   výsledek. Jeden blok, jedna pravda; navíc `prefers-color-scheme` neumí
   odpovědět na „uživatel chce natvrdo Day na tmavém systému".

   ZADÁNÍ: „opravdu minimalistickou krásnou čistou verzi s málo barvami …
   nejsou tam ani zelené a červené texty". Night je proto o stupeň přísnější
   než Day:

     · **Barva zůstává jen na plochách.** Tečka, pruh, výplň chipu — ano.
       Text ne: `--green-dk`, `--red-dk` i `--amber-dk` (dohromady 67 míst)
       míří na primární text, takže „uhrazeno" a „po splatnosti" se v Night
       liší tečkou a slovem, ne barvou písma. Den to má naopak a je to v pořádku:
       na bílé barevný text funguje, na černé svítí.
     · **Ani jedna nová barva.** Celá paleta Night je `--ink` (barva loga,
       #030305) prosvětlený bílou o jednotky procent — přesně ty hodnoty, které
       vyšly z konceptu ve Figmě (node 5072-904): plocha #0E0F11, hlavní lišta
       #101010, lišta podstránek #131315, ground #030305. Měřeno z vykresleného
       PNG, ne odhadnuto; odchylka míchání je 1–2/255 v kanálu. Paleta appky
       tím nerostla (test/barvy.test.js). Výjimky z návrhu 22. 9. 2026
       (Figma 5154:6567): akční modrá je zesvětlená namícháním, jen
       noční zelená a červená se odvozují z denních přes oklch(from …).
     · **Žebřík rovin se obrací.** V Day leží appka na modré obloze a každá
       rovina je o závoj bílé blíž divákovi — panel obsahu je nejsvětlejší.
       V Night je plátno nejtmavší a světlo přibývá tomu, co na něm LEŽÍ:
       lišty jsou o ždibec světlejší než plátno, karta (`--surface`) taky.
       Proto tu závoje nejsou průhledné, ale plné barvy — rovnice skládání
       z :root by záporný krok (rovina 3 zpátky na ground) neuměla.
     · **Stín nenahradí hranu.** Černý stín na černém podkladu není vidět,
       takže `--sh-box` je v Night vlasová linka světla po obvodu. Modaly si
       hloubku drží tmou pod sebou — tam stín smysl dává, leží nad závojem.
     · **Tisk je vždy Day** (rozhodnutí 13a, night-09). Blok proto platí jen
       pro obrazovku: tiskárna dostane denní sadu, jinak by bílé písmo vyšlo
       na bílý papír. Pravidla tisku jsou v sekci 2. */
@media screen {
:root[data-tema="night"] {
  color-scheme: dark;
  --mix-bg: var(--ink);

  /* Akční modrá je v Night světlá a do azuru — značková #1265FF na inkoustu
     svítí, a modrý text na modrém podkladu (kalendář období) byl nečitelný.
     27. 9. 2026 (rozhodnutí 1b, náhled přehledů v15) Ondra vybral #53ABFB
     místo dřívějšího ≈ #5F90ED (modrá 60 % v bílé a inkoustu, Figma
     5154:6567). Odvozená ze značkové přes oklch — paleta neroste: L 0,722,
     C 0,144, odstín o 13,2° do azuru.
     --blue-txt je modrý TEXT na modrém podkladu (dny v rozsahu kalendáře,
     měsíc v období, badge platby). V Day je to --blue-dk, v Night musí být
     naopak světlejší, jinak je na --blue-lt nečitelný (hlášeno 22. 9. 2026 na
     kalendáři období). ≈ #94BAFF. --blue-dk zůstává hoverem plochy.
     Primární tlačítko drží značkovou modrou: bílé písmo na zesvětlené modré
     by mělo kontrast 3,2 : 1, na #1265FF má 4,9 : 1. Každá plná modrá plocha
     s bílým písmem proto čte --blue-plocha, ne --blue (pristupnost-10). */
  --blue:    oklch(from var(--blue-brand) 0.722 0.144 calc(h - 13.24));   /* ≈ #53ABFB */
  --blue-dk: var(--blue-brand);   /* hover plochy s bílým písmem */
  --blue-txt: oklch(from var(--blue-brand) 0.779 0.110 h);
  --blue-plocha: var(--blue-brand);
  --btn-gradient: linear-gradient(180deg,
    color-mix(in srgb, var(--blue-brand) 96%, var(--white)) 0%,
    color-mix(in srgb, var(--blue-brand) 82%, var(--ink)) 100%);
  /* Zelená a červená jsou v Night tentýž tón, jen světlejší (verze 3).
     Plocha tlačítka zůstává denní (--plocha-*), bílé písmo na ní. */
  --green: oklch(from var(--green-den) 0.761 0.209 h);
  --red:   oklch(from var(--red-den) 0.669 0.215 h);
  --na-green: var(--white);

  /* Text — bílá a dvě šedé, všechny jen z bílé v inkoustu (bez modrošedé).
     27. 9. 2026 (pristupnost-03): --t2 podle návrhu 22. 9. (#606060, bílá
     37 %) mělo na kartě 2,89 : 1 a bylo TMAVŠÍ než --t3 (--gray-6, 3,74).
     Teď žebřík klesá: t1 18 : 1, t2 7,5 : 1, t3 5,5 : 1 na --surface,
     na --bg 6,65 a 4,87. Vědomá odchylka od Figmy, zapsaná v DS §3. */
  --t1: var(--white);
  /* Verze 3 (Ondra): co nejblíž hranici čitelnosti — t2 6,1 : 1 a t3
     4,65 : 1 na kartě. */
  --t2: color-mix(in srgb, var(--white) 58%, var(--ink));   /* ≈ #959596 */
  --t3: color-mix(in srgb, var(--white) 50%, var(--ink));   /* ≈ #818182 */

  /* Navigace a datové plochy (viz :root). */
  --nav-t:      color-mix(in srgb, var(--white) 50%, transparent);
  --subnav-t:   var(--t2);
  --nav-akcent: var(--t1);
  --pruh-plny:  var(--blue);
  --pruh-tlumeny: var(--t1);
  --graf-out: linear-gradient(180deg,
    color-mix(in srgb, var(--blue) 60%, var(--ink)) 0%,
    color-mix(in srgb, var(--blue) 20%, color-mix(in srgb, var(--white) 9.5%, var(--ink))) 100%);
  --graf-teck-out: color-mix(in srgb, var(--blue) 40%, var(--ink));
  --cesta-k: var(--t1);
  --cesta-1: var(--t1);
  --cesta-2: var(--t1);
  /* Třetí stupeň je v Night plocha, ne modrá — nejdál došlá koruna se kreslí
     jako prázdný žlábek. Do 24. 9. 2026 to byl ruční mix bílé 15 % (#29292A),
     tedy vlastní příčka 1,2 ΔE od --bg-3 mimo žebřík, kterou nehlídal žádný test. */
  --cesta-3: var(--bg-3);

  /* Povrchy. Procento = kolik bílé prosvítá inkoustem; vyšší číslo je blíž
     divákovi. Nesahat na ně po jednom — je to jeden žebřík, ne šest hodnot.

     24. 9. 2026 celý žebřík o stupeň výš (zadání Ondry: „tmavý design je moc
     tmavý, boxy mají mít barvu lišty"). --surface bylo 4,5 %, tedy #0E0E10 —
     na 0,3 % totéž co --veil-2 pod ním, takže box na plátně z čistého inkoustu
     nebyl vidět jako samostatná deska. Nová hodnota 7,5 % je přesně --veil-1,
     barva hlavní lišty: jediná příčka v Night, která dělá viditelný skok.
     Ostatní hodnoty musely jít nahoru s ní — kdyby zůstaly, hover (--bg) by
     se propadl pod kartu a hrana (--border) by na světlejší ploše zmizela.
     Odstupy jsou zachované: surface → bg je pořád 4,5 bodu, surface → border
     9,5 (bylo 8,5; kontrast se s rostoucím jasem stlačuje, tak o bod víc).
     Ukázka celého žebříku je ve Figmě na DS · Základ, frame 5270:4.

     27. 9. 2026 (rozhodnutí 1b, náhled přehledů v15) jde jen --surface zpátky
     na 5 %: Ondra chtěl boxy „šedé 5 %" na nezměněném inkoustovém plátně.
     Deska se od plátna neodděluje jasem, ale prstenem --sh-box (bílá 8 %),
     takže problém ze 24. 9. (box splývá s plátnem) se nevrací. Ostatní
     příčky zůstávají — hover a hrana tím od karty jen o kus víc odskočí. */
  --surface:   color-mix(in srgb, var(--white)    5%, var(--ink));  /* karta, modal, pole */
  --bg:        color-mix(in srgb, var(--white)   12%, var(--ink));  /* hover, vystouplá plocha */
  --bg-2:      color-mix(in srgb, var(--white)   10%, var(--ink));
  --bg-3:      color-mix(in srgb, var(--white)   14%, var(--ink));
  --border:    color-mix(in srgb, var(--white)   17%, var(--ink));
  --border-md: color-mix(in srgb, var(--white)   30%, var(--ink));
  /* Hrana ovladače v Night (10a): bílá 45 % v inkoustu — 3,90 na --surface,
     3,45 na --bg, 3,66 na --bg-2, 3,24 na --bg-3; bílý jezdec na ní 4,64. */
  --border-pole: var(--border-md);
  /* Pole v okně je světlejší než tělo okna (--bg-2 = 10 %). Do vlny 3 bralo
     --surface (7,5 %), takže v Night leželo pole TMAVŠÍ než plátno pod ním
     (1,06 : 1, okna-10) — proti pravidlu „světlo přibývá tomu, co leží navrch". */
  --pole-bg:   var(--bg);
  /* Vnořený podklad je v Night pod kartou (barva podnavigace), hlavička
     dostane podložky o stupeň světlejší než lišta (viz :root). */
  --plocha-vnor: var(--veil-2);
  --hd-podlozka: var(--bg);
  --hd-inicialy: var(--bg-3);

  /* Roviny (viz „Vzduch" v :root). Obloha je plný inkoust — v Night nemá co
     prosvítat, a gradient pod černou je stejně jen černá. */
  --sky:      var(--ink);
  /* Od 22. 9. 2026 (Figma 5154:6567) je hlavní lišta nejsvětlejší a
     podnavigace i aktivní záložka o stupeň tmavší — obsah pod nimi je plátno. */
  --veil-1:   color-mix(in srgb, var(--white) 7.5%, var(--ink));   /* hlavní lišta  ≈ #161618 */
  --veil-2:   color-mix(in srgb, var(--white) 4.8%, var(--ink));   /* podnavigace   ≈ #0F0F11 */
  --veil-3:   var(--ink);                                          /* panel obsahu  = plátno */

  /* Obrácená plocha a sklo. */
  --inv-bg:   var(--gray-2);
  --inv-fg:   var(--ink);
  --glass-bg: color-mix(in srgb, var(--white) 6%, transparent);
  --glass-br: color-mix(in srgb, var(--white) 10%, transparent);
  --hover:    color-mix(in srgb, var(--white) 8%, transparent);
  --blue-hover: color-mix(in srgb, var(--blue) 10%, transparent);
  --radek-zare: color-mix(in srgb, var(--blue) 20%, transparent);

  /* Podklady stavů — plocha chipu, pruhu, řádku. Procento je vyšší než v Day
     (7–12 %), protože barva v inkoustu mizí rychleji než v bílé; výsledek je
     v obou režimech stejně silný nádech. */
  --blue-lt:   oklch(from var(--blue-brand) 0.300 0.060 h);
  --green-lt:  oklch(from var(--green-den) 0.270 0.065 h);
  --amber-lt:  oklch(from var(--amber) 0.300 0.060 calc(h - 12.3));
  --red-lt:    oklch(from var(--red-den) 0.271 0.065 h);
  --purple-lt: oklch(from var(--purple) 0.299 0.061 h);

  /* -dk — neutrální, viz zadání výš. Stavový text, který barvu nést MÁ
     (mapa stav → barva), čte role --*-txt (27. 9. 2026, night-04, night-13). */
  --green-dk: var(--t1);
  --amber-dk: var(--t1);
  --red-dk:   var(--t1);
  --green-txt:  var(--green);
  --red-txt:    var(--red);
  --amber-txt:  oklch(from var(--amber) 0.780 0.130 calc(h - 13.8));
  --purple-txt: oklch(from var(--purple) 0.779 0.122 h);

  /* Pořadí v žebříčcích: klesající důraz znamená v Night klesající JAS,
     tedy přesně opačné pořadí šedých než v Day. */
  --rank-gold:   var(--white);
  --rank-silver: var(--gray-4);
  --rank-bronze: var(--gray-6);

  /* Velké modré plochy (hlavička modalu, karta dodavatele) — tytéž zastávky,
     ale ředěné do inkoustu, ne do bílé. */
  --gradient-blue: linear-gradient(135deg,
    color-mix(in srgb, var(--blue) 80%, var(--ink))  0%,
    color-mix(in srgb, var(--blue) 46%, var(--ink)) 55%,
    color-mix(in srgb, var(--blue) 22%, var(--ink)) 100%);
  --gradient-blue-modal: linear-gradient(155deg,
    color-mix(in srgb, var(--blue) 80%, var(--ink))  0%,
    color-mix(in srgb, var(--blue) 52%, var(--ink)) 30%,
    color-mix(in srgb, var(--blue) 32%, var(--ink)) 60%,
    color-mix(in srgb, var(--blue) 16%, var(--ink)) 85%, var(--blue-lt) 100%);

  /* Stíny. Box dostane hranu místo stínu, plovoucí panel stín i hranu.
     Hrana boxu 8 % (do 27. 9. 2026 7 %): na kartě 5 % nese celé oddělení. */
  --sh-box: 0 0 0 1px color-mix(in srgb, var(--white) 8%, transparent);
  --sh:     0 0 0 1px color-mix(in srgb, var(--white) 7%, transparent);
  --sh-md:  0 4px 12px rgba(0,0,0,.5), 0 0 0 1px color-mix(in srgb, var(--white) 8%, transparent);
  --sh-lg:  0 8px 32px rgba(0,0,0,.6), 0 0 0 1px color-mix(in srgb, var(--white) 9%, transparent);
  --btn-shadow: 0 1px 3px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.14);
  /* Závoj pod oknem: .4 na tmavé ploše skoro nečte (Ondra 29. 9. 2026: 60 %). */
  --scrim: rgba(0,0,0,.6);
}
}

/* ── 2. PAPÍR, TISK A VIDITELNOST V REŽIMU ────────────────────────────────
   Do 27. 9. 2026 platilo rozhodnutí 13a „papír dokladu je v Night bílý".
   Ondra ho při schvalování barev (verze 3 náhledu) zrušil: doklad, výkaz
   i náhled faktury jsou v Night tmavé jako zbytek appky. Tisk a PDF pro
   klienta zůstávají vždy Day — Night blok platí jen pro obrazovku.

   .gs-papir proto už nevrací denní tokeny. Označuje list (plocha karty,
   hlavní text), aby šel v tisku a v kódu najít jedním selektorem. */
.gs-papir {
  background: var(--surface);
  color: var(--t1);
}

/* .gs-papir-pdf — obálka exportu do PDF (invoice.js, nabidka.js, report.js).
   html2canvas snímá obrazovku, kde může být Night, ale klient dostane
   doklad vždy denní. Vrací proto lokálně denní hodnoty rolí, které Night
   přepisuje; jsou to kopie `:root` a že se nerozešly, hlídá
   test/vlna2-jadro.test.js. */
.gs-papir-pdf {
  color-scheme: light;
  --mix-bg: var(--white);
  --blue: var(--blue-brand);
  --blue-dk: var(--blue-brand-dk);
  --blue-txt: oklch(from var(--blue-brand) 0.546 0.219 h);
  --blue-plocha: var(--blue);
  --green: var(--green-den);
  --red: var(--red-den);
  --na-green: var(--white);
  --t1: var(--gray-9);
  --t2: var(--gray-7);
  --t3: color-mix(in srgb, var(--gray-6) 70%, var(--gray-7));
  --surface: var(--white);
  --bg: var(--gray-1);
  --bg-2: var(--gray-0);
  --bg-3: color-mix(in srgb, var(--gray-2) 71%, var(--gray-1));
  --border: var(--gray-2);
  --border-md: var(--gray-4);
  --border-pole: color-mix(in srgb, var(--gray-4) 73%, var(--gray-2));
  --pole-bg: var(--surface);
  --plocha-vnor: var(--bg);
  --inv-bg: var(--gray-9);
  --inv-fg: var(--white);
  --hover: color-mix(in srgb, var(--ink) 4%, transparent);
  /* Řádek výpisu pod kurzorem (29. 9. 2026, návrh „Výpis bez výplně", Ondra:
     „u den bude 5 % a noc tedy 10 %"). Modrá jako záře, ale světlejší než
     `--blue-lt`: ta patří vybranému řádku, hover ho nesmí přebít. Vržená záře
     řádku má ve dne polovinu noci — na bílé modrá svítí víc než na tmavé. */
  --blue-hover:  color-mix(in srgb, var(--blue) 5%, transparent);
  --radek-zare:  color-mix(in srgb, var(--blue) 10%, transparent);
  --blue-lt:   oklch(from var(--blue-brand) 0.966 0.016 h);
  --green-lt:  oklch(from var(--green-den) 0.960 0.031 h);
  --amber-lt:  oklch(from var(--amber) 0.966 0.041 h);
  --red-lt:    oklch(from var(--red-den) 0.961 0.018 h);
  --purple-lt: oklch(from var(--purple) 0.964 0.019 h);
  --green-dk:  var(--green-txt);
  --amber-dk:  var(--amber-txt);
  --red-dk:    var(--red-txt);
  --green-txt:  var(--green);
  --red-txt:    var(--red);
  --amber-txt:  oklch(from var(--amber) 0.541 0.132 calc(h - 32.9));
  --purple-txt: oklch(from var(--purple) 0.540 0.209 h);
  --sh-box: 0 0 0 1px color-mix(in srgb, var(--blue) 12%, transparent);
  --sh:    0 2px 8px  rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
  --scrim: rgba(0,0,0,.4);
  background: var(--surface);
  color: var(--t1);
}

/* Viditelnost podle režimu — JEDEN pár pro obrázky i ikony (night-15):
   `.jen-day` je vidět jen ve Day, `.jen-night` jen v Night. Nahradil
   dřívější dva páry, z nichž jeden znamenal v DS „ikona toho, co klik
   udělá" a na přihlášení opak (night-15). */
:root[data-tema="night"] .jen-day:not(.gs-papir-pdf *),
:root:not([data-tema="night"]) .jen-night,
.gs-papir-pdf .jen-night { display: none; }

/* .gs-a4 — list dokladu ve formátu A4 (9. 10. 2026). Ondra: „lidé jsou
   zvyklí mít fakturu jako A4 … všude se musí zobrazovat jako A4 velikost",
   a delší obsah pokračuje na dalším listu. Listy skládá `gsA4Strankuj()`
   v shared.js do obalu `.gs-a4-stoh`; na úzké obrazovce se celý stoh
   zmenší (`zoom`, `gsA4Prizpusob`), obsah se nikdy nepřeskládá. Používá
   faktura (invoice.html) a výkaz (report.html); okraj listu si stránka
   nastaví proměnnou `--a4-okraj`. PDF snímá list po listu (`gsA4Pdf`). */
.gs-a4-stoh { display: flex; flex-direction: column; align-items: center; gap: 16px; }
.gs-a4 {
  position: relative;
  width: 210mm;
  height: 297mm;
  flex: none;
  box-sizing: border-box;
  padding: var(--a4-okraj, 18mm 20mm);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  box-shadow: var(--sh);
  overflow: hidden;
}
.gs-a4-obsah { flex: 1 1 auto; min-height: 0; overflow: hidden; }
.gs-a4-cislo {
  position: absolute;
  right: 0;
  bottom: 7mm;
  left: 0;
  text-align: center;
  font-size: var(--fs-xs);
  color: var(--t3);
}
/* Snímek do PDF: bez stínu a o 2 px nižší, aby list nepřetekl na druhou
   stránku PDF zaokrouhlením (html2pdf počítá výšku stránky dolů). */
.gs-a4.gs-a4--pdf { box-shadow: none; height: calc(297mm - 2px); }

/* Tisk (night-09) je na konci souboru — musí přebít display pruhů obalu. */

/* ── 3. FONTY ────────────────────────────────────────────────
   Geist (Vercel, SIL OFL 1.1, public/fonts/Geist-*.woff2) — od 21. 9. 2026,
   na Ondrovo zadání „všude písmo Geist". Do té doby licencovaná Helvetica Neue
   LT Pro, kterou Figma neuměla načíst, takže knihovna jela na Interu a kód na
   Helvetice. Geist je v Google Fonts, takže Figma i kód mají poprvé stejné
   písmo (docs/figma.md §1).
   Tři řezy: Regular, Medium, Bold. Geist SemiBold existuje, ale appka má tři
   viditelné váhy (pravidlo u --fw-* v :root), proto Bold soubor pokrývá rozsah
   600–700 a SemiBold se sem nenačítá. Tiskové dokumenty (invoice/report)
   design systém nenačítají a SemiBold mají.
   Stejné tři @font-face mají login.html, login-otp.html, registrace.html
   a pozvanka.html (DS nenačítají). Geist Mono jen Regular — nese --ff-mono. */

@font-face {
  font-family: 'Geist';
  src: url('/fonts/Geist-Regular.woff2?v=14771855') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Geist';
  src: url('/fonts/Geist-Medium.woff2?v=15cce75d') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Geist';
  src: url('/fonts/Geist-Bold.woff2?v=e4b58163') format('woff2');
  font-weight: 600 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Geist Mono';
  src: url('/fonts/GeistMono-Regular.woff2?v=de7b4bf1') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ── 4. IKONY — Material Symbols Rounded ─────────────────────
   Zadání 14. 9. 2026: „budeme výhradně používat Google Material Icons —
   Weight 300, Grade −25, Optical size 24." Do té doby byly všechny ikony
   ručně psané inline SVG ve stylu Lucide (201 výskytů, 111 různých kreseb)
   a stejná věc měla napříč moduly různou kresbu — Projekty byly v navigaci
   monitor, ve Spotlightu složka a ve výkazu kufřík.

   Doručení: **subsetovaný font**, ne CDN a ne per-ikonu SVG.
   `public/fonts/MaterialSymbolsRounded.woff2` (18 kB) nese přesně těch 107 jmen,
   která appka používá — ani jedno navíc (hlídá test/ikony.test.js).

   Osy: font je instancovaný na wght 400 / GRAD −25 / opsz 24 a variabilní
   zůstala jediná, FILL (0–1), kterou používá `.ms-fill`. Důvod je velikost:
   plně variabilní subset týchž ikon váží přes 130 kB, protože většinu zabere
   tabulka `gvar` s deformacemi pro všechny kombinace os. Zapečení tří os,
   které stejně držíme na jedné hodnotě, srazilo font na 17 kB (−86 %).
   Cena: změna váhy nebo grade už není řádek v CSS — musí se postavit nový
   subset (`scripts/ikony-subset.sh`, postup v docs/design-system.md §5).

   Stránky ikonu preloadují (`<link rel=preload as=font crossorigin>`), aby se
   font začal stahovat souběžně s CSS, ne až po jeho zpracování. Preload nemá
   login.html (ikonu nemá) ani invoice/report/nabidka.html (DS nenačítají, viz VĚDOMĚ VEN níž).

   Ligatury: font mapuje `a–z` a `_` a nese `rlig` + `rclt` — `<span class="ms">
   expand_more</span>` se proto složí do jednoho glyfu bez `font-feature-
   settings`. Doloženo čtením GSUB ze staženého souboru v test/ikony.test.js.

   Licence Apache 2.0 leží vedle jako `MaterialSymbols-LICENSE.txt`
   (self-hosting a úprava jsou povolené, atribuce v UI se nevyžaduje).

   `font-display: block`, ne `swap`: než se font stáhne, vykreslil by prohlížeč
   jméno ikony jako text („expand_more“ v tlačítku). Blok drží místo prázdné.

   Stejný blok má i login-otp.html (DS nenačítá; login.html ikonu nemá).

   VĚDOMĚ VEN: papír invoice.html, report.html a nabidka.html (tisková
   sazba, která jde do PDF přes html2canvas). Ovladače kolem papíru (lišta,
   boční panel, modaly) jedou od vlny 5 (27. 9. 2026) na Material Symbols
   s vlastní kopií @font-face a .ms — tyhle stránky DS nenačítají.
   Platné znění výjimky: docs/design-system.md §5. */

@font-face {
  font-family: 'Material Symbols Rounded';
  src: url('/fonts/MaterialSymbolsRounded.woff2?v=dd16979c') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: block;
}

/* Ikona. Velikost se řídí `--ms` (viz tokeny --ms-*); komponenta ji smí
   přebít na svém kontejneru, aniž by sahala na call-site.
   Váhu, grade ani optickou velikost tu nenajdeš — jsou zapečené ve fontu
   (viz komentář výš). Variabilní zůstala jediná osa, FILL, kvůli `.ms-fill`. */
.ms {
  font-family: 'Material Symbols Rounded';
  font-variation-settings: 'FILL' 0;
  font-weight: var(--fw-regular);
  font-style: normal;
  font-size: var(--ms, var(--ms-sm));
  width: 1em;
  height: 1em;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
  user-select: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
/* Pojistka. Ikona je od 14. 9. 2026 `<span>`, takže ji nově chytají i pravidla
   psaná na text — `.néco span { text-transform: uppercase }` by z `expand_more`
   udělalo `EXPAND_MORE`, což není jméno žádného glyfu, a v tlačítku by se
   místo ikony objevil ten nápis. Totéž `letter-spacing` (rozpadlá ligatura)
   a `font-family` (jméno vysázené naším písmem). Dvojitá třída dává 0,2,0,
   takže porazí `.x span` i `.x .y` z page CSS, které se načítá později.
   Kdo potřebuje ikonu opravdu přebít, musí to napsat adresně — a tím i vědomě. */
.ms.ms {
  font-family: 'Material Symbols Rounded';
  text-transform: none;
  letter-spacing: normal;
  word-spacing: normal;
  font-style: normal;
}
.ms-xs { --ms: var(--ms-xs); }
.ms-sm { --ms: var(--ms-sm); }
.ms-md { --ms: var(--ms-md); }
.ms-lg { --ms: var(--ms-lg); }
/* Vyplněný řez — dnes jen hvězdička oblíbené nástěnky. */
.ms-fill { font-variation-settings: 'FILL' 1; }
/* Rotace pro průběh (progress_activity). */
.ms-spin { animation: ms-spin 1s linear infinite; }
@keyframes ms-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ms-spin { animation: none; } }

/* ── 5. RESET & BASE ────────────────────────────────────────
   Základní reset a body styly sdílené všemi stránkami. */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* Atribut hidden musí vyhrát i nad vlastním display (flex, inline-flex…) —
   bez toho `el.hidden = true` na .gs-pop-item nebo .gs-chip nic neschová.
   Do 13. 9. 2026 to admin.css a invoice.html řešily každý zvlášť. */
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  font-family: var(--ff);
  font-size: var(--fs-base);
  color: var(--t1);
  background: var(--sky);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* --plane-join drží závoj roviny, která leží pod hlavní navigací — a ta je
   od 26. 9. 2026 na každé stránce rovina 2. Mění se tady, na jednom místě;
   .nav-slider i jeho zuby si hodnotu jen berou.

   Do té doby stránky bez podnavigace (Domů, Časy) přeskakovaly rovnou do
   roviny 3, takže se pod hlavičkou i v aktivní záložce objevila jiná barva
   než všude jinde. Na Časech to nebylo vidět — plochu hned zakryje bílá
   tabulka; na Domů, kde pod kartami zbývá půl obrazovky roviny, to bylo
   první, čeho si Ondra všiml (26. 9. 2026: „když překliknu mezi záložkami,
   barva na pozadí Domů se mění; je jiná než na pozadí ostatních záložek…
   měla by tam být barva, jako je ve druhé vrstvě").

   Záložka se proto spojuje vždycky do roviny 2. Kolik rovin je pod ní, řídí
   struktura modulu, ne tohle místo: rovina 3 je panel podnavigace a existuje
   jen tam, kde podnavigace je (viz .pl-3 níž). */
body[data-page] {
  --plane-join: var(--veil-2);
}

/* ── 6. ROVINY ──────────────────────────────────────────────
   Tři závoje bílé nad oblohou na <body>; teorie viz blok „Roviny aplikace“
   v :root. Elementy do stránky vkládá server (panelsHtml v server.js), aby
   je nemusela mít v šabloně každá stránka zvlášť.

   Záporný z-index je tu podstatný: roviny musí ležet nad pozadím body, ale
   pod veškerým obsahem. Obsah appky je až na navigaci nepozicovaný, a ten se
   kreslí nad zápornou vrstvou, ale pod z-index:0. Kdyby roviny měly 0 a víc,
   překryly by celou stránku. */
.plane {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  pointer-events: none;
}
.pl-1 { top: 0;           background: var(--veil-1); z-index: -3; }
.pl-2 { top: var(--hd-h); background: var(--veil-2); z-index: -2;
        border-radius: var(--r) var(--r) 0 0; }
/* Rovina 3 je panel, na kterém leží obsah **pod podnavigací**. Začíná přesně
   tam, kde podnavigace končí, a odsazení po stranách je ten schod, o který
   sestupuje z roviny 2.

   Je to jediná rovina, která se váže na strukturu modulu, ne na okno: modul
   bez podnavigace nemá třetí příčku, ze které by se sestupovalo, takže jeho
   obsah leží rovnou na rovině 2 (Ondra 26. 9. 2026: „proč nemůže náš obsah
   ležet jenom na té druhé, pokud nemáme nějaké další záložky v tom modulu?").
   Dnes jsou to Domů a Časy.

   Pozor na to, co se tím NEspravuje: rovina 3 nesmí vylézt nahoru pod
   hlavičku. Závoje leží nad **gradientem**, ne nad plochou barvou — tentýž
   závoj je u horní hrany okna výrazně modřejší než o padesát pixelů níž.
   Panel vytažený o 48 px výš proto ležel na tmavším kusu oblohy a Domů
   vypadalo tmavší než Projekty, přestože mělo stejné závoje. `top` má
   rovina 3 jedno jediné, pro všechny stránky stejné. */
.pl-3 {
  top: calc(var(--hd-h) + var(--subnav-h));
  left: var(--plane-inset); right: var(--plane-inset);
  background: var(--veil-3);
  border-radius: var(--r) var(--r) 0 0;
  z-index: -1;
}
body:not(:has(.sub-nav)) .pl-3 { display: none; }
/* Bez panelu leží obsah na rovině 2, která sahá ke kraji okna — viz --pad-view-x. */
body:not(:has(.sub-nav)) { --pad-view-x: var(--pad-view); }

/* ── 7. CHECKBOX ─────────────────────────────────────────── */

.gs-checkbox {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1.5px solid var(--border-md);
  background: var(--surface);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  cursor: pointer;
  transition: box-shadow .15s, border-color .15s, background .15s;
}

.gs-checkbox:hover {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 12%, transparent);
  border-color: var(--blue-lt);
}

.gs-checkbox.checked {
  background: var(--plocha-green);
  border-color: var(--plocha-green);
}

/* Fajfka je maska, ne obrázek: data-URI s pevným stroke přebarvit nejde
   Plocha je --plocha-green (denní sytá) v obou režimech, fajfka bílá. */
.gs-checkbox.checked::after {
  content: '';
  display: block;
  width: 10px;
  height: 10px;
  background: var(--na-green);
  -webkit-mask: url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline points='2 6 5 9 10 3' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline points='2 6 5 9 10 3' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* ── 8. BUTTONS ──────────────────────────────────────────── */

.gs-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border-radius: var(--r-ctrl);
  font-weight: var(--fw-medium);
  font-size: var(--fs-md);
  padding: 7px 16px;
  border: none;
  cursor: pointer;
  transition: opacity .15s, box-shadow .15s, transform .1s;
  white-space: nowrap;
  font-family: inherit;
  line-height: 1.2;
}

.gs-btn:active {
  transform: scale(0.97);
}

/* `aria-busy` nastavuje gsUkladani() v shared.js během ukládání (okna-04). */
.gs-btn:is(:disabled, [aria-busy="true"]) {
  opacity: .45;
  cursor: default;
  pointer-events: none;
}

/* Varianty (primary, success, danger, ghost, secondary) tu nemají pozadí,
   okraj ani hover: tělo i odezvu na kurzor kreslí záře v sekci 14, u všech
   stejně (Ondra 29. 9. 2026: „vždy ty s tím gradient hover efektem"). */

.gs-btn-sm {
  padding: 5px 12px;
  font-size: var(--fs-sm);
  border-radius: var(--r-ctrl);
}

/* Jen ikona — čtverec o výšce ovladače, tvar drží `--r-ctrl`, takže z něj je
   kolečko. Pro akce, které glyf popíše beze zbytku (smazat, duplikovat)
   v patičce okna, kde text soutěží s hlavním tlačítkem. Význam nese `title`
   a `aria-label` ze slovníku (§18.1) — bez nich je tlačítko pro čtečku němé.
   (Ondra 23. 9. 2026 nad patičkou okna výkazu: „smazat a duplikovat bude jen
   ikona vždy.") Čte: times.html, tickety.html, crm.html — patičky .modal-ft. */
.gs-btn-ico {
  padding: 0;
  gap: 0;
  width: var(--h-ctrl);
  height: var(--h-ctrl);
  justify-content: center;
  flex-shrink: 0;
}

/* ── 9. REC DOT ──────────────────────────────────────────── */
/* Do vlny 3 tu byla rodina .gs-badge (.gs-badge-linkedin, -email … -running).
   V integraci vlny 3 (27. 9. 2026, rozhodnutí 2a) se smazala: stav i označení
   kreslí jen .gs-chip s variantou (sekce 52, gsChip() v shared.js). Zůstává
   pulzující tečka běžících stopek — není to štítek stavu záznamu. */
@keyframes rec-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--red) 50%, transparent); }
  70%  { box-shadow: 0 0 0 6px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.rec-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--red);
  display: inline-block; flex-shrink: 0; animation: rec-pulse 1.6s infinite;
}

/* ── 10. GLASS CARD — zrušena 30. 9. 2026 (jazyk-15) ─────────
   .gs-glass (průhledná karta s rozostřením a stínem natvrdo) nesla jen kroky
   playbooku v Sales. Sklo na neprůhledném plátně nemá co rozostřit, v Night
   dávalo mléčnou skvrnu. Kroky jsou dnes karta jako .stat-card (crm.css
   .pw-step-card). Tokeny --glass-bg/--glass-br zůstávají pro zavírací kolečko
   na modrém gradientu (finance.css .vd-det-close). Číslo sekce zůstává. */

/* ── 11. TYPOGRAPHY ───────────────────────────────────────── */

.gs-label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--t3);
}

.gs-section-title {
  font-size: var(--fs-2xl);
  font-weight: var(--fw-bold);
  color: var(--t1);
  letter-spacing: -0.01em;
}

.gs-h4 { font-size: var(--fs-xl); font-weight: var(--fw-bold); color: var(--t1); line-height: 1.3; }
.gs-h5 { font-size: var(--fs-lg); font-weight: var(--fw-medium); color: var(--t1); line-height: 1.3; }
.gs-h6 { font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--t1); line-height: 1.4; }
.gs-body    { font-size: var(--fs-base); font-weight: var(--fw-regular); color: var(--t1); line-height: 1.5; }
.gs-body-sm { font-size: var(--fs-md); font-weight: var(--fw-regular); color: var(--t2); line-height: 1.5; }
.gs-body-xs { font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--t3); line-height: 1.4; }

/* ── 12. BUTTON SIZES ─────────────────────────────────────── */

.gs-btn-lg {
  padding: 10px 24px;
  font-size: 15px;
}

.gs-btn-md {
  padding: 8px 16px;
  font-size: var(--fs-base);
}

/* ── 13. BUTTON SECONDARY ─────────────────────────────────── */
/* `.gs-btn-secondary` je od 29. 9. 2026 celé v sekci 14 (tělo i hover). */

/* ── 14. ZÁŘE OKRAJE ZA KURZOREM ─────────────────────────── */

/* Každé tlačítko v appce svítí okrajem za kurzorem, stejně jako na webu
   (`Web/web.css` §1a, třídy `.wb-*`). Web zůstává zdrojem pravdy pro vzhled,
   tady je appková podoba; kdo mění jedno, ať se podívá na druhé.

   ── KDE SVÍTÍ ─────────────────────────────────────────────────────────────
   24. 9. 2026 to byl modifikátor `.gs-btn-zare` a patička okna. 29. 9. 2026
   (Ondra: „vždy ty s tím gradient hover efektem") je to výchozí stav:

   - každá varianta `.gs-btn` — primary, secondary, ghost, success, danger;
     primární tělo je `--btn-gradient` (Ondra: „nechat modré"),
   - ikonové tlačítko `.ico-btn` — bez plochy, jen okraj u kurzoru v barvě
     akce: `.del` červeně, ostatní modře („budou mít vlastní záři podle barvy
     tlačítka").

   Bez záře zůstávají ovladače, které tlačítkem nejsou: segmenty
   (`.gs-seg-btn`, `.gs-sw-btn`), řazení (`.gs-sort-btn`) a čip hodnoty
   (`.gs-btn-cip`, nemá variantu). Tam se přepíná nebo vybírá, nepotvrzuje.

   ── JAK ───────────────────────────────────────────────────────────────────
   `--gx` / `--gy` je poloha kurzoru v px od levého horního rohu tlačítka,
   nastavuje ji jeden posluchač v `public/akce.js` (inline `style` ani
   `<script>` by neprošel CSP, §14.10). Seznam selektorů má appka na dvou
   místech — tady a jako `ZARE_SEL` v `akce.js`; že jsou stejné, hlídá
   `test/zare-selektory.test.js`.

   Tlačítko samo nemá pozadí, kreslí ho dvě vrstvy pod textem:
     ::before  tělo: plocha (--gb-plocha) a okraj (--gb-okraj); na okraji
               u kurzoru ostře svítí --gb-linka,
     ::after   rozmazaná záře, maskou oříznutá na prstenec kolem linky —
               svítí jen okraj u kurzoru, žádná koule.
   `isolation: isolate` drží obě vrstvy pod textem a nad pozadím stránky.

   Okraj nekreslí `border`, ale `padding: 1px` v ::before (border prohlížeč
   zaokrouhluje na celé pixely). Všechny varianty jsou proto stejně vysoké.

   Selektor je `:is(…)` se specificitou jedné třídy (0,1,0), jako varianta
   sama. Varianty v sekci 8 a 13 si proto pozadí ani hover nedefinují — nebylo
   by co přebíjet. */

@property --gb-l { syntax: '<color>'; inherits: false; initial-value: transparent; }

:is(.gs-btn-primary, .gs-btn-secondary, .gs-btn-ghost, .gs-btn-success, .gs-btn-danger, .gs-vyber-btn, .gs-vyber-zavri, .ico-btn) {
  --gx: 50%;
  --gy: 50%;
  --gb-plocha: none;        /* výplň těla (obrázek: přechod) */
  --gb-okraj: none;         /* okraj těla (obrázek: přechod) */
  --gb-linka: transparent;  /* okraj u kurzoru a jádro záře */
  --gb-zare: transparent;   /* měkká záře v lince */
  position: relative;
  isolation: isolate;
  border: 0;
  background: none;
  box-shadow: none;
}

:is(.gs-btn-primary, .gs-btn-secondary, .gs-btn-ghost, .gs-btn-success, .gs-btn-danger, .gs-vyber-btn, .gs-vyber-zavri, .ico-btn)::before,
:is(.gs-btn-primary, .gs-btn-secondary, .gs-btn-ghost, .gs-btn-success, .gs-btn-danger, .gs-vyber-btn, .gs-vyber-zavri, .ico-btn)::after {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
}

/* Plocha je content-box, linka zbytek do padding-boxu. Střed drží plnou barvu
   kolem kurzoru (12 px), teprve pak slábne.
   `--gb-l` se mění přímo na pseudoprvku, ne děděním z tlačítka: Safari
   animovanou zděděnou proměnnou po skončení přechodu zahodí a linka zmizí. */
:is(.gs-btn-primary, .gs-btn-secondary, .gs-btn-ghost, .gs-btn-success, .gs-btn-danger, .gs-vyber-btn, .gs-vyber-zavri, .ico-btn)::before {
  --gb-l: transparent;
  padding: 1px;
  transition: --gb-l .25s;
  background:
    var(--gb-plocha) content-box,
    radial-gradient(circle 53px at var(--gx) var(--gy), var(--gb-l) 0 12px, transparent) padding-box,
    var(--gb-okraj) padding-box;
}

/* Pruh 2 px = 0,5 px ven + linka 1 px + 0,5 px dovnitř. Jádro drží plnou barvu
   prvních 5 px, pak přes širší záři do ztracena. */
:is(.gs-btn-primary, .gs-btn-secondary, .gs-btn-ghost, .gs-btn-success, .gs-btn-danger, .gs-vyber-btn, .gs-vyber-zavri, .ico-btn)::after {
  inset: -.5px;
  padding: 2px;
  filter: blur(3px);
  opacity: 0;
  transition: opacity .25s;
  -webkit-mask: linear-gradient(black 0 0) content-box, linear-gradient(black 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0);
  background:
    radial-gradient(circle 17px at var(--gx) var(--gy), var(--gb-linka) 0 5px, transparent),
    radial-gradient(circle 43px at var(--gx) var(--gy), var(--gb-zare) 0 10px, transparent);
}

:is(.gs-btn-primary, .gs-btn-secondary, .gs-btn-ghost, .gs-btn-success, .gs-btn-danger, .gs-vyber-btn, .gs-vyber-zavri, .ico-btn):hover::before { --gb-l: var(--gb-linka); }

:is(.gs-btn-primary, .gs-btn-secondary, .gs-btn-ghost, .gs-btn-success, .gs-btn-danger, .gs-vyber-btn, .gs-vyber-zavri, .ico-btn):hover::after { opacity: 1; }

/* Plné barvy: linka je bílá, protože barva plochy by na sobě samé zanikla.
   Primární tělo je `--btn-gradient` (dřív ho měla jen patička okna, jinde
   plochá `--blue-plocha`); okraj je o stupeň světlejší nahoře jako gradient. */
.gs-btn-primary {
  --gb-plocha: var(--btn-gradient);
  --gb-okraj: linear-gradient(color-mix(in srgb, var(--blue-brand) 70%, var(--white)), var(--blue-dk));
  --gb-linka: var(--white);
  --gb-zare: color-mix(in srgb, var(--blue) 70%, var(--white));
  color: var(--white);
}

.gs-btn-success {
  --gb-plocha: var(--btn-gradient-green);
  --gb-okraj: linear-gradient(color-mix(in srgb, var(--plocha-green) 70%, var(--white)), color-mix(in srgb, var(--plocha-green) 80%, var(--ink)));
  --gb-linka: var(--white);
  --gb-zare: color-mix(in srgb, var(--plocha-green) 70%, var(--white));
  color: var(--white);
}

.gs-btn-danger {
  --gb-plocha: linear-gradient(var(--plocha-red), var(--plocha-red));
  --gb-okraj: linear-gradient(var(--plocha-red), var(--plocha-red));
  --gb-linka: var(--white);
  --gb-zare: color-mix(in srgb, var(--plocha-red) 70%, var(--white));
  color: var(--white);
}

/* Světlé: plocha `--surface`, linka modrá. V Night se oba tokeny prohodí samy,
   varianta si nic vlastního nedefinuje. */
.gs-btn-secondary {
  --gb-plocha: linear-gradient(var(--surface), var(--surface));
  --gb-okraj: linear-gradient(var(--border-md), var(--border-md));
  --gb-linka: var(--blue);
  --gb-zare: color-mix(in srgb, var(--blue) 55%, transparent);
  color: var(--t1);
}

/* Průsvitné: okraj v ::before leží pod celou plochou a u průhledného tlačítka
   by prosvítal. Proto se ::before maskuje na prstenec stejně jako ::after.
   Ikonové tlačítko je totéž bez klidového okraje — v řádku tabulky by dvacet
   rámečků pod sebou bylo šum, rozsvítí se jen to, na kterém je kurzor. */
.gs-btn-ghost {
  --gb-okraj: linear-gradient(var(--border), var(--border));
  --gb-linka: var(--blue);
  --gb-zare: color-mix(in srgb, var(--blue) 55%, transparent);
  color: var(--t1);
}

.ico-btn {
  --gb-linka: var(--blue);
  --gb-zare: color-mix(in srgb, var(--blue) 55%, transparent);
}

.ico-btn.del {
  --gb-linka: var(--red);
  --gb-zare: color-mix(in srgb, var(--red) 55%, transparent);
}

:is(.gs-btn-ghost, .gs-vyber-zavri, .ico-btn)::before {
  -webkit-mask: linear-gradient(black 0 0) content-box, linear-gradient(black 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0);
}

/* ── 15. SECTION BOX ──────────────────────────────────────── */

/* Box neleží nikdy na šedém plátně stránky, ale na bílé ploše okna nebo
   detailu (.modal i .vd-detail jsou var(--surface)) — sklo se tedy nemělo
   o co opřít: bílá na bílé. A protože pole ve formuláři jsou taky
   var(--surface), zmizela spolu s ním. Proto má box vlastní podklad
   var(--bg) a plnou linku; pole nad ním zase vystoupí.
   (Ondra 23. 9. 2026 nad oknem leadu: „Nejsou tu vůbec vidět ty jednotlivé
   boxy. Ten field tak nemá žádné pozadí ani žádný border.")
   Čte Sales (crm.html) i Finance (finance.html → .vd-box). */
.gs-section-box {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 16px;
  margin-bottom: 12px;
}

.gs-section-box-title {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--t3);
  margin-bottom: 12px;
}

/* ── 16. SEARCH BUTTON — .gs-btn-search zrušen 22. 9. 2026: žádná stránka ho
   nepoužívala (hledání je .gs-search, sekce 31). Číslo sekce zůstává. ───── */

/* ── 17. SORT BUTTON ─────────────────────────────────── */

.gs-sort-btn {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  cursor: pointer;
  color: inherit;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  transition: color .15s;
  user-select: none;
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
  text-transform: inherit;
}

.gs-sort-btn:hover {
  color: var(--t1);
}

.gs-sort-btn .gs-sort-arrow {
  font-size: var(--fs-xs);
  opacity: .6;
  flex-shrink: 0;
}

/* Znak řazení je glyf z ikonového fontu (sekce 4), ne typografická šipka —
   ta se kreslí systémovým písmem a v paletě ani v optické váze nesedí. */
.gs-sort-btn .gs-sort-arrow::after {
  content: 'unfold_more';
  font-family: 'Material Symbols Rounded';
  font-variation-settings: 'FILL' 0;
  font-size: var(--ms-sm);
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
}
/* Aktivní směr má být glyf z téže sady jako `unfold_more` výš. Do 15. 9. 2026 to
   byly znaky ↑ a ↓ — tedy typografická náhražka ikony (§13.2), navíc kreslená
   systémovým písmem, protože je subset nenese. */
.gs-sort-btn.asc  .gs-sort-arrow::after { content: 'arrow_upward';   opacity: 1; }
.gs-sort-btn.desc .gs-sort-arrow::after { content: 'arrow_downward'; opacity: 1; }

/* ── 18. DASHBOARD CARD ──────────────────────────────────── */
/* Základní box pro dashboard sekci (chart, tabulka, přehled) */

.dash-card {
  background: var(--surface);
  padding: 16px 16px;
  overflow: visible;
}

.dash-card-title {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--t3);
  margin-bottom: 16px;
}

/* ── 19. DASHBOARD LAYOUT GRIDS ──────────────────────────── */

/* 2 sloupce: hlavní obsah + boční panel */
.dash-grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: 12px;
}

/* 2 sloupce s postranním panelem pohledávek */
.dash-charts-recv {
  display: grid;
  grid-template-columns: 1fr 300px;
  gap: 12px;
  align-items: start;
}

/* Svislý stack karet */
.dash-charts-col {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* ── 20. CHART TOOLTIP ───────────────────────────────────── */

.chart-tooltip {
  position: fixed;
  background: var(--inv-bg);
  color: var(--inv-fg);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  padding: 8px 12px;
  border-radius: var(--r-sm);
  pointer-events: none;
  z-index: var(--z-toast);
  display: none;
  line-height: 1.6;
  white-space: nowrap;
  box-shadow: var(--sh-md);
}

/* ── 21. DONUT CHART ─────────────────────────────────────── */
/* Wrapper: canvas vlevo, legenda vpravo */

.ds-donut-wrap {
  display: flex;
  align-items: center;
  gap: 16px;
}

.ds-donut-wrap canvas {
  flex-shrink: 0;
}

/* Legenda vedle chartu */
.ds-legend {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  min-width: 0;
}

/* Jeden řádek legendy: tečka + label + hodnota */
.ds-legend-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.ds-legend-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

.ds-legend-label {
  font-size: var(--fs-sm);
  color: var(--t2);
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ds-legend-val {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--t1);
  flex-shrink: 0;
}

/* ── 22. DASHBOARD PANEL ─────────────────────────────────── */
/* Větší obal pro celou dashboard sekci s nadpisem a dělítkem */

.dash-panel {
  background: var(--surface);
  padding: 16px 20px;
}

.dash-panel-title {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--t3);
  margin-bottom: 16px;
}

.dash-panel-subtitle {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--t2);
  margin-bottom: 12px;
}

/* Svislé dělítko mezi sekcemi uvnitř panelu */
.dash-vdivider {
  width: 1px;
  background: var(--border);
  flex-shrink: 0;
  align-self: stretch;
}

/* Součtový řádek pod chartem */
.dash-total-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 8px;
  margin-top: 12px;
  border-top: 1px solid var(--border);
}

.dash-total-label {
  font-size: var(--fs-sm);
  color: var(--t3);
}

.dash-total-val {
  font-size: 15px;
  font-weight: var(--fw-medium);
  color: var(--t1);
}

/* ── 23. DASH ITEM LIST ──────────────────────────────────── */
/* Zkrácený výpis položek pod chartem */

.dash-item-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  border-top: 1px solid var(--border);
}

.dash-item-row:first-child {
  border-top: none;
}

/* …a totéž, když řádkům předchází pruh KPI karet (karta Výkon u klienta,
   23. 9. 2026). `:first-child` tam neplatí, protože prvním dítětem je
   `.stat-row` — linka pak visela nad prvním popiskem bez čeho oddělovat. */
.stat-row + .dash-item-row {
  border-top: none;
}

.dash-item-name {
  font-size: var(--fs-sm);
  color: var(--t2);
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dash-item-val {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--t1);
  flex-shrink: 0;
}

/* ── 23b. ŘÁDEK V BOXU — datum · text · štítky ────────────────────────────
   Vytaženo 29. 9. 2026 z `crm.css` (`.akt-card`), kde to od začátku kreslilo
   frontu připomínek. Důvod k přesunu: log komunikace (migrace 116) visí na
   leadu, kontaktu i projektu, takže týž řádek potřebují tři stránky — a §13.4
   říká, že sdílená komponenta patří sem, ne do třetí kopie.

   `.dash-item-row` (sekce 23) je na dvojici název → hodnota. Tenhle řádek má
   tři sloupce: datum vlevo v pevné šířce (data pod sebou pak lícují), text
   uprostřed a štítky vpravo.

   HOVER SI NEKRESLÍ. Přidá se `.gs-radek-zare` (sekce 42) a řádek dostane
   týž hover a záři jako řádek tabulky. `.akt-card` měla do téhle změny
   vlastní recept (`--blue-lt` + dva `inset` stíny), což byla druhá
   implementace téhož a s `--blue-hover` z 29. 9. 2026 se rozešla.

   Rámeček nemá schválně: stojí uvnitř bílého boxu, a rámeček kolem každé
   položky v orámovaném boxu je druhý rámeček v druhém rámečku. */
.gs-radek {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 8px;
  border-radius: var(--r-sm);
}

/* Hotovo / vyřízeno: zůstává vidět, ale ustoupí. Stav, ne skrytí. */
.gs-radek.hotovo { opacity: .45; }

/* Datum má pevnou šířku, aby řádky pod sebou lícovaly i s „12.10." vedle
   „1.9.". Barva nese blízkost termínu (mapa stav → barva, vlna 3, 2a). */
.gs-radek-datum {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--t3);
  white-space: nowrap;
  width: 50px;
  flex-shrink: 0;
}
.gs-radek-datum.po-terminu { color: var(--red-txt); }
.gs-radek-datum.dnes       { color: var(--amber-txt); }

.gs-radek-telo { flex: 1; min-width: 0; }

.gs-radek-nazev {
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  color: var(--t1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Doplněk v názvu (firma u jména, kanál u zprávy) — tišší a menší.
   Druhý `span` za názvem; název sám je první `span` (viz .gs-s-doplnkem). */
.gs-radek-nazev > span + span {
  font-weight: var(--fw-regular);
  color: var(--t2);
  margin-left: 4px;
  font-size: var(--fs-sm);
}

/* Název s doplňkem na jednom řádku (9. 10. 2026, Ondra: „proč tady ty 3 tečky
   jsou jiným písmem"). Trojtečku kreslí prvek s `text-overflow`, a to svou
   barvou a velikostí. Když se ořízl šedý menší doplněk („Lead · Firma"),
   končil velkou tučnou černou „…". Proto je řádek flex a každá část se ořízne
   sama. Název je první `span`, doplněk druhý. Ustupuje doplněk: název se
   nesmršťuje (jinak by se při ořezu doplňku zmenšil o zlomek pixelu a dostal
   trojtečku i krátký), jen má strop, aby doplňku nechal `4em`. Holý text
   jako položka flexu trojtečku neumí, proto i název musí být ve `span`.
   Čte crm.js (leady) a projects.js (žebříčky v KPI). */
.gs-s-doplnkem { display: flex; align-items: baseline; min-width: 0; }
.gs-s-doplnkem > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gs-s-doplnkem > :first-child:not(:last-child) { flex-shrink: 0; max-width: calc(100% - 4em); }

.gs-radek-popis {
  font-size: var(--fs-xs);
  color: var(--t2);
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Poznámka z logu komunikace se nezkracuje na jeden řádek: je to obsah
   zákazníka, ne popisek, a useknutá věta v půlce je k ničemu. */
.gs-radek-popis.cely {
  white-space: pre-wrap;
  overflow: visible;
  word-break: break-word;
}

.gs-radek-vpravo { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

/* ── Štítek DRUHU (ne stavu) ──────────────────────────────────────────────
   `.gs-chip` je na stav: hotovo / čeká / problém. Tohle je druh — kanál
   komunikace, typ aktivity, kategorie. Barva tu neznamená „dobře / zle",
   jen odlišuje skupiny, proto vlastní štítek (rozhodnutí 2a, vlna 3; hlídač
   starých štítků v test/vlna3-integrace.test.js ho proto nehlásí).

   Varianty se jmenují po barvě, ne po významu: význam přiřazuje stránka
   (Sales: psané modře, mluvené fialově, e-mail ambrově, osobní zeleně).
   Kdyby se jmenovaly `linkedin` nebo `schuzka`, byl by v design systému
   slovník jedné stránky. */
.gs-druh {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  padding: 2px 8px;
  border-radius: var(--r);
  white-space: nowrap;
}
.gs-druh-modra   { background: var(--blue-lt);   color: var(--blue-txt); }
.gs-druh-ambra   { background: var(--amber-lt);  color: var(--amber-txt); }
.gs-druh-fialova { background: var(--purple-lt); color: var(--purple-txt); }
.gs-druh-zelena  { background: var(--green-lt);  color: var(--green-txt); }
.gs-druh-seda    { background: var(--bg);        color: var(--t3); }

/* ── 24. FORM GROUP ──────────────────────────────────────────
   Základní form field: label nahoře, input dole.
   Používá se v modálech a formulářích napříč celou appkou. */

.fg {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.fg label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--t2);
}

/* Chybový stav pole (vlna 3, rozhodnutí 6a). Pole dostane červenou hranu,
   pod ním stojí věta, co je špatně. Nastavuje a ruší `gsChybaPole()` /
   `gsChybaPoleZrus()` v shared.js — ručně se třída nepřidává, jinak by
   chybělo `aria-invalid` a provázání textu (`aria-describedby`). Varianta
   pro pole v okně (bílá karta na plátně) je v sekci 25. */
.fg.chyba > [aria-invalid="true"]:is(input, select, textarea),
.fg.chyba > .gs-field-unit > [aria-invalid="true"]:is(input) { border-color: var(--red); }
.fg-chyba { font-size: var(--fs-sm); line-height: 1.4; color: var(--red-txt); }

/* ── 25. MODAL ───────────────────────────────────────────────
   Sdílený modál: overlay + box + hlavička + tělo + patička.
   Velikosti: .modal (700) · .modal-sm (520) · .modal-lg (860) — do 12. 9. 2026
   deset různých inline max-width; Sales měl vlastní shell (.modal-head/-foot),
   od 12. 9. 2026 také tento. Figma: Modal Shell, Size=sm/md/lg (docs/figma.md §4).
   Patička: .gs-btn-ghost + .gs-btn-primary (rozhodnutí D2, audit 12. 9.);
   ničivá akce (Smazat) stojí vlevo — .modal-ft .gs-btn-danger. */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: var(--scrim);
  z-index: var(--z-modal);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.modal-overlay.open { display: flex; }

.modal {
  background: var(--surface);
  border-radius: var(--r-lg);
  width: 100%;
  max-width: 700px;
  box-shadow: var(--sh-lg);
  display: flex;
  flex-direction: column;
  max-height: 90vh;
}
.modal.modal-sm { max-width: 520px; }
/* Mezi sm a výchozím: okno s časovou osou (Výkazy). Na 520 px se pravítko dne
   mačkalo a dlaždice od–do stály na sobě (Ondra 23. 9. 2026: „o 15 % širší"). */
.modal.modal-md { max-width: 600px; }
.modal.modal-lg { max-width: 860px; }
/* Nejužší okno: krátký seznam bez formuláře (přehled zkratek, 9. 10. 2026). */
.modal.modal-xs { max-width: 400px; }

/* Okno dokladu: faktura (Finance) a výkaz práce (Výkazy, Projekty) v okně
   místo nové záložky — obsah je iframe na /invoice nebo /report, žádná druhá
   sazba ani druhý PDF export. Do 27. 9. 2026 `.iv-panel*` ve finance.css; od
   výkazu v okně (`public/vykaz-okno.js`) to chtějí tři stránky, tak patří sem
   (CLAUDE.md §13.4). Papír uvnitř zůstává bílý i v Night (`.gs-papir` na
   iframe). Stojí za `.modal`, aby přebil jeho max-width a max-height. */
.gs-doklad-okno { max-width: min(980px, 94vw); height: 88vh; max-height: 88vh; overflow: hidden; }
.gs-doklad-okno-hd { display: flex; align-items: center; justify-content: space-between; padding: 16px 16px; border-bottom: 1px solid var(--border); background: var(--surface); flex-shrink: 0; }
.gs-doklad-okno-title { font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--t1); }
.gs-doklad-okno-body { flex: 1; overflow: hidden; background: var(--bg); }
.gs-doklad-okno-body iframe { width: 100%; height: 100%; border: none; display: block; background: var(--papir); }

/* Varianta bento (Ondra 8. 10. 2026): „dva moduly jako máme nastavení, vlevo
   nastavení reportu a vpravo širší modul s reportem … cca 70 % a 30 %
   a mezi nimi spacing jako je v nastavení u modulů". Okno samo je
   průhledné, bez hlavičky; obě karty kreslí stránka v iframu (report.html
   ve třídě `.rp-v-okne`) — jinak by nastavení a výkaz nešly rozdělit, jsou
   v jednom dokumentu. Křížek visí v rohu pravé karty jako v Nastavení.
   `--doklad-okraj` je okraj těla v iframu (místo pro stín karet); stránka
   uvnitř ho má stejný, číslo se musí měnit na obou místech. Čte
   vykaz-okno.js a okno faktury ve finance.html. */
/* Šířka 1248 px (12. 10. 2026, Ondra: okraj kolem faktury „moc široký
   zbytečně"): 2×16 okraj + levá karta 30 % + mezera 12 + karta listu
   (A4 794 px + 2×24 okraj + rámeček). Užší okno zmenší list (gsA4Prizpusob). */
.gs-doklad-okno--bento { --doklad-okraj: 16px; max-width: min(1248px, 96vw); height: 92vh; max-height: 92vh; background: transparent; box-shadow: none; position: relative; }
.gs-doklad-okno--bento .gs-doklad-okno-body { background: transparent; }
.gs-doklad-okno--bento .gs-doklad-okno-body iframe { background: transparent; }
.gs-doklad-okno--bento > .modal-close { position: absolute; top: calc(var(--doklad-okraj) + 14px); right: calc(var(--doklad-okraj) + 14px); z-index: 1; }
/* Stránka pod oknem se rozostří (Ondra 12. 10. 2026: „nějaký box ještě za tou levou
   a pravou stranou"). Rám bento je průhledný, takže mezi kartami a nad nimi
   prosvítaly hrany boxů stránky a četly se jako třetí karta za oknem. */
.modal-overlay:has(> .gs-doklad-okno--bento) { backdrop-filter: blur(12px); }

.modal-hd {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 24px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.modal-title { font-size: var(--fs-lg); font-weight: var(--fw-medium); }

/* Zavírací tlačítko každého okna v appce — jedno pravidlo, ne šest kopií.
   Od 23. 9. 2026 je to plné kolečko (návrh „Čas ve výkazu", schváleno „všude"):
   do té doby bylo průhledné a podklad naskočil až pod myší, takže se křížek
   na bílé hlavičce hledal. Selektor je seznam schválně: `.smm-close`,
   `.vd-det-close` a `.fak-picker-close` měly vlastní definice ve `finance.css`
   a rozcházely se (20 px vs. 22 px vs. 28 px); první a poslední jsou od
   vzory-10 (1. 10. 2026) rovnou `.modal-close`. Nové okno napíše `.modal-close`
   a kolečko dostane samo; kdo přidá další jméno, přidá ho sem, ne do stránky
   (§13.2 — rodina tříd se neopisuje). */
.modal-close,
.settings-modal-close,
.kpi-modal-close,
.vd-det-close {
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  background: var(--bg);
  cursor: pointer;
  border-radius: var(--r-ctrl);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--t3);
  transition: background .15s, color .15s;
  font-size: var(--fs-xl);
  line-height: 1;
  flex-shrink: 0;
}
.modal-close:hover,
.settings-modal-close:hover,
.kpi-modal-close:hover,
.vd-det-close:hover { background: var(--hover); color: var(--t1); }

.modal-body {
  padding: 20px 24px;
  overflow-y: auto;
  /* Doroluješ-li tělo modalu na konec, kolečko dál nepřetéká na stránku pod ním
     (17. 9. 2026 — po převodu posledních panelů na okna; bez tohohle se za oknem
     nepozorovaně posunul seznam a po zavření jsi byl jinde, než kde jsi začal). */
  overscroll-behavior: contain;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Tělo modalu = šedé plátno, pole = bílé karty. Vzhled „Nový záznam" (Times,
   Figma 4831:748) rozšířený na VŠECHNY modály — rozhodnutí D3(a) + D6, 13. 9. 2026
   (docs/design-audit-filtry-modaly.md). Do té doby jen #te-new-modal-overlay
   v times.css s vlastními hexy --nm-grey-*; ty jsou namapované na tokeny (D5):
   plátno --bg-2, labely/placeholder --t3, separátory --border, tmavý label --t2.
   Bez Britti Sans (D4) — DS font.
   Karta = jen PŘÍMÉ pole ve .fg (`.fg > input`) a pole s jednotkou. Husté řádky
   položek (.pi-row, .tx-item-row), vnořené speciály (.gs-hero-num, .gs-date-pill,
   type=time) a checkboxy zůstávají, jak jsou. Čte: každý .modal-body
   v public/*.html, Figma Modal Shell (docs/figma.md §4), test/design-modaly.test.js. */
.modal-body { background: var(--bg-2); }
/* Night (Ondra 8. 10. 2026, plátno „Report hodin"): tělo je černé jako hlavička
   a patička, takže okno je jedna plocha. Šedé jsou až boxy a pole v něm —
   řádek s přepínačem a segment by jinak na `--surface` zmizely. Pole mají
   `--pole-bg` (= `--bg`), `.gs-section-box` má `--bg` sám. */
:root[data-tema="night"] .modal-body { background: var(--surface); }
:root[data-tema="night"] .modal-body .gs-toggle-row { background: var(--bg-2); }
:root[data-tema="night"] .modal-body .gs-seg { background: var(--bg-2); border-color: transparent; }
:root[data-tema="night"] .modal-body .gs-seg-btn.active { background: var(--border-md); }
/* Textarea je ve skupině vyjmenovaná ZVLÁŠŤ, ne uvnitř `:is(...)` (17. 9. 2026):
   `:is()` má specificitu svého nejsilnějšího argumentu, a ten tu nese `:not([type=…])`
   — celý selektor byl tedy silnější než výjimka `.modal-body .fg > textarea` pod ním
   a poznámkovým polím vracel pill. Ondra: „poznámkové fieldy nemohou být kulaté." */
.modal-body .fg > :is(input:not([type=checkbox],[type=radio],[type=time],[type=file]), select),
.modal-body .fg > textarea,
.modal-body .fg > .gs-field-unit > input {
  /* `background-color`, ne zkratka `background` (23. 9. 2026): zkratka shodí
     i `background-image`, a protože `:is()` má specificitu svého nejsilnějšího
     argumentu, byla tahle deklarace silnější než šipka selectu pod ní — selecty
     v modalech tedy stály úplně bez ukazatele, že se rozbalují. */
  /* --pole-bg, ne --surface (vlna 3, okna-10): v Day totéž, v Night je pole
     o stupeň světlejší než tělo okna místo tmavší. */
  background-color: var(--pole-bg);
  border: 1px solid var(--border);   /* jemná linka jako všude (sekce 35); do 6. 10. 2026 v barvě plochy, tedy neviditelná */
  border-radius: var(--r-field);
  padding: 13px 12px;
  font-size: var(--fs-base);
}
.modal-body .fg > .gs-field-unit > input { padding-right: 38px; }
/* Pole pod myší (sekce 35): v okně stejně jako všude — plocha zůstává,
   linka zesílí na --border-pole. Zvláštní noční linka (30. 9. 2026) odpadla
   6. 10. 2026: klidovou linku mají teď pole v obou tématech. */
.modal-body .fg > :is(input, select, textarea),
.modal-body .fg > .gs-field-unit > input {
  --pole-plocha: var(--pole-bg);
  --pole-okraj: var(--border-pole);
  --pole-plocha-fokus: var(--pole-bg);
}
.modal-body .fg > :is(input, select, textarea):focus,
.modal-body .fg > .gs-field-unit > input:focus { border-color: var(--focus, var(--blue)); background-color: var(--pole-bg); }
/* Select v modalu si nekreslí vlastní ukazatel — bere špičku z jediné definice
   v sekci 35 (`select`), aby byla v celé appce stejná. Do 23. 9. 2026 si tu
   kreslil plus-ikonu „podle reference", jenže ta tvrdí „přidat", ne „rozbalí se"
   — a kvůli zkratce `background` výš stejně nebyla vidět (Ondra: „chybí malá
   špička pro výběr"). Prázdný required select vypadá jako placeholder. */
.modal-body .fg > select { padding-right: 32px; }
.modal-body .fg > select:required:invalid { color: var(--t3); }
/* Pole se pod myší ozve — u selectu je to jediný signál, že se do něj dá klikat
   celou plochou. `--hover` je průhledný závoj, tady složený na podklad pole. */
.modal-body .fg > :is(input:not([type=checkbox],[type=radio],[type=time],[type=file]), select):hover:not([aria-invalid="true"]),
.modal-body .fg > textarea:hover:not([aria-invalid="true"]) {
  /* Linka se musí převlékat s podkladem. Základní stav má `border: 1px solid
     var(--surface)` — linku v barvě pole, aby focus neměl co dokreslovat; jakmile
     se pod myší podklad ztmavil a linka zůstala bílá, obkroužilo pole světlé
     obrysové kolečko. (Ondra 23. 9. 2026 nad oknem výkazu: „Při hover efektu na
     fieldy jako klient a pod. máme bílý border. Nechceme tam vůbec žádný border.") */
  /* Linka je průhledná: okraj pod myší kreslí pravidlo v sekci 35 vrstvou
     pozadí (`--pole-okraj`), neprůhledný border by ji zakryl. Chybové pole
     si červenou linku nechává. */
  background-color: var(--pole-bg);
  border-color: transparent;
}
/* Víceřádkové pole je výjimka z tvaru ovládacího prvku — viz textarea v sekci 35. */
.modal-body .fg > textarea { min-height: 64px; resize: vertical; }
.modal-body ::placeholder { color: var(--t3); }
.modal-body .fg label, .modal-body .gs-label { color: var(--t3); }

/* Chyba pole (rozhodnutí 6a, pristupnost-09). Nastavuje ji `gsChybaPole()`
   v shared.js: `.fg.chyba`, `aria-invalid="true"` na poli a text `.fg-chyba`
   pod ním, provázaný přes `aria-describedby`. Rámeček je `--red` (hrana
   ovladače, 3 : 1 na bílé i na plátně), text role `--red-txt`. Selektor
   stojí za hoverem i focusem výš se stejnou specificitou, takže červená
   drží i pod myší a během psaní — zmizí až s opravou (posluchač `input`).
   Obecná varianta pro pole mimo okno je v sekci 24. */
.modal-body .fg.chyba > [aria-invalid="true"]:is(input, select, textarea),
.modal-body .fg.chyba > .gs-field-unit > [aria-invalid="true"]:is(input) { border-color: var(--red); }

.modal-row { display: grid; gap: 12px; }
.modal-row.c1 { grid-template-columns: 1fr; }
.modal-row.c2 { grid-template-columns: 1fr 1fr; }
.modal-row.c3 { grid-template-columns: 1fr 1fr 1fr; }
.modal-row.c4 { grid-template-columns: 80px 1fr 1fr 1fr; }
.modal-row.c4eq { grid-template-columns: 1fr 1fr 1fr 1fr; }

.modal-ft {
  display: flex;
  gap: 8px;
  padding: 16px 24px;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}
/* Ničivá akce vlevo, zbytek doprava (Detail tiketu, Nový lead). */
.modal-ft .gs-btn-danger { margin-right: auto; }

/* ── Okno dokladu: kontext, vysvětlivka, souhrn, položky (13. 10. 2026) ──
   Návrh „Modály faktur — jedna kostra" (canvas, schválil Ondra 12. 10. 2026,
   převzato z Fakturoidu). Dvě okna, která vystavují doklad, mají stejnou
   kostru: pod názvem kontext (klient, období, stav), uprostřed souhrn
   částky, v patičce věta, co akce způsobí. Čte: report.html (Vystavit
   fakturu), finance.html (Nová faktura), public/polozky-dokladu.js. */
.modal-hd--kontext { align-items: flex-start; gap: 12px; }
.modal-hd-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.modal-hd-radek { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-height: 32px; }
/* Přepínač typu dokladu (Nová faktura, Úprava dokladu) stojí přímo v .modal-hd
   vpravo vedle křížku: .gs-seg má výšku --h-ctrl (32 px) jako .modal-close
   a mezeru dělá gap hlavičky (Ondra 13. 10. 2026). */
.modal-hd--kontext .modal-title { font-size: var(--fs-2xl); font-weight: var(--fw-bold); }
.modal-kontext { display: flex; flex-wrap: wrap; gap: 4px 8px; }
.modal-kontext .gs-chip .ms { font-size: var(--fs-base); }

/* Věta s ikonou: co se stane (patička), co znamená záloha (tělo). Varianta
   `.varovani` je jantarový pruh — hodiny bez projektu, neschválené řádky. */
.gs-vysvetlivka { display: flex; gap: 8px; align-items: flex-start; font-size: var(--fs-sm); line-height: 1.45; color: var(--t2); }
.gs-vysvetlivka > .ms { font-size: var(--fs-lg); color: var(--t3); flex-shrink: 0; }
.gs-vysvetlivka.varovani { padding: 8px 12px; border-radius: var(--r-field); background: var(--amber-lt); color: var(--amber-txt); }
.gs-vysvetlivka.varovani > .ms { color: inherit; }
/* Patička s vysvětlivkou: věta vlevo, tlačítka vpravo v přirozené šířce
   (jinak primární tlačítko roztáhne `flex: 1` níž přes celou patičku). */
.modal-ft--info { align-items: center; gap: 16px; background: var(--bg-2); }
.modal-ft--info > .gs-vysvetlivka { flex: 1; min-width: 0; }
.modal-ft--info .modal-ft-akce { display: flex; gap: 8px; flex-shrink: 0; }
.modal-ft--info .gs-btn-primary { flex: 0 0 auto; }

/* Souhrn dokladu: řádky (projekt, hodiny, částka) a celkem. Plocha jako
   pole (`--pole-bg`), aby v Day i Night seděla k polím okna. Seznam roluje
   sám, celkem zůstává vidět. */
.gs-souhrn { background: var(--pole-bg); border: 1px solid var(--border); border-radius: var(--r-field); overflow: hidden; }
.gs-souhrn-seznam { max-height: 232px; overflow-y: auto; overscroll-behavior: contain; }
.gs-souhrn-radek { display: flex; justify-content: space-between; align-items: center; gap: 16px; padding: 12px 16px; border-bottom: 1px solid var(--border); }
.gs-souhrn-nazev { display: flex; flex-direction: column; min-width: 0; }
.gs-souhrn-nazev > b { font-weight: var(--fw-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gs-souhrn-meta { font-size: var(--fs-sm); color: var(--t3); }
.gs-souhrn-castka { font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; white-space: nowrap; }
.gs-souhrn-rozpad { display: flex; flex-direction: column; gap: 4px; padding: 12px 16px 4px; font-size: var(--fs-sm); color: var(--t2); font-variant-numeric: tabular-nums; }
.gs-souhrn-rozpad > div { display: flex; justify-content: space-between; align-items: center; gap: 16px; }
.gs-souhrn-rozpad > div > :last-child { color: var(--t1); }
.gs-souhrn-celkem { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 12px 16px; }
.gs-souhrn-rozpad + .gs-souhrn-celkem { padding-top: 8px; }
.gs-souhrn-celkem > :first-child { font-weight: var(--fw-medium); color: var(--t2); }
.gs-souhrn-celkem .gs-souhrn-meta { font-weight: var(--fw-regular); margin-left: 8px; }
.gs-souhrn-cislo { font-size: var(--fs-2xl); font-weight: var(--fw-bold); color: var(--t1); font-variant-numeric: tabular-nums; white-space: nowrap; }
.gs-souhrn-prazdno { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 24px 16px; text-align: center; }
.gs-souhrn-prazdno > .ms { font-size: var(--fs-2xl); color: var(--t3); }
.gs-souhrn-prazdno > b { font-weight: var(--fw-medium); }

/* Položky dokladu jako tabulka (vzor Fakturoid): úchyt, počet, jednotka,
   popis na víc řádků, cena, sazba DPH, celkem, odebrat. Buňky jsou pole bez
   rámečku, rámeček se ukáže pod myší a ve fokusu. Neplátce sloupec DPH
   nemá (`.bez-dph`). Pod řádky „Přidat položku" a sleva, dole rozpad
   po sazbách (`.gs-souhrn-rozpad`, `.gs-souhrn-celkem`). Skládá a čte
   public/polozky-dokladu.js. */
.gs-polozky { --polozky-sloupce: 20px 56px 64px minmax(0, 1fr) 104px 72px 112px 28px; background: var(--pole-bg); border: 1px solid var(--border); border-radius: var(--r-field); overflow: hidden; }
.gs-polozky.bez-dph { --polozky-sloupce: 20px 56px 64px minmax(0, 1fr) 112px 112px 28px; }
.gs-polozky.bez-dph .gs-polozky-dph { display: none; }
.gs-polozky-hlava,
.gs-polozky-radek { display: grid; grid-template-columns: var(--polozky-sloupce); gap: 4px; padding: 4px 8px 4px 4px; }
.gs-polozky-hlava { padding-top: 8px; }
.gs-polozky-hlava > .vpravo { text-align: right; padding-right: 8px; }
.gs-polozky-seznam { max-height: 288px; overflow-y: auto; overscroll-behavior: contain; }
.gs-polozky-radek { align-items: start; border-top: 1px solid var(--border); }
.gs-polozky-radek.tazeny { opacity: .4; }
.gs-polozky-radek.cil-nad { box-shadow: inset 0 2px 0 var(--blue); }
.gs-polozky-radek.cil-pod { box-shadow: inset 0 -2px 0 var(--blue); }
/* Reset tlačítka patří sem: doklad (invoice.html) nemá reset appky a bez něj
   úchyt dostal šedou výplň prohlížeče (13. 10. 2026). */
.gs-polozky-uchyt { height: 32px; display: grid; place-items: center; color: var(--t3); cursor: grab; border-radius: var(--r-sm); border: 0; background: transparent; padding: 0; }
.gs-polozky-uchyt:hover { color: var(--t1); }
.gs-polozky-uchyt > .ms { font-size: var(--fs-lg); }
.gs-polozky .gs-polozky-bunka { min-width: 0; height: 32px; padding: 0 8px; border: 1px solid transparent; border-radius: var(--r-sm); background-color: transparent; font-size: var(--fs-base); line-height: 20px; }
.gs-polozky .gs-polozky-bunka:hover:not(:focus, [aria-invalid="true"]) { background-image: none; border-color: var(--border); }
.gs-polozky .gs-polozky-bunka:focus { background-color: var(--surface); }
.gs-polozky .gs-polozky-bunka.cislo { text-align: right; font-variant-numeric: tabular-nums; }
.gs-polozky textarea.gs-polozky-bunka { height: auto; min-height: 32px; padding: 4px 8px; line-height: 22px; resize: none; overflow: hidden; field-sizing: content; }
.gs-polozky select.gs-polozky-bunka { padding: 0 20px 0 8px; cursor: pointer; background-image: var(--pole-sipka); background-repeat: no-repeat; background-position: right 4px center; }
.gs-polozky .gs-polozky-bunka[aria-invalid="true"] { border-color: var(--red); }
.gs-polozky-celkem { line-height: 32px; text-align: right; padding-right: 8px; font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gs-polozky-radek > .ico-btn { width: 28px; height: 32px; }
.gs-polozky-akce { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 4px 8px; border-top: 1px solid var(--border); }
.gs-polozky-akce .gs-btn-ghost { font-size: var(--fs-sm); }
.gs-polozky-sleva { display: flex; align-items: center; gap: 8px; font-size: var(--fs-sm); color: var(--t2); }
.gs-polozky-sleva .gs-field-unit { width: 96px; }
.gs-polozky-sleva .gs-field-unit > input { height: 32px; padding-top: 0; padding-bottom: 0; }
.gs-polozky-rezim { display: flex; align-items: center; gap: 4px; font-size: var(--fs-sm); color: var(--t3); }
.gs-polozky > .gs-souhrn-rozpad { border-top: 1px solid var(--border); }
/* Jen ke čtení (.gs-polozky-cist, 13. 10. 2026): tytéž sloupce bez úchytu a křížku.
   Řádky spočítala appka (Vystavit fakturu z výkazu); mění se až v konceptu. */
.gs-polozky.gs-polozky-cist { --polozky-sloupce: 56px 64px minmax(0, 1fr) 104px 72px 112px; }
.gs-polozky.gs-polozky-cist.bez-dph { --polozky-sloupce: 56px 64px minmax(0, 1fr) 112px 112px; }
.gs-polozky-cist .gs-polozky-hlava,
.gs-polozky-cist .gs-polozky-radek { padding: 4px 8px; }
.gs-polozky-cist .gs-polozky-hlava { padding-top: 8px; }
.gs-polozky-text { min-width: 0; padding: 4px 8px; line-height: 24px; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.gs-polozky-text.cislo { text-align: right; white-space: nowrap; }
.gs-polozky-text > .gs-souhrn-meta { display: block; line-height: 16px; }
.gs-polozky-cist .gs-polozky-celkem { line-height: 24px; padding: 4px 8px; }
/* Záloha: kolik po ní zbude, malý řádek pod „Celkem k úhradě" (13. 10. 2026). */
.gs-souhrn-zbyva { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; margin-top: -8px; padding: 0 16px 12px; font-size: var(--fs-sm); color: var(--t3); font-variant-numeric: tabular-nums; }
.gs-odkaz-btn { border: 0; background: transparent; padding: 0; font: inherit; font-weight: var(--fw-medium); color: var(--blue-txt); cursor: pointer; }
.gs-odkaz-btn:hover { text-decoration: underline; }
/* Sbalitelný blok `.gs-sbal` — nativní <details>, bez JS (Ondra 13. 10. 2026).
   Volitelné pole, které většinou zůstává prázdné (poznámka na dokladu, další
   údaje), stojí sbalené jako černý odkaz „+ Poznámka“; plus se po rozbalení
   otočí na křížek. Vyplněné pole ve sbaleném bloku prozradí modrá tečka —
   pozná se přes :placeholder-shown; pole bez placeholderu (datum)
   tečku nedá, jinak by svítila i u prázdného.
   Stránka při otevření okna nastaví `open = false`. */
.gs-sbal > summary { display: inline-flex; align-items: center; gap: 4px; width: max-content; list-style: none; font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--t1); cursor: pointer; }
.gs-sbal > summary::-webkit-details-marker { display: none; }
.gs-sbal > summary:hover { text-decoration: underline; }
.gs-sbal > summary .ms { --ms: var(--ms-md); color: var(--t2); transition: transform .15s; }
.gs-sbal[open] > summary .ms { transform: rotate(45deg); }
.gs-sbal[open] > summary { margin-bottom: 8px; }
.gs-sbal:not([open]):has(:is(input, textarea)[placeholder]:not(:placeholder-shown)) > summary::after { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--blue); }

/* Potvrzovací okno — náhrada `confirm()` prohlížeče (Ondra 23. 9. 2026:
   „uděláme vlastní design, modal, který vždycky vyskočí na prostředku v našem
   designu, aplikovaný všude, kde se toto řeší"). Skládá ho `gsPotvrd()`
   v shared.js z TÉHLE skořápky — žádné druhé okno, jen dvě odchylky:

   1. Stojí NAD otevřeným modalem. Ptá se zpravidla právě na něj („zavřít bez
      uložení?"), takže pod ním nemá co dělat. --z-potvrd je nad vším, co se
      dá mít otevřené současně (.modal-overlay, okna nad oknem, popover);
      .gs-confirm-overlay je hláška po akci, ne okno, a nemá pointer-events.
   2. Tělo je jeden odstavec, ne formulář — mezera 16px mezi poli by tu byla
      mezera nad ničím. */
.modal-overlay.gs-potvrd { z-index: var(--z-potvrd); }
.gs-potvrd .modal-body { gap: 8px; }
.gs-potvrd-text { margin: 0; font-size: var(--fs-base); line-height: 1.5; color: var(--t2); }
/* Destruktivní potvrzení (`gsPotvrd(…, { nebezpecne: true })`, audit toky-08):
   hlavní tlačítko je `.gs-btn-danger` místo `.gs-btn-primary` a fokus stojí na
   Zrušit. V okně potvrzení ale NEstojí vlevo jako Smazat v patičce formuláře —
   tady je to odpověď na otázku, takže zabírá místo hlavního tlačítka vpravo. */
.gs-potvrd .modal-ft .gs-btn-danger { margin-right: 0; }
/* Úprava 12. 10. 2026 (Ondra u „Smazat tiket": „ten box je moc veliký a proč je
   tam ta linka?"): otázka je jedna věta, ne formulář. Okno má šířku .modal-xs
   (třída zůstává modal-sm, čtou ji testy a gsVstup), bez linek mezi nadpisem,
   textem a tlačítky, a tlačítka stojí vpravo ve své přirozené šířce. Do té doby
   se Smazat roztáhlo přes celou patičku (flex: 1) a bez detailu zůstaly pod
   nadpisem dvě linky nad sebou. */
.gs-potvrd .modal.modal-sm { max-width: 400px; }
.gs-potvrd .modal-hd { border-bottom: 0; padding-bottom: 8px; }
.gs-potvrd .modal-ft { border-top: 0; justify-content: flex-end; padding-top: 16px; }
.gs-potvrd .modal-hd + .modal-body[hidden] + .modal-ft { padding-top: 8px; }
/* Okno se zadáním textu (`gsVstup()`, náhrada `prompt()`, rozhodnutí 6a): stejná
   skořápka, v těle jedno pole `.fg` — vypadá jako karta pole v každém modalu. */
.gs-vstup .modal-body { gap: 12px; }

/* Okno jako dialog (vlna 3, pristupnost-06): když v okně není co zaměřit,
   `gsOknoOtevreno()` dá fokus samotnému `.modal` (tabindex="-1"). Čtečka pak
   začne nadpisem; prstenec kolem celého okna by jen rušil. */
.modal[tabindex="-1"]:focus { outline: none; }

/* Tlačítka v patičce okna jsou obyčejná `.gs-btn` (od 29. 9. 2026; dřív
   `.btn-modal-save` a `.btn-modal-cancel`, dvojčata primary a ghost s jiným
   odsazením). Z nich zůstala jen velikost: v patičce je tlačítko o stupeň
   větší a hlavní akce zabere zbytek řádku. Panel Fakturoidu má stejnou
   patičku pod jiným jménem. Ikonové tlačítko si drží svůj čtverec. */
:is(.modal-ft, .fak-panel-ft) .gs-btn:not(.gs-btn-ico) { padding: 9px 20px; justify-content: center; }
:is(.modal-ft, .fak-panel-ft) .gs-btn-primary { flex: 1; font-size: var(--fs-base); }

/* ── 26. PAY BADGE — smazáno ─────────────────────────────────
   .pay-badge (k/u/n/p/z/r/w/pf/x/brt/rev a .ikona) se smazal v integraci
   vlny 3 (27. 9. 2026, rozhodnutí 2a). Stav platby kreslí gsChip() /
   platbaChip() / invStavChip() v shared.js s mapou GS_PLATBA_VARIANTA;
   ikonová podoba je .gs-chip.ikona. Číslo sekce zůstává kvůli odkazům. */

/* ── 27. FAKTUROID SUBJECT PICKER ──────────────────────────── */
/* Skořápka je od 1. 10. 2026 DS .modal.modal-sm (vzory-10); tady jen vnitřek:
   pruh hledání a seznam, který se roluje. Do té doby vlastní overlay, box
   (420 px), hlavička a křížek s jiným odsazením než ostatní okna. */
.fak-picker-modal{max-height:520px;overflow:hidden}
/* Layout wrapper (padding/border) — search input uvnitř je .gs-search, viz sekce 31 */
.fak-picker-search{padding:8px 16px;border-bottom:1px solid var(--border);flex-shrink:0}
.fak-picker-search .gs-search{max-width:none}
.fak-picker-list{flex:1;overflow-y:auto}
.fak-picker-item{display:flex;align-items:center;justify-content:space-between;padding:8px 16px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .1s}
.fak-picker-item:last-child{border-bottom:none}
.fak-picker-item:hover{background:var(--blue-lt)}
.fak-picker-name{font-size:var(--fs-md);font-weight:var(--fw-medium);color:var(--t1)}
.fak-picker-id{font-size:var(--fs-xs);color:var(--t3);font-family:var(--ff-mono)}

/* ── 28. PROFIT ──────────────────────────────────────────────
   Barevné označení zisku / ztráty. */

.profit-pos { color: var(--green-txt); font-weight: var(--fw-medium); }
.profit-neg { color: var(--red-txt);   font-weight: var(--fw-medium); }
.margin-pct { font-size: var(--fs-xs); font-weight: var(--fw-medium); padding: 2px 8px; border-radius:var(--r-pill); white-space: nowrap; }
.margin-good { background: var(--green-lt); color: var(--green-txt); }
.margin-ok   { background: var(--amber-lt); color: var(--amber-txt); }
.margin-bad  { background: var(--red-lt);   color: var(--red-txt); }

/* ── 29. ICO-BTN ─────────────────────────────────────────────
   Malé ikonkové akční tlačítko (edit, delete…). */

.ico-btn {
  width: 26px;
  height: 26px;
  border-radius: var(--r-ctrl);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--t3);
  transition: .15s;
  flex-shrink: 0;
}
/* Hover nemá podklad, jen barvu glyfu; okraj rozsvítí záře (sekce 14) v barvě
   akce — `.del` červeně, ostatní modře. Rodinu dřív opisovaly Finance
   (`.tx-act-btn`) a Projekty (`.pi-del`), od 29. 9. 2026 berou tuhle. */
.ico-btn:hover          { color: var(--t1); }
.ico-btn.del:hover      { color: var(--red-txt); }

/* ── 30. ENTITY PILL ─────────────────────────────────────────
   Kompaktní pill badge se jménem fakturujícího subjektu (`issuers`).
   Do 22. 9. 2026 měl dvě barevné varianty, `.sro` (šedá) a `.osvc` (modrá) —
   subjekty tehdy byly natvrdo dva. Od migrace 092 jich může být libovolně
   a barva na subjekt neexistuje (paleta má strop 16, CLAUDE.md §13.2), takže
   rozlišuje jméno. Neutrální styl je ten, co dřív nesla `.sro`.
   Bývalá sekce 15 (číslování do 27. 9. 2026; `.ds-entity-dot`, tečka téhož) zanikla tamtéž — nikdo ji nepoužíval. */

.entity-pill {
  display: inline-flex;
  align-items: center;
  padding: 1px 8px;
  border-radius:var(--r-pill);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: .04em;
  flex-shrink: 0;
  background: var(--border);
  color: var(--t2);
}


/* ── 31. FILTER BAR ───────────────────────────────────────────
   Jediný kontejner filtrů v appce (Projekty, Times, Finance ×4, Tickety;
   index). Kontejner: .gs-time-filter (jméno historické — od 12. 9. 2026 nese
   i filtry bez času), řádky .ftf-row, vnitřní prvky:
     .gs-seg / .gs-seg-btn   — segmentovaný filtr (Figma: Segmented Filter)
     .gs-filter-select       — malý select (Figma: Filter Select)
     .gs-obd                 — filtr období (sekce 60, hotový z lib/obdobi-html.js)
     .ftf-actions            — skupina akcí zarovnaná doprava
     .ftf-row-sub            — další řádek lišty, oddělený linkou
   **Poslední řádek lišty je řádek akcí** (16. 9. 2026): `.ftf-row.ftf-row-sub`
   s `.gs-search` vlevo a `.ftf-actions` vpravo, a v nich je hlavní akce
   stránky modrá `.gs-btn.gs-btn-primary.gs-btn-sm` **jako poslední prvek**
   (sekundární akce — Export, Report, Faktura — nalevo od ní). Do té doby měla
   appka „+ nový" na čtyři způsoby a na čtyřech místech; hlídá
   `test/akcni-radek.test.js`.
   Do 12. 9. 2026 měl segment pět jmen (.ftf-presets, .entity-filter,
   .entity-seg, .filt-grp v DS + .pros-filter-btn v crm.css) a select čtyři
   (.pv-filter, .filter-select, .ftf-year-wrap select, .tk-projekt-sel; obal
   roku a měsíce zanikl 22. 9. 2026) —
   sloučeno podle docs/design-audit-filtry-modaly.md, návrhy N1–N3. */

/* Plochu (bílá, radius, stín) nastavuje sekce 38 — filtr je box. Od
   26. 9. 2026 to platí i uvnitř `.kpi-filter-card`: ta už plochy neslučuje,
   jen skládá boxy pod sebe (viz níž). */
.gs-time-filter {
  padding: 8px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex-shrink: 0;
}
.ftf-row        { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Druhý řádek filtru oddělený linkou (Finance/Transakce: typ + stav platby +
   hledání). Do 12. 9. 2026 inline style na finance.html. */
.ftf-row-sub    { border-top: 1px solid var(--border); padding-top: 8px; margin-top: 4px; }

/* Segmentovaný filtr — šedý pill, aktivní segment bílý se stínem. Přepíná
   podmnožinu dat (Vše / Aktivní / Dokončené, Vše / S.R.O. / OSVČ…).
   Na přepínání *pohledu* (Board / Seznam) je černý .gs-switcher, sekce 46.
   Figma: Segmented Filter (node id v docs/figma.md §4). */
.gs-seg         { display: flex; align-items: stretch; gap: 2px; height: var(--h-ctrl); background: var(--plocha-vnor); border-radius: var(--r-ctrl); padding: 2px; border: 1px solid var(--border); flex-shrink: 0; }
.gs-seg-btn     { display: inline-flex; align-items: center; padding: var(--tx-center) 12px 0; border-radius: var(--r-ctrl); font-size: var(--fs-sm); font-weight: var(--fw-medium); border: none; cursor: pointer; color: var(--t2); background: transparent; transition: .15s; white-space: nowrap; font-family: inherit; }
.gs-seg-btn.active                { background: var(--surface); color: var(--t1); box-shadow: var(--sh); font-weight: var(--fw-medium); }
.gs-seg-btn:hover:not(.active)    { color: var(--t1); }
/* Ve formuláři (OSVČ / S.R.O. v modalu transakce) se roztáhne na šířku pole. */
.gs-seg.gs-seg-block              { width: 100%; }
.gs-seg-block .gs-seg-btn         { flex: 1; text-align: center; }

/* Tlačítko v řádku filtrů (.ftf-actions — Export, Nová položka…) drží stejnou
   výšku jako pole vedle něj; samo o sobě je .gs-btn o 2 px nižší a v řadě to
   bylo vidět. Scopované na .ftf-row schválně: tlačítka v modalech a formulářích
   si svou výšku počítají dál z odsazení. */
.ftf-row .gs-btn { height: var(--h-ctrl); padding-top: 0; padding-bottom: 0; }

/* Filtr období stojí od 16. 9. 2026 v čele lišty (zadání Ondry: *„to od do
   dáme ve všech filtrech na první místo"*). Kdo chce prvek vpravo, řekne si
   o to sám (`#entity-filter-wrap` ve finance.css). Pole Od/Do s popisky
   (`.ftf-range`, `.ftf-label`) a selecty roku a měsíce (`.ftf-year-wrap`)
   nahradil 22. 9. 2026 filtr `.gs-obd` (sekce 60). */
.ftf-clear-range       { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border: 1px solid var(--border); border-radius: var(--r-ctrl); background: transparent; cursor: pointer; color: var(--t3); font-size: var(--fs-base); line-height: 1; transition: .15s; }
.ftf-clear-range:hover { color: var(--red-txt); border-color: var(--red); }

/* Skupina akcí na konci řádku filtru (Nový projekt / Report / Faktura…).
   Do 12. 9. 2026 pětkrát inline `margin-left:auto;display:flex;gap:8px`. */
.ftf-actions    { margin-left: auto; display: flex; gap: 8px; align-items: center; flex-shrink: 0; }
.ftf-actions a  { text-decoration: none; }

/* Malý select v řádku filtru (Stav projektu / Typ / Stav platby, Typ dokladu,
   Rok / Měsíc, Typ práce, Projekt na Tiketech). Do 12. 9. 2026 se jmenoval
   .pv-filter a vedle něj žily .filter-select a .ftf-year-wrap select.
   Figma: Filter Select. */
.gs-filter-select {
  width: auto; height: var(--h-ctrl); padding: var(--tx-center) 26px 0 10px; border: 1px solid var(--border); border-radius: var(--r-ctrl);
  font-size: var(--fs-sm); background: var(--pole-bg); color: var(--t2); outline: none; cursor: pointer;
  appearance: none; font-family: inherit; color-scheme: light; /* světlý nativní dropdown i v dark módu OS — do 12. 9. 2026 inline na Financích */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239CA3AF' stroke-width='2.5' 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 8px center;
}
.gs-filter-select:focus { border-color: var(--blue); }
/* Filtr se chová jako pole (varianta B3, Ondra 6. 10. 2026): v klidu plocha
   --pole-bg a jemná linka --border, pod myší silnější linka, ve fokusu modrá
   se září. Vlastní pravidla, ne obecný hover pole: ten kreslí okraj přes
   background-image a šipku posouvá na 10 px, filtr ji má na 8 px. */
.gs-filter-select:hover:not(:focus, :disabled) { border-color: var(--border-pole); }
.gs-filter-select:focus { box-shadow: 0 0 6px 1px color-mix(in srgb, var(--blue) 55%, transparent); }

/* Row 2 filtru — hledání + multi-select dropdowny (Klienti/Projekty).
   Sdíleno mezi Times a Projekty (Dashboard i Projekty tab) — DO NĚDÁVNA bylo
   jen v times.html, projects.html si tvořilo stejný HTML/JS bez vlastního
   CSS a spoléhalo na tuhle definici v design-system.css, kterou ale
   extrakce Times (commit c6eb438) omylem smazala jako "Times-only" — sem
   patřilo od začátku (2+ stránky, viz CLAUDE.md sekce 13.4).
   Search pole zde používá sdílený .gs-search komponent, viz sekce 31. */
.ti-filter-row2 { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* „+ Filtr" — tlačítko, kterým si člověk lištu skládá (16. 9. 2026, zadání
   Ondry: *„filtrace nám někde bobtná… pokud bude více filtrů k dispozici,
   člověk si je bude moci přidávat a ubírat podle potřeby"*). Vkládá ho
   `gsFiltryInit()` v shared.js, ne stránka — a proto má vlastní jméno, i když
   je to obyčejný ghost button: podle něj se pozná, že v liště už jedna volba
   filtrů běží, a druhá se nepřidá.
   Výšku si musí říct samo. `.ftf-row .gs-btn` (výš) na druhý řádek nedosáhne
   a tlačítko by vedle 32px polí stálo o 4 px nižší. */
.gs-filtr-pridat { height: var(--h-ctrl); padding-top: 0; padding-bottom: 0; gap: 4px; flex-shrink: 0; }
.gs-filtr-pridat .ms { --ms: var(--ms-sm); }
/* Volba sloupců stála do 16. 9. 2026 tady vedle „+ Filtr" jako druhé ghost
   tlačítko. Dnes je to „+" v záhlaví tabulky (sekce 42) — lišta patří filtrům
   (čím výpis zúžit), tabulka svým sloupcům (co v ní vidět). */

/* Filtr s víc volbami (Klienti / Projekty). Spouštěč vypadá jako
   .gs-filter-select — stejná výška, tvar i šipka — ale je to <button>, protože
   nabídka je zaškrtávací, ne jedna hodnota; vybrané volby ho obarví domodra.
   Panel kreslí `gsFiltrDd()` v shared.js přes DS popover (sekce 57), takže
   filtr, výběr z pole a karta tiketu mají od 16. 9. 2026 jednu nabídku.
   Do té doby to bylo `.te-proj-dd*`: vlastní absolutně pozicovaný seznam
   s dvojicí „Vše / Žádné“ a vlastním zavíráním klikem mimo, na třech
   stránkách ve dvou různých tvarech položky. Prázdný výběr dnes znamená
   „nefiltruj“, takže tlačítko „Vše“ zmizelo — bylo by totéž co zrušit výběr.
   Čte: times.html, projects.html, finance.html (spouštěče) a jejich JS. */
.gs-filter-dd {
  display: inline-flex; align-items: center; gap: 8px; flex-shrink: 0;
  min-width: 130px; max-width: 220px; white-space: nowrap;
  height: var(--h-ctrl); padding: 0 11px; border: 1px solid var(--border); border-radius: var(--r-ctrl);
  background: var(--pole-bg); color: var(--t2); font-size: var(--fs-sm); font-family: inherit; cursor: pointer;
}
.gs-filter-dd:hover:not(.has-sel) { border-color: var(--border-pole); }
.gs-filter-dd.has-sel { background: var(--blue-lt); border-color: var(--blue); color: var(--blue-txt); font-weight: var(--fw-medium); }
/* Přímý potomek = šipka. Křížek „zrušit" sedí uvnitř `.gs-clear` a otáčet se
   s panelem nesmí (23. 9. 2026, viz sekce 31). */
.gs-filter-dd > .ms         { flex-shrink: 0; transition: transform .15s; }
.gs-filter-dd.gs-open > .ms { transform: rotate(180deg); }
/* Křížek stojí až za šipkou — „když bude aplikovaný filtr, tak bude za tou
   šipkou" (Ondra 23. 9. 2026). Vkládá ho `gsFiltrDdPopis()` v shared.js až
   při neprázdném výběru, takže tlačítko bez filtru vypadá jako dřív.
   V modrém stavu `.has-sel` si bere barvu tlačítka, ne šedou. */
.gs-filter-dd .gs-clear { margin-left: -2px; }
.gs-filter-dd.has-sel .gs-clear { color: var(--blue-txt); }
.gs-filter-dd.has-sel .gs-clear:hover { background: var(--surface); }
.gs-filter-dd-lbl { padding-top: var(--tx-center); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; text-align: left; }

/* Pás skupin nad výpisem: každá skupina je VLASTNÍ box (26. 9. 2026).
   Do toho dne kontejner slučoval KPI a filtr do jedné plochy a dětem
   orámování sundával (`> *:first-child` / `> *:last-child`). Ondra to přes
   Vercel toolbar otočil: *„Filtrace by měla být ve svém vlastním boxu. To
   stejné i ty rychlé ukazatele, které jsou pod tím."* a *„filtrování tak má
   za sebou ještě box a svůj vlastní box tak má i hledat a buttony k akci"* —
   vzorem jsou Předplatná, kde tři skupiny stojí na třech plochách pod sebou.
   Kontejner proto plochu nemá, jen skládá děti pod sebe s mezerou; box nese
   každé dítě samo. Tím zmizely i tři výjimky, které slučování potřebovalo
   (`.kpi-off` bez pozadí, `:only-child` s plným zaoblením, `:has()` pro
   samotný filtr) — jeden tvar místo čtyř stavů.
   **Pořadí je ukazatele → filtr → akce** (*„Ten rychlý přehled s boxy tak
   musí být nad tou filtrací"*): nejdřív co se stalo, pak čím to zúžit a
   nakonec co s tím udělat. Hlídá `test/boxy-skupin.test.js`. */
.kpi-filter-card { display: flex; flex-direction: column; gap: 8px; flex-shrink: 0; margin: var(--pad-view) var(--pad-view-x) 0; }
.kpi-filter-card > * { background: var(--surface); border: none; border-radius: var(--r); box-shadow: var(--sh-box); }
/* Obaly, které už mají vlastní odsazení 22px (.fin-wrap, .pv-wrap,
   #pv-section-projekty) — karta nesmí přidat druhé. Margin nahoře je pro
   .gs-view bez paddingu (Times). */
.fin-wrap > .kpi-filter-card, .pv-wrap > .kpi-filter-card, #pv-section-projekty > .kpi-filter-card,
.fin-subview > .kpi-filter-card, #pv-section-dashboard > .kpi-filter-card,
.cv-wrap > .kpi-filter-card { margin: 0; }
/* KPI mřížka (5 stat-cards na Projektech/Times/Finance, 4 na Sales). Do
   12. 9. 2026 dvě identické kopie .pv-kpi (projects.css) a .ti-kpi
   (times.css); Finance a Sales měly KPI mimo kartu. Návrh N4. */
/* Odsazení je ze všech stran stejné (Ondra 26. 9. 2026: „padding by měl být
   všude stejný a obsah by měl vyplňovat šířku"). Do toho dne bylo `14px 20px`,
   takže karty začínaly o 6 px dál od kraje než filtrační lišta pod nimi
   (`.gs-time-filter`, 14 px). Stejnou opravu dostala `.vd-kpi` ve finance.css. */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; padding: 16px; background: var(--surface); flex-shrink: 0; }
/* Karta bez KPI: Finance/Transakce mřížku schovají (finance.js showFinView
   přepíná .kpi-off), zbylé boxy stojí dál každý sám za sebe. */
.kpi-filter-card.kpi-off > .kpi-grid     { display: none; }

/* Měsíční picker .ftf-months/.ftf-month zrušen 22. 9. 2026 — období vybírá
   kalendář .gs-obd (sekce 60), mřížka měsíců v liště nikde nezůstala. */

/* Bývalá 24b FILTER BAR (.filter-bar/.filter-bar-row/.filter-select) zrušeno 12. 9. 2026 —
   jediný kontejner je .gs-time-filter (sekce 31), select .gs-filter-select. */

/* ── SEARCH BAR ──────────────────────────────────────────────
   Jednotný search komponent pro celou appku (sjednoceno 2026-09-02 —
   nahrazuje 6 dřívějších skoro-duplicitních implementací: .te-search,
   .filter-search, .vd-search, .fak-picker-search, .sb-si, .hist-search;
   dvě z nich měly stejný bug jako Kontakty sidebar — [type=text] chybělo,
   remíza specificity s globálním input[type=text] níže v tomto souboru
   přebíjela padding-left a lupa se překrývala s textem).
   Dvě velikosti:
     .gs-search              — kompaktní (toolbary, filtr lišty, picker modaly)
     .gs-search.gs-search-lg — velký "button" pill (hero search, např. Kontakty
       sidebar) — radius nad 10px je zde záměrná výjimka pro pill/button,
       viz sekce 13.2 CLAUDE.md.
   Markup:
     <div class="gs-search">
       <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
       <input type="search" autocomplete="off" placeholder="…">
       <button class="gs-search-clear">×</button>  (volitelné — smaže input)
     </div>
   type="search" (ne "text", od 2026-09-05) — Chrome u type="text" polí
   pojmenovaných/umístěných blízko password polí (např. "Jméno" v Nastavení
   vedle API klíčů) nabízel uložená hesla/jména i s autocomplete="off",
   protože ten atribut u login-like polí běžně ignoruje. type="search" tuhle
   nabídku nezobrazuje vůbec — nativní lupu/× ve WebKitu proto níže vypínáme
   (appka má vlastní SVG lupu + .gs-search-clear).
   Focus border barva se dědí z per-sekce pravidel ("Focus border barva dle
   sekce" níže — search input není nijak jiný než ostatní inputy). Barva
   ikony na focus viz stejná sekce, pravidla `[data-page] .gs-search:has(...)`. */
.gs-search{position:relative;flex:1;min-width:160px;max-width:280px}
/* Pozicuje se JEN vedoucí lupa, proto `>`, ne potomek. Do 23. 9. 2026 tu stálo
   `.gs-search .ms`, takže `position:absolute; left:9px; pointer-events:none`
   dostal i glyf `close` uvnitř `.gs-search-clear`: křížek vypadl z toku
   tlačítka (to zůstalo 4×0 px, `elementFromPoint` v jeho středu vracel input)
   a vykreslil se přes lupu vlevo. Křížek tedy nešlo trefit na žádném z osmi
   hledacích polí v appce — Ondra to nahlásil na Výkazech (Vercel toolbar,
   23. 9. 2026). Kdo sem přidá další ikonu, dá ji taky mimo přímého potomka. */
.gs-search > svg,.gs-search > .ms{position:absolute;left:9px;top:50%;transform:translateY(-50%);
  --ms:var(--ms-sm);width:13px;height:13px;color:var(--t3);pointer-events:none;transition:color .15s}
.gs-search > .ms{width:1em;height:1em}
.gs-search input[type=text],.gs-search input[type=search]{width:100%;height:var(--h-ctrl);padding:var(--tx-center) 26px 0 30px;border:1px solid var(--border);
  border-radius:var(--r-ctrl);font-size:var(--fs-sm);background:var(--pole-bg);color:var(--t1);
  outline:none;transition:border-color .15s;color-scheme:light}
.gs-search input:focus{border-color:var(--blue)}
/* ── Křížek „zrušit" ─────────────────────────────────────────
   Kolečko s glyfem `close` (Ondra 23. 9. 2026 přes Vercel toolbar: „malý křížek
   v kroužku"). Jeden tvar pro hledací pole (`.gs-search-clear`) i pro spouštěč
   filtru (`.gs-clear` v `.gs-filter-dd`, sekce 31) — „tohle zruší, co jsem
   zadal" se pak pozná všude stejně (CLAUDE.md §13.4). Do té doby to byl
   holý znak bez plochy; viz komentář u lupy výš, proč se nedal ani trefit.
   Kruh je vidět jen na hover — v klidu nese význam glyf, ne rám. */
.gs-clear,.gs-search-clear{
  display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:16px;height:16px;padding:0;border:none;border-radius:var(--r-pill);
  background:transparent;color:var(--t3);cursor:pointer;
  transition:background .15s,color .15s}
.gs-clear:hover,.gs-search-clear:hover{background:var(--hover);color:var(--t1)}
.gs-clear .ms,.gs-search-clear .ms{--ms:var(--ms-xs);color:inherit}
.gs-search-clear{position:absolute;right:6px;top:50%;transform:translateY(-50%);display:none}
.gs-search input:not(:placeholder-shown)~.gs-search-clear{display:inline-flex}

/* Autofill do filtračního pole (2026-09-09) — Chrome sem sám vypsal křestní
   jméno z adresního profilu ("Ondra" Ondrovi, "Anna" Anně) a rovnou k tomu
   odpálil `input`, takže se stránka nepozorovaně vyfiltrovala do prázdna
   (Times ukazovaly 0 h při 18 živých záznamech). Přechod na type="search"
   výš zastavil jen nabídku hesel, tuhle ne, a autocomplete="off" Chrome
   u autofillu ignoruje — prohlížeč se odsud tedy zastavit nedá.
   Místo toho ho přistihneme: na vyplněné pole Chrome sáhne pseudotřídou
   :-webkit-autofill, na kterou tady visí prázdná animace. Její
   `animationstart` je jediný signál, který rozliší "tohle vyplnil
   prohlížeč" od "tohle napsal člověk" — psaní ani obnova formuláře po
   reloadu ji nespustí. Odklízí to guardSearchAutofill() v shared.js. */
@keyframes gs-search-autofilled{from{opacity:1}to{opacity:1}}
.gs-search input:-webkit-autofill{animation-name:gs-search-autofilled;
  animation-duration:.01s}

/* Příčina toho autofillu nesedí tady, ale v polích pro API klíče — viz
   input.input-secret u globálních pravidel pro inputy níž. */

.gs-search.gs-search-lg{max-width:none}
.gs-search-lg svg{left:14px;width:15px;height:15px}
.gs-search-lg .ms{left:14px;--ms:var(--ms-md);width:1em;height:1em}
/* Velké hledání (spotlight) má vlastní výšku — 40 px, jak vypadalo do
   16. 9. 2026 (11px odsazení + 14px text + rámeček). Filtrační --h-ctrl je
   pro řádek filtrů, tohle je hlavní pole stránky. */
.gs-search-lg input[type=text],.gs-search-lg input[type=search]{height:40px;padding:var(--tx-center) 40px 0 38px;border-radius:var(--r-ctrl);
  font-size:var(--fs-base);background:var(--bg);box-shadow:var(--sh)}
.gs-search-lg input:focus{background:var(--surface);box-shadow:var(--sh-md)}
.gs-search-lg .gs-search-clear{right:14px;width:20px;height:20px}
.gs-search-lg .gs-search-clear .ms{--ms:var(--ms-sm)}

/* ── 32. SETTINGS MODAL ──────────────────────────────────────
   Apple System Settings styl: centrovaný modal, sidebar kategorií vlevo,
   obsah vpravo. Nahradilo starý dropdown (.sh-anchor/.sh-dropdown/.sh-item) —
   viz CHANGELOG.md, roles/permissions redesign. Postavené jen z existujících
   tokenů, žádné nové hex hodnoty. */

.settings-modal-overlay {
  position: fixed; inset: 0; background: var(--scrim); z-index: var(--z-panel);
  display: none; align-items: center; justify-content: center; padding: 20px;
}
.settings-modal-overlay.open { display: flex; }

.settings-modal {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-lg);
  width: 100%;
  max-width: 880px;
  height: 620px;
  max-height: 85vh;
  display: flex;
  overflow: hidden;
  position: relative;
  transition: max-width var(--bento-t);
}

/* ── Bento: okno + karta detailu vedle něj (17. 9. 2026) ──
   Detail podstránky (Obory, Sazby, Fakturace…) nevyjíždí zprava přes celou
   výšku, ale stojí jako druhá karta vedle okna; okno se o ~30 % zúží (880 → 620),
   ať se obě vejdou. Stav drží třída `.rozsireno`, kterou přepíná
   settings-panel.js (nastaveniBento) podle otevřené karty. Zamýšlené i pro
   detail faktury (Finance) a prospektu (Sales). Pod 1100 px karta okno překryje. */
.modal-bento {
  /* Jedna křivka pro zúžení okna i rozevření karty — když běží stejně dlouho,
     střed bento se posouvá plynule a nic neposkočí (Ondra 17. 9.: „hrozně skáče"). */
  --bento-t: .38s cubic-bezier(.32, .72, 0, 1);
  display: flex; align-items: stretch; justify-content: center;
  width: 100%; height: 620px; max-height: 85vh; position: relative;
}
.modal-bento > .settings-modal { height: 100%; max-height: none; flex-shrink: 1; }
.modal-bento.rozsireno > .settings-modal { max-width: 620px; }
@media (max-width: 1100px) {
  .modal-bento.rozsireno > .settings-modal { max-width: 880px; }
}

/* Vzhled dodává sdílené pravidlo v sekci 25; tady zůstává jen umístění —
   Nastavení nemá hlavičku, křížek visí v rohu panelu. */
.settings-modal-close { position: absolute; top: 14px; right: 14px; z-index: 1; }

.settings-sidebar {
  width: 220px; flex-shrink: 0; background: var(--bg-2); border-right: 1px solid var(--border);
  padding: 16px 8px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px;
}
.settings-cat-item {
  display: flex; align-items: center; gap: 8px; padding: 8px 8px; border-radius: var(--r-sm);
  cursor: pointer; font-size: var(--fs-base); color: var(--t2); transition: .12s;
}
.settings-cat-item svg, .settings-cat-item .ms { flex-shrink: 0; }
.settings-cat-item:hover  { background: var(--hover); }
.settings-cat-item.active { background: var(--blue-lt); color: var(--blue-txt); font-weight: var(--fw-medium); }

/* Odhlášení sedí na dně bočního panelu (15. 9. 2026, připomínka z Vercelu).
   `margin-top: auto` ho odtlačí dolů bez ohledu na to, kolik kategorií členovi
   zbylo — řadový člen vidí jednu, admin osm. Písmo si nechává z .settings-cat-item,
   přebírá se jen rodina (tlačítko ji jinak bere od prohlížeče). */
.settings-sidebar-odhlasit { margin-top: auto; padding-top: 8px; border-top: 1px solid var(--border); }
.settings-cat-item.odhlasit {
  width: 100%; border: none; background: none; font-family: inherit;
  color: var(--red-txt); cursor: pointer; text-align: left;
}
.settings-cat-item.odhlasit:hover { background: var(--red-lt); }

.settings-content { flex: 1; overflow-y: auto; padding: 24px 32px; }
.settings-category-pane { display: none; }
.settings-category-pane.active { display: block; }
.settings-section { margin-bottom: 24px; padding-bottom: 24px; border-bottom: 1px solid var(--border); }
.settings-section:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
.settings-section-title { font-size: var(--fs-lg); font-weight: var(--fw-medium); margin-bottom: 4px; }
.settings-section-sub   { font-size: var(--fs-sm); color: var(--t3); margin-bottom: 16px; }

/* Klikatelná položka uvnitř kategorie — otevírá existující panel (worktypes-panel apod.) */
.settings-row {
  display: flex; align-items: center; gap: 12px; padding: 12px 16px;
  border: 1px solid var(--border); border-radius: var(--r); cursor: pointer;
  transition: .12s; margin-bottom: 8px; background: var(--surface);
}
/* Myš = jen modrý rámeček, otevřená karta = modrý podklad (Ondra 7. 10. 2026,
   varianta 1). Do té doby měly obě recept A, takže otevřená karta a karta pod
   myší vypadaly stejně a svítily dvě najednou. Modrá linka je myš, plocha výběr. */
.settings-row:hover      { border-color: var(--blue); }
/* Řádek, jehož detail je právě otevřený v kartě vedle (.modal-bento). */
.settings-row.active     { background: var(--blue-lt); }
.settings-row.active .settings-row-chev { color: var(--blue); }
.settings-row svg, .settings-row .ms { flex-shrink: 0; color: var(--t2); }
.settings-row-label      { font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--t1); }
.settings-row-sub        { font-size: var(--fs-xs); color: var(--t3); margin-top: 1px; }
/* Uložit vedle pole (jméno v Účtu, název workspace): pole a tlačítko v jednom
   řádku, tlačítko se natáhne na výšku pole. Do 14. 10. 2026 stálo .gs-btn-sm
   (24 px) vedle 35 px pole o patro výš v rodiči, kterého výšku dělala
   56px fotka — dno tlačítka tak nelícovalo s polem. */
.settings-pole-radek { display: flex; gap: 8px; }
.settings-pole-radek input { flex: 1; min-width: 0; }
/* Zaplatit předplatné: roční a měsíční varianta tarifu pod sebou ve dvou
   sloupcích. V obyčejné liště se tlačítka různé délky lámala, jak vyšla,
   a sloupce ročně / měsíčně nelícovaly. Dvě třídy: .gs-toolbar stojí
   v souboru níž a jednu by přebil. */
.gs-toolbar.predplatne-volby { display: grid; grid-template-columns: repeat(2, max-content); }

/* Řádek editoru číselníku v kartách Nastavení: Kategorie, Sazebník, Typy práce
   (cisRadek) a Sloupce a Štítky tiketů (tkCfgRadek). Do 14. 10. 2026 ho obě
   funkce skládaly z inline stylů — odsazení 7/10 px, písmo 12/13 px natvrdo,
   ikonky dvou velikostí — a název měl inline `border` i `background`, takže
   přebíjel hover i fokus pole z DS; fokus si kreslil JS přes `style`.
   Teď je název obyčejné pole bez okraje v klidu, hover a fokus má z DS. */
.cis-radek {
  display: flex; align-items: center; gap: 8px; padding: 8px 8px 8px 12px;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-sm);
}
.cis-radek.archiv { opacity: .6; }
.cis-radek .cis-radek-nazev {
  flex: 1; min-width: 0; padding: 4px 8px; font-size: var(--fs-md);
  border-color: transparent; background-color: transparent;
}
.cis-radek select { width: auto; flex-shrink: 0; padding: 4px 24px 4px 8px; font-size: var(--fs-sm); }
.cis-radek .cis-radek-castka { width: 96px; flex-shrink: 0; padding: 4px 8px; font-size: var(--fs-md); text-align: right; }
.cis-radek-pozn  { flex-shrink: 0; white-space: nowrap; font-size: var(--fs-sm); color: var(--t3); }
/* Dvě třídy: .gs-cb (14 px) stojí v souboru níž. */
.cis-radek .gs-cb { flex-shrink: 0; white-space: nowrap; font-size: var(--fs-sm); }
.cis-radek-barva { width: 14px; height: 14px; border-radius: 4px; flex-shrink: 0; }
.cis-radek-barva.bez { border: 1.5px dashed var(--border-md); }
.cis-archiv {
  margin: 12px 0 4px; font-size: var(--fs-xs); color: var(--t3);
  text-transform: uppercase; letter-spacing: .04em;
}
/* Nový API token (Nastavení → Účet → API tokeny): blok kódu na celou šířku.
   Do 14. 10. 2026 inline s `--r-ctrl` (pilulka na dvouřádkovém bloku),
   paddingem 10 px a systémovým `monospace` místo Geist Mono. */
.token-hodnota {
  display: block; word-break: break-all; padding: 8px 12px;
  border-radius: var(--r-field); background: var(--bg-2); color: var(--t1);
  font-family: var(--ff-mono); font-size: var(--fs-sm); user-select: all;
}
/* Podpora (Nastavení → Obecné → Podpora): vlákno je rozbalovací karta.
   Čte settings-panel.js (_supportRadek, _supportNactiVlakno). Do 14. 10. 2026
   celé inline, s velikostmi písma v px a mezerami mimo škálu. `overflow-x:
   hidden` — tlačítko prázdného stavu přetékalo o 1 px a seznam s
   `overflow-y: auto` pod ním kreslil vodorovný posuvník. */
.support-vlakna { display: flex; flex-direction: column; gap: 8px; max-height: 60vh; overflow-y: auto; overflow-x: hidden; }
.sup-vlakno { flex-shrink: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden; }
.sup-vlakno-hlava {
  width: 100%; display: flex; align-items: flex-start; gap: 8px; padding: 12px;
  background: none; border: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.sup-vlakno-hlava:hover { background: var(--blue-hover); }
.sup-vlakno-hlava:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.sup-vlakno-hlava > .ms { color: var(--t3); flex-shrink: 0; }
.sup-vlakno-text   { flex: 1; min-width: 0; }
.sup-vlakno-meta   { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: var(--fs-xs); color: var(--t3); }
.sup-vlakno-cislo  { font-weight: var(--fw-medium); }
.sup-vlakno-nadpis { display: block; margin-top: 4px; font-size: var(--fs-md); line-height: 1.45; color: var(--t1); }
.sup-vlakno-detail { border-top: 1px solid var(--border); padding: 12px; }
.sup-zprava        { margin-bottom: 8px; }
.sup-zprava-kdo    { margin-bottom: 4px; font-size: var(--fs-xs); color: var(--t3); }
.sup-zprava-text   {
  padding: 8px 12px; border-radius: var(--r-sm); background: var(--bg);
  font-size: var(--fs-md); line-height: 1.5; white-space: pre-wrap; color: var(--t1);
}
.sup-zprava.nase .sup-zprava-text { background: var(--blue-lt); }
.sup-nahled  { display: block; max-width: 100%; margin-bottom: 8px; border: 1px solid var(--border); border-radius: var(--r-sm); }
.sup-odpoved { display: flex; gap: 8px; align-items: flex-end; }
.sup-odpoved textarea { flex: 1; resize: vertical; }
.settings-row-chev       { margin-left: auto; color: var(--t3); flex-shrink: 0; }

/* Řádek člena ve Workspace → Členové & role */
.tm-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 8px 16px;
  border: 1px solid var(--border); border-radius: var(--r); background: var(--surface);
}
/* Fotka v řádku: kliknutím se vybírá soubor, proto <label> se skrytým
   vstupem. Není to nová komponenta — kruh kreslí .gs-avatar (sekce 51),
   tady přibývá jen chování a křížek na odebrání. */
.tm-foto { position: relative; flex-shrink: 0; display: inline-flex; }
.tm-foto label { cursor: pointer; display: inline-flex; position: relative; border-radius: 50%; }
/* Pole je .gs-skryte-pole (sekce 65): skryté, ale fokusovatelné — `display:none`
   ho do 27. 9. 2026 vyřazovalo z Tabu (nastaveni-11). */
.tm-foto:hover .gs-avatar { opacity: .75; }
.tm-foto-x {
  position: absolute; right: -4px; bottom: -4px;
  width: 16px; height: 16px; padding: 0; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 50%;
  background: var(--surface); color: var(--t3);
  font-size: var(--fs-xs); cursor: pointer;
}
.tm-foto-x:hover { color: var(--red-txt); border-color: var(--red); }
/* .tm-row se láme na dvě patra: nahoře fotka, jméno a akce, dole přes celou
   šířku propojení na dodavatele. Do 14. 10. 2026 stálo propojení ve sloupci
   se jménem, který mezi fotkou a třemi tlačítky zbyl na ~120 px — popisek
   se lámal do čtyř řádků a e-mail do tří (kolo testování Nastavení). */
.tm-row-info  { flex: 1; min-width: 0; }
.tm-row-name  { font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--t1); }
.tm-row-user  { font-size: var(--fs-xs); color: var(--t3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tm-row-pozn  { font-size: var(--fs-xs); color: var(--t3); max-width: 200px; }
/* Odsazení = fotka .gs-avatar-md (32 px) + mezera řádku (12 px), ať patro
   začíná pod jménem, ne pod fotkou. */
.tm-row-vendor {
  flex: 1 0 100%; display: flex; align-items: center; gap: 8px;
  padding-left: calc(32px + 12px); font-size: var(--fs-xs); color: var(--t3);
}
.tm-row-vendor select { width: auto; min-width: 160px; }
.tm-row-mods  { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.tm-mod-chip  { font-size: var(--fs-xs); padding: 2px 8px; border-radius:var(--r-pill); background: var(--blue-lt); color: var(--blue-txt); font-weight: var(--fw-medium); }
.tm-mod-chip.admin { background: var(--purple-lt); color: var(--purple-txt); }
.tm-mod-chip.role  { background: var(--bg); color: var(--t2); }
/* Super admin platformy — visí na e-mailu v platform_admins, ne na členství
   ve workspace, proto vlastní barva vedle .admin (správce workspace). */
.tm-mod-chip.platform { background: var(--amber-lt); color: var(--amber-txt); }

/* ── 33. LEGACY BUTTON ALIASES — smazáno 29. 9. 2026 ──────────
   `.btn`, `.btn-primary`, `.btn-ghost`, `.btn-sm` nahradilo `.gs-btn`
   s variantou. Že se nevrátí, hlídá test/tlacitka-jedna-rodina.test.js. */

/* ── 34. NAVIGAČNÍ HLAVIČKA ───────────────────────────────────
   Sdílená na všech 5 stránkách. Sloučeno s hodnotami z style.css. */

.hd {
  height: var(--hd-h);
  /* Zdola bez odsazení — aktivní záložka musí doběhnout přesně na spodní
     hranu hlavičky, jinak se s rovinou pod sebou nespojí, jen se jí dotkne. */
  padding: var(--nav-inset) 20px 0;
  gap: 12px;
  display: flex;
  align-items: center;
  flex-shrink: 0;
  z-index: var(--z-hd);
  /* Rovinu 1 maluje .pl-1 přes celé okno — hlavička sama je průhledná.
     Linka dole nedává smysl: hranice mezi hlavičkou a rovinou pod ní není
     čára, ale stupínek v hustotě závoje. */
  background: transparent;
  border-bottom: none;
}
/* Spodní odsazení hlavičky je vypnuté kvůli záložkám — všechno ostatní
   v pruhu (značka, skupina ikon, chip tarifu, CTA) si ho vrací zpátky, aby to
   zůstalo opticky na středu. */
.hd > *:not(.nav-tabs) { margin-bottom: 8px; }

/* Značka vlevo: samotný logotyp, bez dlaždice a bez názvu appky vedle
   (Ondra 24. 9. 2026 — „vlevo bude jen logo Airine, ne symbol, a nebude
   v žádném boxu"). Logotyp je čitelný text, takže druhý nápis „Airine" vedle
   něj by byl týž údaj dvakrát. Šířka 100px je nad dokumentovaným minimem
   90px (docs/brand.md); na telefonu klesá přesně na ně, níž ne. */
.hd-znacka {
  display: flex; align-items: center; flex-shrink: 0; text-decoration: none;
}
.hd-logotyp { width: 100px; height: auto; display: block; }
/* Inkoustový logotyp na tmavé rovině Night zmizí a modré stopy ve značce
   nejdou obarvit filtrem, takže se mění celý soubor. Obě varianty jsou v DOM
   a jednu schová pár `.jen-day`/`.jen-night` (sekce 1) — kdyby se adresa
   dosazovala JavaScriptem, problikla by při každém načtení ta špatná. */

/* Pravá skupina: lupa, režim, Nastavení a kulaté logo účtu. Odsazení mezi nimi
   jsou 4px (Ondra 24. 9. 2026) — hlavička sama drží 12px mezi značkou,
   záložkami a chipem tarifu, což je mezi ikonami moc: čtyři kolečka od sebe
   dvanáct pixelů vypadají jako čtyři samostatné věci, ne jako jeden panel. */
.hd-akce { margin-left: auto; display: flex; align-items: center; gap: 4px; }
.hd-akce form { margin: 0; display: flex; }

/* ── Timer v hlavičce (.hd-timer, 26. 9. 2026) ──────────────────────────────
   Návrh 3 z plátna „Timer v hlavičce" (Design artefakt „Airine dashboard —
   vizuální jazyk", deska TimerHlavicka), schválený Ondrou podle CLAUDE.md
   §13.3 (a — do DS). Do té doby plovoucí tlačítko vpravo dole s vlastním
   `<style>` v timer-widget.js.
   - Kolečko 36 px je PRVNÍ v `.hd-akce`; v klidu jen ikona stopek.
   - Běží/pauza: roztažené samo a ukazuje čas. Najetí promění stopky v akci
     (Spustit na modré, Stop červeně) a u běžícího vysune Pauzu.
   - Obsah je zarovnaný doprava: přibude-li hodina, blok roste doleva.
     Proto `.hd-timer` drží místo 36 px a pilulka nad ním visí od pravé hrany.
   - Šířku pilulky, válečky číslic i obíhající světlo počítá timer-widget.js
     po snímcích (šířka závisí na počtu číslic, světlo na obvodu). CSS drží
     jen stavbu a barvy — kdo mění rozměry tady, musí je změnit i v
     `sirkaPilulky()` tam (odsazení 12 / tečka 17 / pauza 12 / 6 / 27 / 36).
   Rozestupy (Ondra na plátně): tečka → čas 10 px, čas → Pauza 6 px,
   Pauza → Stop 3 px. Pauza jsou dvě linky 1 px, ne glyf. */
.hd-timer { position: relative; width: 36px; height: 36px; flex-shrink: 0; }
.hd-timer-pill {
  position: absolute; top: 0; right: 0; z-index: 1; width: 36px; height: 36px;
  border-radius: var(--r-ctrl); background: var(--hd-podlozka);
  transition: width .34s cubic-bezier(.22, 1, .36, 1), box-shadow .2s;
}
.hd-timer.rozbalena .hd-timer-pill { box-shadow: var(--sh-md); }
/* Okraj podle záře tlačítek (sekce 14): linka 1 px na celém obvodu a nad ní
   záře = pás 2 px rozostřený o 3 px, zamaskovaný zpátky na okraj — nikam
   nepřetéká, takže se nemá kde oříznout. Pozadí (conic-gradient) dosazuje JS. */
.hd-timer-okraj, .hd-timer-zare {
  position: absolute; border-radius: inherit; pointer-events: none; display: none;
  -webkit-mask: linear-gradient(black 0 0) content-box, linear-gradient(black 0 0); -webkit-mask-composite: xor;
          mask: linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0);
}
.hd-timer-okraj { inset: 0; padding: 1px; }
.hd-timer-zare  { inset: -.5px; padding: 2px; filter: blur(3px); }
.hd-timer[data-stav="bezi"] :is(.hd-timer-okraj, .hd-timer-zare),
.hd-timer[data-stav="pauza"] .hd-timer-okraj { display: block; }
.hd-timer-obsah {
  position: absolute; inset: 0; border-radius: inherit; overflow: hidden;
  display: flex; align-items: center; justify-content: flex-end;
}
/* Čas: v klidu bez najetí schovaný. `margin-right` −2 px = čas zajede do
   slotu stopek; s vysunutou Pauzou 6 px. */
.hd-timer-cas {
  flex-grow: 1; min-width: 0; height: 36px; padding-left: 12px; margin-right: -2px;
  display: none; align-items: center; justify-content: flex-end; gap: 8px; white-space: nowrap;
}
.hd-timer.rozbalena .hd-timer-cas { display: flex; }
.hd-timer.s-pauzou .hd-timer-cas { margin-right: 8px; }
/* Tečka nahrávání: plný střed a dvě vlny z linky 1 px, které se rozplývají
   jako kruhy na vodě. Roste inset, ne scale, takže linka zůstane 1 px. */
.hd-timer-tecka {
  position: relative; width: 7px; height: 7px; margin-right: 4px; border-radius: 50%;
  background: var(--red); flex-shrink: 0; display: none;
}
.hd-timer-tecka::before, .hd-timer-tecka::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%; border: 1px solid var(--red);
  opacity: 0; animation: hd-timer-vlna 3.2s cubic-bezier(.2, .6, .35, 1) infinite;
}
.hd-timer-tecka::after { animation-delay: 1.6s; }
@keyframes hd-timer-vlna { 0% { inset: 0; opacity: .75; } 100% { inset: -7px; opacity: 0; } }
.hd-timer[data-stav="bezi"] .hd-timer-tecka { display: block; }
/* Pauza = dvě svislé linky 1 px, stejná tloušťka jako okraj pilulky. Stop je
   čtvereček z téže linky (glyf `stop` subset ikon nenese a linky drží jeden
   řez s pauzou). */
.hd-timer-ik-pauza {
  display: inline-block; box-sizing: border-box; width: 6px; height: 10px; flex-shrink: 0;
  border-left: 1px solid currentColor; border-right: 1px solid currentColor;
}
.hd-timer-ik-stop { display: block; box-sizing: border-box; width: 10px; height: 10px; border: 1px solid currentColor; border-radius: 2px; }
.hd-timer-cas > .hd-timer-ik-pauza { display: none; color: var(--amber-txt); }
.hd-timer[data-stav="pauza"] .hd-timer-cas > .hd-timer-ik-pauza { display: inline-block; }
/* Válečky číslic — stavba jako `.gs-valec` (sekce 60), ale spojitě jako
   počítadlo kilometrů: pás má za poslední číslicí ještě jednu nulu, 9 → 0
   dojede dolů na ni a nevrací se přes všechny číslice. Pozice jsou pevné
   (desítky hodin, hodiny, :, desítky minut …); co není potřeba, má nulovou
   šířku, takže hodina se vysune a nic se nepřeskládá. */
.hd-timer-rada {
  display: inline-flex; align-items: baseline; font-variant-numeric: tabular-nums;
  font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--t1);
}
.hd-timer[data-stav="klid"] .hd-timer-rada { color: var(--t3); }
.hd-timer[data-stav="pauza"] .hd-timer-rada { color: var(--t2); }
.hd-timer-okno {
  display: block; width: .62em; height: 1.1em; line-height: 1.1em; overflow: hidden; flex-shrink: 0;
  transition: width .3s cubic-bezier(.22, 1, .36, 1), opacity .3s;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, black 16%, black 84%, transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0, black 16%, black 84%, transparent 100%);
}
.hd-timer-okno.dvojtecka { width: .32em; overflow: visible; -webkit-mask-image: none; mask-image: none; }
.hd-timer-okno.skryte { width: 0; opacity: 0; }
.hd-timer-pas { display: block; will-change: transform; }
.hd-timer-pas.dosedne { transition: transform .3s cubic-bezier(.22, 1, .36, 1); }
.hd-timer-znak { display: block; height: 1.1em; text-align: center; }
/* Pauza/Pokračovat: kolečko 28 px, 3 px od kolečka Stop (−1 px okraj). */
.hd-timer-pauza {
  width: 28px; height: 28px; flex-shrink: 0; margin-right: -1px; padding: 0; border: none;
  border-radius: var(--r-ctrl); background: var(--bg); color: var(--t1); cursor: pointer;
  display: none; align-items: center; justify-content: center;
  animation: hd-timer-fade .22s ease .06s both; transition: background .12s;
}
.hd-timer-pauza:hover { background: var(--hover); }
.hd-timer.s-pauzou .hd-timer-pauza { display: inline-flex; }
.hd-timer-pauza .ms { --ms: var(--ms-md); display: none; }
.hd-timer[data-stav="pauza"] .hd-timer-pauza .ms { display: inline-block; }
.hd-timer[data-stav="pauza"] .hd-timer-pauza .hd-timer-ik-pauza { display: none; }
@keyframes hd-timer-fade { from { opacity: 0; } to { opacity: 1; } }
/* Slot: stopky se po najetí promění v akci. Obě ikony stojí na sobě a prolnou
   se s pootočením; pod akcí se rozsvítí kolečko 28 px. */
.hd-timer-slot {
  position: relative; width: 36px; height: 36px; flex-shrink: 0; padding: 0; border: none;
  border-radius: var(--r-ctrl); background: transparent; cursor: pointer;
}
.hd-timer-slot-bg {
  position: absolute; inset: 4px; border-radius: var(--r-ctrl); background: transparent; transform: scale(.6);
  transition: background .2s, transform .24s cubic-bezier(.22, 1, .36, 1);
}
.hd-timer-slot-ik {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  transition: opacity .18s, transform .26s cubic-bezier(.22, 1, .36, 1);
}
.hd-timer-slot-ik .ms { --ms: var(--ms-md); }
.hd-timer-slot-ik.stopky { color: var(--t2); }
.hd-timer[data-stav="bezi"] .hd-timer-slot-ik.stopky { color: var(--red-txt); }
.hd-timer[data-stav="pauza"] .hd-timer-slot-ik.stopky { color: var(--amber-txt); }
.hd-timer-slot-ik.akce { opacity: 0; transform: scale(.6) rotate(60deg); color: var(--red-txt); }
.hd-timer-slot-ik.akce .ms { display: none; }
.hd-timer[data-stav="klid"] .hd-timer-slot-ik.akce { color: var(--white); }
.hd-timer[data-stav="klid"] .hd-timer-slot-ik.akce .hd-timer-ik-stop { display: none; }
.hd-timer[data-stav="klid"] .hd-timer-slot-ik.akce .ms { display: inline-block; }
.hd-timer.hover .hd-timer-slot-bg { transform: scale(1); background: color-mix(in srgb, var(--red) 14%, var(--surface)); }
.hd-timer.hover[data-stav="klid"] .hd-timer-slot-bg { background: var(--blue-plocha); }
.hd-timer.hover .hd-timer-slot-ik.stopky { opacity: 0; transform: scale(.6) rotate(-60deg); }
.hd-timer.hover .hd-timer-slot-ik.akce { opacity: 1; transform: none; }
.hd-timer-slot:hover .hd-timer-slot-bg { filter: brightness(.97); }
@media (prefers-reduced-motion: reduce) {
  .hd-timer-pauza, .hd-timer-tecka::before, .hd-timer-tecka::after { animation: none; }
  .hd-timer-pill, .hd-timer-okno, .hd-timer-pas.dosedne, .hd-timer-slot-bg, .hd-timer-slot-ik { transition: none; }
}

/* Kulaté logo účtu — poslední v řadě, tvarem jiné než ikonová tlačítka vedle
   (kruh, ne zaoblený čtverec), protože to není akce, ale KDO/KDE. Klik i najetí
   otevírá panel s přepínačem workspace a odhlášením (`otevriUcetPanel()`).
   Uvnitř je logo zákazníka přes celý kruh (`cover`), stejně jako avatar
   workspace jinde v appce (`.gs-avatar`). Do 8. 10. 2026 tu bylo `contain`
   s odsazením 3 px — logo pak plavalo v kruhu jako menší čtverec (Ondra:
   „aby mělo fill, ne fit"). Bez loga zbydou iniciály na inkoustu —
   `.hd-avatar-txt`. */
.hd-avatar {
  width: 36px; height: 36px; padding: 0; flex-shrink: 0;
  border: none; border-radius: 50%; background: var(--papir);
  color: var(--t1); font-family: inherit; font-size: var(--fs-sm); font-weight: var(--fw-medium);
  line-height: 1; cursor: pointer; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  transition: box-shadow .12s;
}
.hd-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* S logem bez podkladu (8. 10. 2026). Bílý `--papir` pod obrázkem prosvítal
   na vyhlazené hraně kruhu — tmavé logo pak mělo tenký světlý obrys, nejvíc
   vidět v Night (Ondra: „co to je za obrys okolo toho loga?"). Podklad má
   smysl jen pro iniciály, ty mají vlastní (`.hd-avatar-txt`). */
.hd-avatar:has(> img) { background: transparent; }
/* Totéž u avatarů v appce: fotka/logo jako `<img class="gs-avatar">` by na
   hraně kruhu lemovala modrou plochou určenou pro iniciály. */
img.gs-avatar { background: transparent; }
/* Iniciály se centrují OPTICKY (`padding-top`), ze stejného důvodu jako
   u `.gs-avatar` (DS sekce 51): velká písmena sedí v řádkovém boxu výš než
   jeho střed. Na `<img>` variantu se použít nesmí — tu by odsazení ořízlo. */
.hd-avatar-txt { background: var(--hd-inicialy); color: var(--white); padding-top: .08em; }
.hd-avatar:hover, .hd-avatar.gs-open { box-shadow: 0 0 0 2px var(--border-md); }

.hd-right     { margin-left: auto; display: flex; align-items: center; gap: 8px; }

/* Mezera mezi záložkami musí uživit zuby propojení z obou stran (2× --joint),
   jinak by zub aktivní záložky zasahoval pod sousední. */
.nav-tabs {
  display: flex;
  gap: calc(2 * var(--joint));
  align-self: stretch;
  position: relative;   /* kotva pro jezdec .nav-slider */
  /* Odstup od logotypu (Ondra 26. 9. 2026: „aby nebyli tolik na tom logu").
     Hlavička drží mezi svými prvky 12 px, což je mezi značkou a první
     záložkou málo — logotyp je text a záložka vedle něj vypadá jako jeho
     pokračování. 20 px navíc je tedy odstup od značky, ne od kraje okna:
     proto `margin-left` na záložkách a ne větší `gap` v `.hd`, který by
     roztáhl i mezeru ke skupině ikon vpravo. */
  margin-left: 20px;
}

/* ── Jezdec hlavní navigace ────────────────────────────────────────────────
   Totéž co .sub-slider o patro níž; obojí sleduje hover a po opuštění pruhu
   se vrací na aktivní záložku (viz nav-slider.js, hoverFollow). Jediný rozdíl
   je rovina, do které se spojuje: tady --plane-join (rovina pod hlavičkou),
   dole --veil-3 (panel obsahu). */
.nav-slider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--sl-w, 0px);
  transform: translateX(var(--sl-x, 0px));
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  background: var(--plane-join);
  --join-into: var(--plane-join);
  pointer-events: none;
  z-index: 0;
  transition: transform .34s cubic-bezier(.22, 1, .36, 1),
              width     .34s cubic-bezier(.22, 1, .36, 1);
}
.nav-tabs:not([data-sl-ready]) .nav-slider { opacity: 0; transition: none; }
.nav-tabs:not([data-sl-ready]) .nav-tab.active { background: var(--plane-join); }

.nav-tab {
  /* Šířka +50 % (2026-09-08, na přání) — dřív 8px/16px. Roste jen odsazení,
     výška a typografie zůstávají, aby se nezměnil rytmus hlavičky. */
  padding: 8px 32px;
  /* Zaoblení jen nahoře — dole záložka přechází do roviny pod sebou. */
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  cursor: pointer;
  color: var(--nav-t);
  border: none;
  background: transparent;
  transition: background .15s, color .15s;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  align-self: stretch;      /* doběhne na spodní hranu hlavičky */
  position: relative;
  z-index: 1;               /* text nad jezdcem */
  gap: 4px;
  text-decoration: none;
  white-space: nowrap;
}
.nav-tab svg { width: 22px; height: 22px; flex-shrink: 0; }
.nav-tab .ms { --ms: var(--ms-lg); }

/* Zpětnou vazbu na hover nese jezdec, který pod tab přijede — šedá vrstva
   navíc by se s ním prala. Zůstává jen ztmavení textu.
   Text aktivního tabu jde na --t1: rovina pod ním je světlá. */
.nav-tab:hover        { background: transparent; color: var(--t1); }
.nav-tab.active,
.nav-tab.active:hover { background: transparent; color: var(--t1); }

/* Ikona aktivního tabu. Jedna barva: modul se pozná názvem a ikonou,
   ne barvou (viz :root — sekční barvy zrušeny 14. 9. 2026). */
.nav-tab.active svg, .nav-tab.active .ms { color: var(--nav-akcent); }

/* ── Zuby propojení (sdílené pro .nav-tab i .sub-tab) ─────────
   Aby aktivní záložka vypadala jako výběžek roviny pod sebou, nesmí se do
   ní zapíchnout ostrým rohem — potřebuje po stranách vydutý roh, který
   plynule přejde do roviny. Vedle jazýčku sedí čtvereček v barvě roviny
   pod ním a maskou je z něj vykrojená čtvrtkružnice — totéž, co ve Figmě
   dělá boolean subtract.

   POZOR na střed kružnice (2026-09-07): vykrojit se musí roh VZDÁLENÝ od
   záložky, ne ten přilehlý. U levého zubu je to tedy 0 0 (levý horní),
   u pravého 100% 0. Dřív to tu bylo prohozené a místo vydutého přechodu
   vznikl odtržený klínek, který se záložky dotýkal jen v jednom bodě —
   ty „zuby“ na screenshotech.

   Totéž používají záložky uvnitř panelu (.gs-tab-slider, sekce 58).

   Zuby nenese aktivní záložka, ale jezdec (.nav-slider / .sub-slider) — spoj
   se musí přesouvat spolu s ním, jinak by zůstal viset na staré pozici. */
.nav-slider::before, .nav-slider::after,
.sub-slider::before, .sub-slider::after,
.gs-tab-slider::before, .gs-tab-slider::after {
  content: '';
  position: absolute;
  bottom: 0;
  width: var(--joint);
  height: var(--joint);
  background: var(--join-into);
  pointer-events: none;
}
.nav-slider::before, .sub-slider::before, .gs-tab-slider::before {
  left: calc(-1 * var(--joint));
  -webkit-mask-image: radial-gradient(circle var(--joint) at 0 0, #0000 0 var(--joint), var(--ink) var(--joint));
          mask-image: radial-gradient(circle var(--joint) at 0 0, #0000 0 var(--joint), var(--ink) var(--joint));
}
.nav-slider::after, .sub-slider::after, .gs-tab-slider::after {
  right: calc(-1 * var(--joint));
  -webkit-mask-image: radial-gradient(circle var(--joint) at 100% 0, #0000 0 var(--joint), var(--ink) var(--joint));
          mask-image: radial-gradient(circle var(--joint) at 100% 0, #0000 0 var(--joint), var(--ink) var(--joint));
}

/* Primární CTA v headeru.
   Od 16. 9. 2026 už ho má jen skrytý modul Marketing: „+ nový" na Projektech,
   Financích a v Sales se přestěhoval do posledního řádku filtrační lišty
   (hledání vlevo, akce vpravo) a nosí `.gs-btn.gs-btn-primary.gs-btn-sm` —
   zadání Ondry přes Vercel toolbar, jeden design a jedno místo na všech
   stránkách. Nová stránka tenhle tvar nepoužívá; sahá po akčním řádku. */
.hd-action {
  margin-left: auto;
  padding: 7px 16px;
  color: var(--white);
  border: none;
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  border-radius: var(--r-ctrl);
  /* Hlavička je zase světlá (varianta B+), takže CTA je nejsytější prvek
     v pruhu — zpátky na sdílený modrý gradient tlačítek. */
  background: var(--btn-gradient);
  color: var(--white);
  box-shadow: var(--btn-shadow);
  transition: filter .15s, transform .1s;
}
.hd-action + .hd-action { margin-left: 0; }
.hd-action:hover  { filter: brightness(1.08); }
.hd-action:active { transform: scale(.98); filter: brightness(.96); }

/* `.hd-export` zrušen 16. 9. 2026 — byl to `.gs-btn.gs-btn-secondary` s jiným
   odsazením a vlastním stínem, a obě jeho poslední použití (Export výdajů,
   Export faktur) stála v řádku akcí, ne v hlavičce. Dnes je tam sdílené
   tlačítko; kdo potřebuje sekundární akci, bere `.gs-btn.gs-btn-secondary`. */

/* Bývalé sekce 28 ENTITY CONTROLS a 29 KATEGORIE FILTR (číslování do 27. 9. 2026) zrušeny 12. 9. 2026 — .entity-seg,
   .entity-btn, .entity-filter, .entity-filter-btn, .filt-grp, .filt-btn byly
   čtyři kopie segmentovaného filtru; teď .gs-seg / .gs-seg-btn (sekce 31). */

/* ── 35. FORM INPUTS ──────────────────────────────────────────
   Sdílený styl pro inputy, selecty a textarey.
   Sekce je záměrně POSLEDNÍ v souboru → načítá se po style.css
   → var(--bg), var(--r) atd. se vždy resolvují na správné hodnoty. */

input[type=text],
input[type=email],
input[type=tel],
input[type=url],
input[type=date],
input[type=month],
input[type=number],
input[type=search],
select,
textarea {
  padding: 8px 11px;
  /* Pole v klidu: světlá plocha a jemná linka v barvě linek appky (B3, Ondra
     6. 10. 2026). Do té doby měl každý podklad jiné pole: v okně bílé bez
     okraje na skoro bílém těle (kontrast 1,05, pole nebylo vidět), na kartě
     šedé s okrajem --border-pole, v liště bílé s tenkou linkou. Teď všude
     totéž; silnější linka --border-pole přijde až pod myší. --pole-bg je
     v Day bílá, v Night o stupeň světlejší než karta. */
  border: 1px solid var(--border);
  border-radius: var(--r-field);
  font-size: var(--fs-md);
  color: var(--t1);
  background: var(--pole-bg);
  outline: none;
  font-family: inherit;
  /* Bez přechodu okraje (30. 9. 2026): záře kreslí okraj pozadím a border je
     průhledný. Přechod šedé → průhledné nechal zaměřené pole chvíli (a v okně
     bez fokusu natrvalo) s šedou linkou přes modrou. */
  transition: box-shadow .15s, background-color .15s;
  width: 100%;
  box-sizing: border-box;
}

/* `background-color`, NE zkratka `background` (16. 9. 2026). Zkratka přepisuje
   i `background-image`, takže zaměřenému `<select>` mizela šipka: člověk na
   pole klikl, šipka zmizela a zůstalo modře orámované prázdné pole, které
   vypadalo rozbitě. Platilo to pro každý select v appce (obě definice šipky
   — `select` i `.gs-filter-select` — ji kreslí přes `background-image`).
   Hlídá test/boxy.test.js. */
input:focus, select:focus, textarea:focus {
  border-color: var(--blue);
  background-color: var(--pole-bg);
}

/* ── Pole pod myší a ve fokusu (30. 9. 2026, hover zklidněný 5. 10. 2026) ────
   Pod myší jen zesílí linka (z --border na --border-pole), plocha ani světlo
   se nemění. Od 30. 9. do
   5. 10. 2026 tu svítila záře u kurzoru jako u tlačítek (sekce 14); Ondra
   5. 10. 2026 nad oknem výkazu: „až příliš moc efektů na jednom místě, část
   boxů musí být více standardní a statická". Záře zůstává tlačítkům
   a řádkům, pole jsou klidná. Zaměřené pole svítí celým obvodem — plná
   modrá linka a kolem ní měkká záře.

   Pole (input, select, textarea) nemá ::before ani ::after, proto se okraj
   nekreslí borderem, ale vrstvami pozadí: border je průhledný a pod ním leží
   `border-box` vrstva s okrajem a září, přes ni `padding-box` plocha pole.
   Select nese navrch svou šipku (`--pole-sipka`), jinak by ji vrstvy přepsaly.
   Jen dlouhé vlastnosti `background-*`, nikdy zkratka `background` — ta by
   selectu smazala šipku (test/boxy.test.js).

   Barvy dávají kontexty přes proměnné, samy si pravidlo nekopírují:
     --pole-plocha        plocha pod myší      (základ --pole-bg)
     --pole-okraj         okraj pod myší       (základ --border-pole)
     --pole-plocha-fokus  plocha zaměřeného pole (základ --pole-bg)
   Pole nejsou v `ZARE_SEL` (akce.js): polohu kurzoru nepotřebují.

   Beze změny pod myší: zamčené a jen ke čtení pole, pole s chybou (červená má přednost),
   velké číslo `.gs-hero-num` (pole bez okraje) a filtr `.gs-filter-select`,
   který má stejné stavy z vlastních pravidel (sekce 31). */
:is(input:is([type=text], [type=email], [type=tel], [type=url], [type=date], [type=month], [type=number], [type=search]), select, textarea) {
  --pole-plocha: var(--pole-bg);
  --pole-okraj: var(--border-pole);
  --pole-plocha-fokus: var(--pole-bg);
}
select { --pole-sipka: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239CA3AF' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); }

:is(input:is([type=text], [type=email], [type=tel], [type=url], [type=date], [type=month], [type=number], [type=search]), select, textarea):hover:not(:focus, :disabled, [readonly], [aria-invalid="true"], .gs-hero-num > *, .gs-filter-select, .gs-chip-select) {
  border-color: transparent;
  background-image:
    var(--pole-sipka, none),
    linear-gradient(var(--pole-plocha), var(--pole-plocha)),
    linear-gradient(var(--pole-okraj), var(--pole-okraj));
  background-origin: padding-box, padding-box, border-box;
  background-clip: padding-box, padding-box, border-box;
  background-repeat: no-repeat;
  background-position: right 10px center, 0 0, 0 0;
}

:is(input:is([type=text], [type=email], [type=tel], [type=url], [type=date], [type=month], [type=number], [type=search]), select, textarea):focus:not(:disabled, [readonly], [aria-invalid="true"], .gs-hero-num > *, .gs-filter-select, .gs-chip-select) {
  border-color: transparent;
  background-image:
    var(--pole-sipka, none),
    linear-gradient(var(--pole-plocha-fokus), var(--pole-plocha-fokus)),
    linear-gradient(var(--blue), var(--blue));
  background-origin: padding-box, padding-box, border-box;
  background-clip: padding-box, padding-box, border-box;
  background-repeat: no-repeat;
  background-position: right 10px center, 0 0, 0 0;
  box-shadow: 0 0 6px 1px color-mix(in srgb, var(--blue) 55%, transparent);
}

/* Zamčené pole — základní stav, který appce chyběl (23. 9. 2026). První místo,
   kde je potřeba, je odběratel v Kontaktech: se zapnutým „Fakturovat na firmu"
   pole jen ukazují údaje firmy a nedají se psát (Ondra: „bude vyplněné a
   šedivé a bude zamčené"). Text jde na --t2, plocha zůstává --bg, takže je
   čitelný, ale zřetelně neaktivní. Prohlížeče kreslí `:disabled` vlastní
   šedí, která paletu nedrží — proto to appka říká sama. */
input:disabled, select:disabled, textarea:disabled {
  color: var(--t2);
  cursor: default;
}

/* ── Maskovaný tajný klíč — input.input-secret (2026-09-09) ──────────────────
   API tokeny a client secrets v Nastavení (Apify, Google Places, Fakturoid)
   byly type="password". Přitom to nejsou přihlašovací hesla, jen dlouhé
   řetězce, které nemají svítit na obrazovce.
   Rozdíl není kosmetický: type="password" kdekoli na stránce znamená pro
   Chrome "tady se přihlašuje". Nastavení se přitom injektuje do KAŽDÉ
   stránky (panelsHtml v server.js), takže Chrome bral za přihlašovací
   formulář i modal s časovým záznamem — nabízel uložit heslo s uživatelským
   jménem "1.5" (počet hodin) a do filtračního pole doplňoval křestní jméno
   z adresního profilu. Guard u .gs-search výš uklízí ten druhý příznak;
   tady mizí příčina obojího.
   Maskujeme proto stylem, ne typem pole — dojem je stejný, ale pro prohlížeč
   je to obyčejný text a žádné přihlášení nikde nevidí.
   Selektor musí být `input.input-secret`, ne samotná třída: `font-family:
   inherit` v pravidle nad tímhle má vyšší specificitu a monospace by přebilo.
   (Maskování funguje v Chrome/Safari/Edge, ve Firefoxu od verze 141. Ve
   starším Firefoxu by byl klíč čitelný — proto to patří jen na pole, která
   si uživatel vyplňuje sám, ne na cizí tajemství.) */
input.input-secret {
  -webkit-text-security: disc;
  text-security: disc;
  font-family: var(--ff-mono);
  letter-spacing: .05em;
}

/* type=search dostává vlastní nativní lupu/× ve WebKitu (Chrome/Safari) —
   appka má všude svoje vlastní "Hledat…" pole s vlastním × tlačítkem
   (viz contacts.html apod.), takže nativní dekorace vypínáme, aby se
   nezdvojily. Samotný type=search zůstává (viz CHANGELOG 2026-09-05) —
   type=text na poli "Hledat…" nutil Chrome nabízet uložená hesla/jména. */
input[type=search]::-webkit-search-decoration,
input[type=search]::-webkit-search-cancel-button,
input[type=search]::-webkit-search-results-button,
input[type=search]::-webkit-search-results-decoration {
  -webkit-appearance: none;
  appearance: none;
}

/* Focus — jedna barva pro celou appku.
   Do 14. 9. 2026 tu bylo 27 pravidel, sedm barev, jedna na modul: focus
   pole v Financích zelený, v Projektech oranžový. Sekční barvy padly
   (viz :root nahoře), takže focus je všude --blue. Token --focus zůstává,
   protože ho přes var(--focus, var(--blue)) čtou pravidla s vyšší
   specificitou (karty polí v modálech, sekce 25) — jen už se nikde nepřepisuje. */
input:focus, select:focus, textarea:focus { border-color: var(--focus); }

/* Lupa v search poli na focus — border výš platí i pro .gs-search input,
   tohle jen dobarví ikonu, viz sekce 31 SEARCH BAR. */
.gs-search:has(input:focus) > svg, .gs-search:has(input:focus) > .ms { color: var(--focus); }

input::placeholder, textarea::placeholder {
  color: var(--t3);
}

select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239CA3AF' stroke-width='2.5' 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: 30px;
}

textarea { resize: vertical; min-height: 80px; line-height: 1.6; }

/* `height` je pro vodorovné posuvníky (board tiketů, široké tabulky) — bez něj
   jim zůstávala systémová výška ~15 px a tlustý šedý pruh vypadal jako linka
   nakreslená do karty (13. 9. 2026). */
::-webkit-scrollbar       { width: 5px; height: 5px; }
::-webkit-scrollbar-track  { background: transparent; }
::-webkit-scrollbar-thumb  { background: var(--border-md); border-radius: 3px; }

/* ── 36. STAT CARDS ──────────────────────────────────────────
   KPI boxy sdílené mezi Finance, Projekty a Dashboard. */

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 8px;
  flex-shrink: 0;
}
/* KPI dlaždice. NENÍ primární box (sekce 38) — v celé appce stojí výhradně
   uvnitř pásu .kpi-grid nebo .vd-kpi, nikdy sama. Proto si hranu drží: bílá
   dlaždice na bílém pásu bez ní zmizí a z pěti čísel je jedna plocha.
   Stejný důvod jako u .sub-month-card a .akt-card. */
.stat-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
/* .stat-card.glass zrušen 30. 9. 2026 (jazyk-15) — nepoužíval ho nikdo. */

.stat-label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--t3);
}
.stat-val {
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  color: var(--t1);
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
.stat-val span { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--t2); }
.stat-sub { font-size: var(--fs-xs); color: var(--t3); }
.stat-val.green, .stat-val.pos  { color: var(--green-txt); }
.stat-val.amber, .stat-val.warn { color: var(--amber-txt); }
.stat-val.red,   .stat-val.neg  { color: var(--red-txt); }

/* ── 37. SUB-NAVIGATION ──────────────────────────────────────
   Submenu pod hlavním headerem (Finance, CRM, atd.). */

/* Rovina 1 — prostřední stupínek žebříku. Sem se shora spojí aktivní modul
   z hlavní navigace, zdola z ní vystupuje aktivní podzáložka do obsahu.
   Výška je pevná (--subnav-h), protože na ní závisí, kde na body začíná
   obsahová rovina; linka dole odpadla, hranici teď dělá barevný stupínek. */
.sub-nav {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--joint));
  height: var(--subnav-h);
  /* Shora 10px jako .hd — záložka nesmí doběhnout až k rovině nad sebou,
     jinak se ty dvě dotknou a stupínek mezi nimi zmizí. Zdola nula, tam se
     naopak spojit musí. Do stran --pad-view-x: záložky stojí v jedné linii
     s boxy obsahu na panelu .pl-3 (Ondra 13. 10. 2026, dřív 20px = o 5 px vedle). */
  padding: var(--nav-inset) var(--pad-view-x) 0;
  /* Rovinu 2 maluje .pl-2 přes celé okno — lišta sama je průhledná. */
  background: transparent;
  border-bottom: none;
  flex-shrink: 0;
  position: relative;   /* kotva pro jezdec .sub-slider */
}

/* ── Jezdec ────────────────────────────────────────────────────────────────
   Aktivní podzáložka není obarvený button — je to tenhle jeden element, který
   mezi záložkami popojede. Nese pozadí roviny obsahu i zuby spoje do ní, díky
   čemuž spoj přejede s ním a nikdy se nerozpadne na dvě místa.

   Geometrii (--sl-x, --sl-w) měří nav-slider.js a zapisuje ji na .sub-nav; ta
   dědí. Dokud první měření nedoběhne, chybí data-sl-ready a jezdec je skrytý
   bez přechodu — jinak by při načtení stránky přijel zleva od nuly.

   Chová se stejně jako .nav-slider nahoře: sleduje hover a po opuštění pruhu
   se vrací na aktivní záložku.

   POZOR na top: obsahující blok absolutního potomka je *padding box*, takže
   top: 0 by jezdce posadilo nad odsazení, ne pod něj. Odtud --nav-inset.
   U .nav-slider to potřeba není, ten sedí v .nav-tabs uvnitř odsazení .hd. */
.sub-slider {
  position: absolute;
  top: var(--nav-inset);
  bottom: 0;
  left: 0;
  width: var(--sl-w, 0px);
  transform: translateX(var(--sl-x, 0px));
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  /* Jezdec leží nad rovinou 2 a spojuje se do roviny 3 — nese proto rozdíl
     mezi nimi, tedy přesně --veil-3 (viz rovnice v :root). */
  background: var(--veil-3);
  --join-into: var(--veil-3);
  pointer-events: none;
  z-index: 0;
  transition: transform .34s cubic-bezier(.22, 1, .36, 1),
              width     .34s cubic-bezier(.22, 1, .36, 1);
}
.sub-nav:not([data-sl-ready]) .sub-slider { opacity: 0; transition: none; }
/* Než jezdec doskočí (a kdyby JS neproběhl vůbec), drží aktivní stav záložka
   sama — bez zubů, ale se správnou barvou. Žádná podnavigace bez signálu. */
.sub-nav:not([data-sl-ready]) .sub-tab.active { background: var(--veil-3); }
/* Segmentovaný filtr na konci podnavigace (Finance: Vše / S.R.O. / OSVČ) —
   zarovnaný doprava. Do 12. 9. 2026 obalový <div style="margin-left:auto">. */
.sub-nav > .gs-seg { margin-left: auto; }

.sub-tab {
  padding: 0 16px;
  /* Zaoblení jen nahoře, dole se záložka spojí s obsahem — stejné pravidlo
     jako o patro výš u .nav-tab. */
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  border: none;
  cursor: pointer;
  transition: color .18s;
  background: transparent;   /* rovinu obsahu maluje jezdec, ne záložka */
  color: var(--subnav-t);
  display: inline-flex;
  align-items: center;
  align-self: stretch;   /* doběhne na spodní hranu pruhu */
  position: relative;
  z-index: 1;            /* text nad jezdcem */
  gap: 8px;
  font-family: inherit;
  white-space: nowrap;
}

/* Zpětnou vazbu na hover nese jezdec, který pod záložku přijede — šedá vrstva
   navíc by se s ním prala. Zůstává jen ztmavení textu, stejně jako v .hd. */
.sub-tab:hover  { color: var(--t1); }
.sub-tab.active { color: var(--t1); }
/* Ikona podzáložky stojí vedle názvu (na rozdíl od .nav-tab, kde je nad ním) —
   pruh je nízký a dvě patra by se do něj nevešla. Do 14. 9. 2026 tu bylo pět
   emoji a devět záložek bez ikony; emoji navíc kreslí systémové písmo, takže
   na Windows vypadalo jinak než na macOS. */
.sub-tab .ms { --ms: var(--ms-sm); }
.sub-tab.active .ms { color: var(--nav-akcent); }

/* Klávesnicový focus ano, kroužek po kliknutí myší ne. */
.sub-tab:focus { outline: none; }
.sub-tab:focus-visible { outline: 2px solid var(--focus); outline-offset: -3px; }   /* recept sekce 65, jen dovnitř */

/* ── Rovina 3 — obsahový panel ────────────────────────────────────────────
   Plochu maluje .pl-3 (fixed, přes celé okno), takže obaly obsahu jsou
   průhledné — jinak by na sebe navrstvily druhý závoj a panel by v místě
   obsahu vysvítil oproti okrajům.

   Odsazení zůstává, mění se jen pozadí. */
body[data-page="projects"] .pv-wrap,
body[data-page="finance"]  .fin-wrap { background: transparent; }

/* Záložka Projekty žije mimo .pv-wrap (viz projects.html), ale leží pod stejnou
   podnavigací. Odsazení kopíruje .pv-wrap, aby rovina byla opticky jedna. */
body[data-page="projects"] #pv-section-projekty { background: transparent; padding: var(--pad-view) var(--pad-view-x); }

/* Do 13. 9. 2026 tu bylo ještě odbarvení .cf-slide:not(.active) — dlaždice
   cashflow byly na těchhle dvou stránkách průhledné a měl je jen rámeček.
   To byl přesně ten „prázdný box jen s linkou", kvůli kterému vznikla sekce 38;
   dlaždice jsou teď bílé jako všechno ostatní a výběr kreslí prstenec. */

/* ── 38. PLOCHA BOXU — JEDNO PRAVIDLO PRO CELOU APPKU ─────────────────────
   Zadání (Ondra, 13. 9. 2026): *„naprosto zřejmě máme u každého modulu a
   záložek zcela odlišné ty primární boxy, ve kterých jsou další boxy… musíme
   toto sjednotit. Výchozí boxy budou všechny čistě bílé, budou mít rádius
   10px a nebudou mít žádný border, budou mít jen lehký velmi světle modrý až
   bílý shadow."*

   Do té doby existovalo pět různých provedení téže věci: bílá + rámeček + stín
   (14px), bílá + rámeček bez stínu (10px), bílá + stín bez rámečku (14px),
   průhledná jen s rámečkem (odbarvovací pravidla pro Projekty/Finance/Kontakty,
   zrušená sem) a jedna karta s 12px. Vznikalo to postupně a každé nové místo
   si vybralo, co zrovna vypadalo dobře.

   Proto je plocha od teď JEN TADY a třídy si ji nenastavují samy — v jejich
   pravidlech zůstal layout a odsazení, `border`/`border-radius`/`box-shadow`
   se z nich vyndaly. Když má nový box vypadat jinak, je to výjimka
   s komentářem, ne další varianta výchozího stavu.

   Pořadí načtení: stránkové CSS se načítá PŘED tímhle souborem, takže při
   stejné specificitě vyhraje tohle pravidlo. Na vyšší specificitu (obal
   s body[data-page]) to ale nestačí — takové pravidlo by tohle přebilo,
   a přesně proto tu odbarvovací bloky zrušené jsou, ne jen přepsané.

   Nepatří sem (a je to záměr): karty kanbanu (.tk-card, .lead-card) a vnitřní
   dlaždice uvnitř boxu (.stat-card, .sub-month-card, .akt-card) — ty nejsou
   „primární box, ve kterém jsou další boxy", a jejich hrana nese význam.
   U .stat-card to bylo vyzkoušené v prohlížeči: když dostala plochu odsud,
   splynula s bílým pásem, ve kterém stojí, a z KPI byla jedna bílá plocha.

   `.vd-kpi` je pořád druhá implementace `.kpi-grid` (fixní počet sloupců přes
   .four/.six proti auto-fit) — sjednocení na jednu třídu je na jinou práci,
   tady jde jen o to, aby obě vypadaly stejně. Obě měly `border-bottom`, což
   dávalo smysl, dokud pásy stály na sobě nasucho; `.fin-subview` má dnes
   `gap: 8px`, takže z linky pod pásem byla jen linka ve vzduchu. */
.dash-card,
.dash-panel,
.tbl-wrap,
.form-card,
.profile-card,
.proj-card,
.proj-box,
.pros-data-section,
.km-card,
.sh-health-panel,
.cf-kpi-card,
.aging-panel,
.subs-panel,
.bill-panel,
.recv-panel,
.vd-contractor-wrap,
.vd-h-kpi,
.vd-kpi,
.sub-months-wrap,
.gs-time-filter {
  background: var(--surface);
  border: none;
  border-radius: var(--r);
  box-shadow: var(--sh-box);
}

/* ── 39. SHARED SETTINGS (injected on all pages) ──────────────────────────── */
/* Ikonová tlačítka v headeru — lupa (Spotlight) + ozubené kolo (Nastavení).
   Bez textu (na přání 2026-09-02), jen ikona na větší světle šedé ploše. */
/* Na světlé rovině hlavičky: bílý čtvereček s tmavou ikonou (2026-09-07). */
.hd-icon-btn {
  width: 36px; height: 36px; background: var(--hd-podlozka); color: var(--t2);
  border: none; border-radius: var(--r-ctrl); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .12s, color .12s; flex-shrink: 0;
}
.hd-icon-btn:hover { background: var(--hover); color: var(--t1); }
/* Lokální záplata z 23. 9. 2026 („ikony v Night musí být víc vidět") padla
   27. 9. 2026: Night --t2 je teď 7,5 : 1 (pristupnost-03), takže ikona je
   vidět sama a podložka --hd-podlozka má v Night vlastní tvar (night-12). */
.hd-icon-btn svg, .hd-icon-btn .ms { flex-shrink: 0; }
/* Notifikační centrum (6. 10. 2026, schválil Ondra podle §13.3 a): zvonek
   `#hd-notif` hned za timerem, panel je `.gs-popover` s řádky `.gs-pop-item`.
   Kreslí `notifikaceZvonek` (lib/jadro/html-appky.js), otevírá
   `otevriNotifikace` (settings-panel.js).
   Počet je kolečko v pravém horním rohu ikony: červené, když je něco rozbité
   (platba neprošla, workspace jen ke čtení), jinak modré. */
#hd-notif { position: relative; }
.hd-pocet {
  position: absolute; top: 2px; right: 2px; min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: var(--r-pill); background: var(--blue-plocha); color: var(--white);
  font-size: var(--fs-xs); font-weight: var(--fw-medium); line-height: 16px;
  text-align: center; font-variant-numeric: tabular-nums; pointer-events: none;
}
.hd-pocet.problem { background: var(--red); }
/* Řádek notifikace je věta, ne jméno — láme se a nezkracuje. Pod ní modře
   to, co klik udělá. */
/* Dvě třídy: `.gs-pop-item` stojí v souboru níž a jednou třídou by vyhrál. */
.gs-pop-item.hd-notif-item { align-items: flex-start; }
.gs-pop-item.hd-notif-item > .ms:first-child { margin-top: 1px; }
.gs-pop-item.hd-notif-item > .ms:first-child + span {
  white-space: normal; display: flex; flex-direction: column; gap: 2px; line-height: 1.4;
}
.hd-notif-akce { color: var(--blue); font-weight: var(--fw-medium); }
.gs-pop-item.hd-notif-item.problem > .ms:first-child { color: var(--red-txt); }
/* Přepínač Day/Night v hlavičce. Obě ikony jsou v DOM a jednu schová pár
   `.jen-day`/`.jen-night` — kdyby se glyf dosazoval JavaScriptem, problikla by
   při každém načtení ta špatná. Ukazuje se ikona toho, co klik UDĚLÁ: ve dne
   měsíc (.jen-day), v noci slunce (.jen-night). */
/* Přepnutí režimu za běhu vypne na dva snímky všechny přechody (třídu přidává
   a zase sundává `temaScript()` v server.js — tam je i proč). Krátce: Chrome
   umí přechod barvy pozadí na `color-mix()` zaseknout natrvalo, takže prvek
   s `transition: background` po přepnutí do Night drží světlé pozadí, text
   z `--t1` na něm zbělá a obsah zmizí. Není to vlastnost jedné komponenty,
   proto je to jedno pravidlo a ne oprava po jedné (CLAUDE.md §14.7).
   `!important` je tu na místě: přebíjí se jím KAŽDÝ přechod v appce. */
:root.tema-prepina, :root.tema-prepina *, :root.tema-prepina *::before,
:root.tema-prepina *::after { transition: none !important; }

/* Doprava tlačí celou skupinu `.hd-akce` (výš, sekce 34) — do 24. 9. 2026 to
   nesla lupa jako první z nich. Co na stránce stojí ZA skupinou (CTA Marketingu,
   `.hd-right` v Obchodu), už se odtlačovat nesmí, jinak by mezi nimi vznikla
   druhá mezera přes půl hlavičky. */
.hd-akce ~ .hd-action { margin-left: 0; }
.hd-akce ~ .hd-right  { margin-left: 0; }

/* ── Karta detailu Nastavení (v .modal-bento, sekce 32) ──
   Do 17. 9. 2026 panel vyjíždějící zprava přes celou výšku (vlastní fixed
   překryv); jméno třídy zůstalo, ať se nemusí přepisovat 15 panelů. */
/* Zavřená karta není display:none, ale nulová šířka — jen tak jde šířka
   animovat souběžně se zúžením okna. Cílová šířka se bere z varianty panelu
   (--karta-w); overflow: clip s okrajem nechá vidět stín karty. */
.ind-mgr-overlay {
  --karta-w: 420px;
  display: flex; flex-shrink: 0; min-width: 0; width: 0; margin-left: 0;
  overflow: clip; overflow-clip-margin: 40px;
  visibility: hidden; pointer-events: none;
  transition: width var(--bento-t), margin-left var(--bento-t), visibility 0s linear .38s;
}
.ind-mgr-overlay:has(> .ind-mgr-panel--wide),
.ind-mgr-overlay:has(> .invoicing-panel) { --karta-w: 640px; }
.ind-mgr-overlay:has(> .scraping-panel) { --karta-w: 520px; }
.ind-mgr-overlay.open {
  width: var(--karta-w); margin-left: 12px; visibility: visible; pointer-events: auto;
  transition: width var(--bento-t), margin-left var(--bento-t), visibility 0s;
}
.ind-mgr-overlay > .ind-mgr-panel {
  flex-shrink: 0; opacity: 0; transform: translateX(-16px) scale(.98); transform-origin: left center;
  transition: opacity .2s ease, transform var(--bento-t);
}
.ind-mgr-overlay.open > .ind-mgr-panel {
  opacity: 1; transform: none;
  transition: opacity .28s ease .06s, transform var(--bento-t);
}
@media (max-width: 1100px) {
  /* Vedle se nevejde — karta se přes okno jen prolne. */
  .ind-mgr-overlay, .ind-mgr-overlay.open {
    position: absolute; inset: 0; margin: 0 auto; width: auto; max-width: 880px; z-index: 2;
  }
  .ind-mgr-overlay > .ind-mgr-panel { width: 100%; transform: scale(.98); }
}
@media (prefers-reduced-motion: reduce) {
  .modal-bento > .settings-modal, .ind-mgr-overlay, .ind-mgr-overlay > .ind-mgr-panel { transition: none !important; }
}
.ind-mgr-panel {
  width: 420px; max-width: calc(100vw - 40px); height: 100%; background: var(--surface);
  border-radius: var(--r-lg); box-shadow: var(--sh-lg);
  display: flex; flex-direction: column; overflow: hidden;
}
/* Široká varianta pro seznamy s víc sloupci na řádku (Kategorie, Typy práce,
   Sloupce a Štítky tiketů). Šířka je pevná — inline `max-width` na panelu
   nic nedělá, proto varianta a ne style="". */
.ind-mgr-panel--wide { width: 640px; }

/* Scraping panel (wider) */
.scraping-panel { width: 520px; }

/* Fakturace panel (wider — vydavatel + číslování + logo + patička) */
.invoicing-panel { width: 640px; }
.scraping-toggle-row { display: flex; align-items: center; justify-content: space-between;
  padding: 12px 0; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
.scraping-toggle-label { font-size: var(--fs-md); font-weight: var(--fw-medium); color: var(--t1); }
.scraping-toggle-sub { font-size: var(--fs-xs); color: var(--t3); margin-top: 2px; }
.scraping-time-row { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.scraping-time-label { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--t2); white-space: nowrap; }
.scraping-time-input { padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--r-field);
  font-size: var(--fs-md); background: var(--bg); color: var(--t1); width: 90px; }
.scraping-job { border: 1px solid var(--border); border-radius: var(--r); padding: 14px; margin-bottom: 12px; }
.scraping-job-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.scraping-job-name-input { flex: 1; border: none; border-bottom: 1px solid var(--border);
  font-size: var(--fs-md); font-weight: var(--fw-medium); background: transparent; color: var(--t1);
  padding: 2px 0; outline: none; }
.scraping-job-name-input:focus { border-bottom-color: var(--focus); }
.scraping-job-toggle { margin-left: auto; }
.scraping-job-prompt { width: 100%; min-height: 80px; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: var(--r-sm); font-size: var(--fs-sm);
  background: var(--bg); color: var(--t1); resize: vertical; font-family: inherit;
  outline: none; line-height: 1.5; }
.scraping-job-prompt:focus { border-color: var(--focus); }
.scraping-job-count-row { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.scraping-job-count-label { font-size: var(--fs-xs); color: var(--t3); }
.scraping-job-count-input { width: 60px; padding: 4px 8px; border: 1px solid var(--border);
  border-radius: var(--r-field); font-size: var(--fs-sm); background: var(--bg); color: var(--t1); }
.scraping-job-sources { display: flex; gap: 14px; margin-top: 8px; }
.scraping-source-toggle { display: flex; align-items: center; gap: 5px; font-size: var(--fs-xs);
  color: var(--t2); cursor: pointer; user-select: none; }
.scraping-source-toggle input { cursor: pointer; accent-color: var(--blue); }
.scraping-status { font-size: var(--fs-xs); color: var(--t3); margin-top: 12px; padding-top: 12px;
  border-top: 1px solid var(--border); line-height: 1.6; }
.scraping-run-btn { padding: 7px 16px; border-radius: var(--r-ctrl); font-size: var(--fs-sm); font-weight: var(--fw-medium);
  border: none; cursor: pointer; background: var(--green-lt); color: var(--green-txt); }
.scraping-run-btn:hover { background: color-mix(in srgb, var(--green) 18%, var(--mix-bg)); }

/* Toggle switch — jeden přepínač, jedna barva „zapnuto" (vlna 3, rozhodnutí 10a;
   ds-19, pristupnost-15). Zapnutý je modrý (--blue-plocha, akční barva) ve všech
   třech podobách: tady, v .gs-toggle-row (sekce 56) i v .toggle-ikona. Do vlny 3
   byl zelený v Nastavení a v okně výkazu, modrý v okně transakce a projektu —
   stejný ovladač tak mezi okny měnil význam barvy. Zelená zůstává stavu
   „hotovo". Vypnutá dráha je hrana ovladače --border-pole (3 : 1), dřív --border
   (1,24 : 1) — vypnutý přepínač skoro nebyl vidět. Bílý jezdec má na vypnuté
   dráze 3,68 (Day) / 4,64 (Night), na zapnuté 4,85. */
.toggle-switch { position: relative; width: 38px; height: 22px; flex-shrink: 0; }
.toggle-switch input { opacity: 0; width: 0; height: 0; }
.toggle-slider { position: absolute; cursor: pointer; inset: 0; background: var(--border-pole);
  border-radius: var(--r-ctrl); transition: .2s; }
.toggle-slider:before { content: ''; position: absolute; height: 16px; width: 16px;
  left: 3px; bottom: 3px; background: var(--white); border-radius: 50%; transition: .2s;
  box-shadow: 0 1px 3px rgba(0,0,0,.2); }
.toggle-switch input:checked + .toggle-slider { background: var(--blue-plocha); }
.toggle-switch input:checked + .toggle-slider:before { transform: translateX(16px); background: var(--white); }
.toggle-switch input:focus-visible + .toggle-slider { box-shadow: 0 0 0 2px var(--focus); }
.toggle-switch input:disabled + .toggle-slider { cursor: default; opacity: .5; }

/* Toast notification */
.toast { position: fixed; bottom: 24px; right: 24px; background: var(--inv-bg); color: var(--inv-fg);
  padding: 8px 16px; border-radius: var(--r); font-size: var(--fs-md); font-weight: var(--fw-medium);
  box-shadow: var(--sh-lg); z-index: var(--z-toast); opacity: 0; transform: translateY(8px);
  transition: .25s; pointer-events: none; max-width: 320px; }
.toast.show  { opacity: 1; transform: translateY(0); }
.toast.green { background: var(--plocha-green); color: var(--white); }
.toast.blue  { background: var(--blue-plocha); color: var(--white); }
.toast.red   { background: var(--plocha-red); }

/* Toast s akcí (audit designu 2026-09, vlna 3 — shell-04, toky-07, rozhodnutí 5a).
   Skládá ho `gsToast()` v shared.js: text, volitelně tlačítko akce („Vrátit" po
   měkkém smazání, `gsSmazanoSVratit()`) a u chyby zavírací křížek. Toast sám
   dál myš nepropouští (`pointer-events: none` výš), klikat jde jen na jeho
   tlačítka — neblokuje tak nic, co leží pod ním. Tlačítka dědí barvu textu
   varianty, takže drží kontrast na tmavé i barevné ploše v Day i Night. */
.toast:has(.toast-akce, .toast-zavri) { display: flex; align-items: center; gap: 12px; }
.toast-text { flex: 1; min-width: 0; }
.toast-akce, .toast-zavri {
  pointer-events: auto; flex-shrink: 0; background: none; border: 0; padding: 4px 2px;
  color: inherit; font: inherit; font-weight: var(--fw-medium); cursor: pointer;
}
.toast-akce { text-decoration: underline; text-underline-offset: 3px; }
.toast-akce:hover { text-decoration-thickness: 2px; }
.toast-zavri { display: flex; align-items: center; opacity: .75; }
.toast-zavri:hover { opacity: 1; }
/* Schovaný toast stojí na místě s nulovou průhledností — jeho tlačítka
   nesmí zůstat v pořadí Tabu ani pod myší (klávesnice, 2. 10. 2026).
   Zmizí až po doznění toastu (.25s výš), ne v prvním snímku. */
.toast:not(.show) :is(.toast-akce, .toast-zavri) { visibility: hidden; pointer-events: none; transition: visibility 0s .25s; }
.toast-akce:focus-visible, .toast-zavri:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; border-radius: var(--r-sm); }

/* Confirmation overlay — velké centrované potvrzení důležité akce (viz showConfirm()
   v shared.js), narozdíl od drobného .toast v rohu. Grafický checkmark, ne emoji. */
.gs-confirm-overlay {
  position: fixed; inset: 0; z-index: var(--z-confirm);
  background: var(--scrim);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none;
  transition: opacity .2s;
}
.gs-confirm-overlay.show { opacity: 1; }

.gs-confirm-card {
  background: var(--surface); border-radius: var(--r-lg); box-shadow: var(--sh-lg);
  display: flex; flex-direction: column; align-items: center; gap: 20px;
  padding: 32px; max-width: 360px; text-align: center;
  transform: scale(.92); transition: transform .2s;
}
.gs-confirm-overlay.show .gs-confirm-card { transform: scale(1); }

.gs-confirm-icon {
  width: 96px; height: 96px; border-radius: 50%; background: var(--green-lt);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.gs-confirm-icon svg { width: 44px; height: 44px; stroke: var(--green-txt); }
.gs-confirm-icon .ms { --ms: 44px; color: var(--green-txt); }

.gs-confirm-title { font-size: var(--fs-2xl); font-weight: var(--fw-bold); color: var(--t1); line-height: 1.3; }
.gs-confirm-sub   { font-size: var(--fs-base); color: var(--t2); }

/* Fakturoid settings panel */
.fak-panel-overlay { position: fixed; inset: 0; background: var(--scrim); z-index: var(--z-modal-nad);
  display: none; align-items: center; justify-content: center; }
.fak-panel-overlay.open { display: flex; }
.fak-panel { background: var(--surface); border-radius: var(--r-lg); width: 420px;
  box-shadow: var(--sh-lg); overflow: hidden; }
.fak-panel-hd { display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px; border-bottom: 1px solid var(--border); }
.fak-panel-title { font-size: 15px; font-weight: var(--fw-medium); }
.fak-panel-body { padding: 20px; display: flex; flex-direction: column; gap: 16px; }
.fak-field { display: flex; flex-direction: column; gap: 4px; }
.fak-field label { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--t2);
  text-transform: uppercase; letter-spacing: .05em; }
.fak-field input { padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--r-field);
  font-size: var(--fs-md); font-family: inherit; outline: none; transition: .15s; }
.fak-field input:focus { border-color: var(--blue); }
.fak-field input[readonly] { background: var(--bg); color: var(--t2); }
/* .fak-status (řádek s výsledkem testu Fakturoidu) se smazal v integraci
   vlny 3: výsledek hlásí gsToast(), ne řádek v kartě. */
.fak-panel-ft { display: flex; gap: 8px; padding: 16px 20px; border-top: 1px solid var(--border); }

/* Industries manager panel */
.ind-mgr-head { padding: 16px 20px 16px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
.ind-mgr-head h3 { font-size: 15px; font-weight: var(--fw-medium); }
.ind-mgr-body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 16px; }
/* Pravidlo ukládání v Nastavení (audit shell-09, Ondra 7. 10. 2026; settings-panel.js
   → ulozenoTise / ulozKartu). Tiché „Uloženo" místo toastu: v hlavičce karty před
   křížkem, u popisku řádku nebo pole. Chyba formuláře stojí v kartě nad tlačítkem. */
.gs-ulozeno { display: inline-flex; align-items: center; gap: 2px; font-size: var(--fs-xs);
  font-weight: var(--fw-regular); color: var(--green-txt); text-transform: none; letter-spacing: normal; }
.ind-mgr-head > .gs-ulozeno { margin-left: auto; margin-right: 8px; }
.settings-row-label > .gs-ulozeno, .gs-label > .gs-ulozeno { margin-left: 8px; }
.fg-chyba.gs-chyba-karty { margin-bottom: 8px; }
.ind-row { display: flex; align-items: center; gap: 8px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.ind-row:last-child { border-bottom: none; }
.ind-row-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.ind-row-name { flex: 1; font-size: var(--fs-md); font-weight: var(--fw-medium); }
.ind-row-del { border: none; background: transparent; color: var(--t3); cursor: pointer;
  font-size: var(--fs-lg); padding: 2px 4px; border-radius: var(--r-ctrl); }
.ind-row-del:hover { background: var(--red-lt); color: var(--red-txt); }
.ind-add-form { display: flex; flex-direction: column; gap: 8px; padding: 16px 0 0; }
.color-grid { display: flex; gap: 8px; flex-wrap: wrap; }
.color-swatch { width: 24px; height: 24px; border-radius: 50%; cursor: pointer; padding: 0;
  border: 2px solid transparent; transition: .15s; flex-shrink: 0; }
.color-swatch.selected { border-color: var(--t1); transform: scale(1.15); }

/* ── 40. ROW HOVER — blue border glow ────────────────────────────────────────
   Přidej třídu .row-hover na jakýkoliv řádek výpisu.
   Efekt: horní + dolní modrá čára + jemný glow. */
.row-hover {
  position: relative;
  transition: box-shadow .15s, background .15s;
}
.row-hover:hover {
  /* recept B, sekce 45 */
  background: var(--blue-lt); z-index: 1;
  box-shadow: inset 0 1px 0 var(--blue), inset 0 -1px 0 var(--blue);
}

/* ── 41. LOADING SKELETON ────────────────────────────────────────────────────
   Nový primitiv 2026-09-03 — appka nemá SPA routing ani server-rendered
   data (viz CLAUDE.md), takže každý page load má krátké okno, kdy tabulky/
   KPI karty čekají na fetch. Dřív prázdné "—"/nic; teď shimmer placeholder
   ve stejném layoutu, ať obsah nenaskakuje. Použití: skeletonRows()/
   skeletonStatVal() ze shared.js vykreslí .gs-skeleton bloky, dokud
   page-specific render funkce nepřepíše skutečnými daty. */
.gs-skeleton {
  display: inline-block;
  background: linear-gradient(90deg, var(--bg) 25%, var(--border) 37%, var(--bg) 63%);
  background-size: 400% 100%;
  animation: gs-skeleton-wave 1.4s ease-in-out infinite;
  border-radius: var(--r-sm);
}
@keyframes gs-skeleton-wave {
  0%   { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

/* ── 42. UNIFIED DATA TABLE ──────────────────────────────────────────────────
   Sdílený styl pro tabulkové výpisy (projects, times, …).
   grid-template-columns NENÍ zde — každá stránka si ji nastaví sama
   přes page-specific CSS: .tbl-header, .tbl-row { grid-template-columns: … }   */

/* `min-width: 0` (18. 9. 2026): flex položka má výchozí `min-width: auto`, což
   je minimální obsah — a minimální obsah mřížky je součet stop sloupců. Přetažený
   sloupec tak výpis rozšířil přes okraj stránky a vodorovný posuvník dostalo celé
   okno, místo aby se tabulka ořízla. Vlastní mez tahu je v `gsSloupceSirkaTah()`
   (shared.js); tohle je pojistka, aby jedna špatná šířka nikdy nerozjela layout. */
.tbl-wrap {
  background: var(--surface); overflow: hidden; flex: 1; min-height: 0; min-width: 0;
  display: flex; flex-direction: column;
}
/* Záhlaví má od 16. 9. 2026 pevnou minimální výšku 48 px (Ondra) — proto uvnitř
   `align-items: center` a svislý padding pryč; výšku drží `min-height`, ne obsah.

   Bez šablony sloupců drží buňky v jednom řádku (10. 10. 2026, audit tabulek,
   nález 1). Šablonu píše `gsSloupceInit()` do `<style>` až ze skriptu stránky —
   u Prospektů a Tiketů dokonce až po načtení dat — a do té doby byla mřížka
   bez sloupců: každá buňka vlastní řádek, záhlaví Výkazů 245 px místo 48.
   `grid-auto-flow: column` dá každé buňce vlastní implicitní stopu, takže se
   výpis rozpadnout nemůže; jakmile šablona dorazí, platí ona. Stránka, která
   chce buňky vědomě zalamovat do řádků (Admin na úzkém okně), si napíše
   `grid-auto-flow: row` sama. */
.tbl-header {
  display: grid; gap: 8px 16px; padding: 0 16px; min-height: 48px; align-items: center;
  grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  border-bottom: 1px solid var(--border); border-image: var(--linka-vodor) 1;
  font-size: var(--fs-xs); font-weight: var(--fw-medium); text-transform: uppercase; letter-spacing: .07em;
  color: var(--t3); flex-shrink: 0; background: var(--surface);
  position: sticky; top: 0; z-index: 2;
}
/* Roh tabulky drží tvar i tam, kde se neořezává (26. 9. 2026). `.tbl-wrap` má
   `overflow: hidden`, jenže Projekty ho vypínají, aby rolovala celá sekce
   a lepivá hlavička se chytala jí (`projects.css`). Ořez tím přestal platit
   a neprůhledné záhlaví přemalovalo zaoblené horní rohy do pravého úhlu —
   Ondra to nahlásil jako „tabulka nemá rádius". Tvar proto nese i záhlaví
   a poslední řádek, ne jen obal: pojistka místo spoléhání na to, že si žádná
   stránka `overflow` nevypne (CLAUDE.md §14.7).
   `:first-child`/`:last-child` proto, že pod tabulkou může stát stránkování —
   tam poslední řádek koncem tabulky není. */
.tbl-wrap > .tbl-header:first-child { border-radius: var(--r) var(--r) 0 0; }
.tbl-wrap > .tbl-body-wrap:last-child > .tbl-row:last-child { border-radius: 0 0 var(--r) var(--r); }

/* Optický střed popisků — táž náprava metriky písma jako
   u ovladačů filtrační lišty: odsazení shora o `--tx-center`, zdola nula (viz
   komentář u tokenu v :root). Padding nesmí být na `.tbl-header`, protože ten
   nese `min-height` a `align-items` — musí být na buňkách, aby se posunul jen
   text. Řadicí tlačítko posun dědí i se svou šipkou: šipka patří k popisku
   a má se hýbat s ním. Výjimka je „+" na skládání sloupců — je to ikona, ne
   text, a navíc se táhne přes celou výšku záhlaví. */
.tbl-header > *:not(.gs-sloupce-btn) {
  padding-top: var(--tx-center);
  /* Šířku sloupce si od 16. 9. 2026 může člověk přetáhnout, takže popisek musí
     umět být užší, než je sám: bez `min-width: 0` by grid stopu sice udržel,
     ale text by z buňky vytekl přes sousedy. */
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Záhlaví se dá chytit myší za dvě věci (16. 9. 2026, Ondra podle Toggle:
   *„dalo by se nastavovat i šířka sloupce? Oni to indikují tou fialovou linkou…
   + mají možnost přesouvat sloupce, tedy nejen v tom tabu"*): za HRANU sloupce
   se mění jeho šířka, za BUŇKU jeho pořadí. Obojí ukazuje táž modrá čára —
   nikdy se nedějí naráz. Je jedna na hlavičku a stojí až za všemi buňkami
   i za „+", protože `:nth-child` pravidla, kterými se sloupce schovávají,
   počítají všechny děti hlavičky. */
.gs-hd-cara {
  /* `-4.5px` = půl šířky: střed úchytu (a jeho modré čáry) je přesně na `left`,
     který shared.js staví doprostřed mezery na linku sloupce. */
  position: absolute; top: 0; bottom: 0; width: 9px; margin-left: -4.5px;
  z-index: 3; cursor: col-resize;
}
.gs-hd-cara::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: 50%; width: 2px;
  transform: translateX(-50%); border-radius: 1px; background: var(--blue);
  box-shadow: 0 0 6px color-mix(in srgb, var(--blue) 70%, transparent);
}
/* Při přesunu sloupce je čára jen značka — kdyby brala myš, `dragover` by
   místo buňky pod ní dostával ji a cíl by se přestal počítat. */
.tbl-header.gs-hd-tahne .gs-hd-cara { pointer-events: none; }
.tbl-header .gs-hd-zdroj { opacity: .4; }
/* Kurzor musí po dobu tahu držet celá stránka: myš úchyt při rychlém pohybu
   předběhne a nad textem by se přepnul na `text`. `!important` proto, že
   přebíjí kurzory prvků, přes které se zrovna táhne. */
body.gs-meni-sirku, body.gs-meni-sirku * { cursor: col-resize !important; user-select: none; }
.tbl-body-wrap { flex: 1; overflow-y: auto; min-height: 0; scrollbar-gutter: stable; }
/* Záhlaví nad rolujícím tělem drží tutéž mezeru na posuvník (8. 10. 2026,
   Ondra: „linky sloupců v nadpisech nejsou srovnané s linkami sloupců").
   Posuvník (5 px, `::-webkit-scrollbar`) bral místo jen tělu, takže pružný
   sloupec (`1fr`) byl v těle o 5 px užší a všechny linky za ním ujely
   doleva. `stable` na obou = mezera je vždycky, i když tělo neroluje — jinak
   by se linky posouvaly podle počtu řádků. Kde tělo nerole (`overflow:
   visible` v Projektech a na nízkém okně), musí se vypnout i tady. */
.tbl-wrap:has(> .tbl-body-wrap) > .tbl-header { overflow-y: hidden; scrollbar-gutter: stable; }
.tbl-row {
  display: grid; gap: 8px 16px; padding: 2px 16px; min-height: 44px;
  /* Tatáž pojistka jako u záhlaví: bez šablony sloupců se řádek (i kostra
     načítání v HTML) nerozpadne do sloupce. */
  grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  /* Písmo řádku je písmo buňky (10. 10. 2026, audit tabulek, nález 5). Výpisy
     Financí (transakce, faktury) mají buňky jako holé `<span>` bez `.tbl-cell`,
     takže braly 14 px ze stránky, zatímco ostatní tabulky 13 px. Velikost nese
     řádek a buňka ji jen opakuje — kdo zapomene třídu, nedostane jiné písmo. */
  font-size: var(--fs-md);
  /* Linka pod řádkem slábne do stran (`--linka-vodor`, jako KPI pás) —
     29. 9. 2026, návrh „Výpis bez výplně". `border-image` místo pozadí, aby
     podklad hoveru ani `.checked` linku nepřemazal. Mezera sloupců 16 px nese
     svislé linky mezi sloupci, viz blok pod `.tbl-cell`. */
  border-bottom: 1px solid var(--border); border-image: var(--linka-vodor) 1; align-items: center;
  position: relative; transition: background .15s; cursor: default;
  /* Vstupy záře za kurzorem — viz blok pod hoverem. */
  --gx: 50%; --zar: 0;
}
/* Týž řádek mimo tabulku: `.gs-radek-zare` nese jen chování (hover, záře),
   ne mřížku ani linku pod sebou. Vznikla 26. 9. 2026 pro seznam kontaktů —
   Ondra přes Vercel toolbar: *„je to seznam, takže ten seznam by měl mít
   stejný hover efekt jako například výpis v tabulkách."* Opsat recept do
   `contacts.css` by znamenalo druhou implementaci, která se rozejde (§13.2),
   takže se rozšířil selektor. Kdo třídu přidá na nový prvek, dostane hover
   i záři; polohu kurzoru píše `akce.js` podle `ZARE_SEL`. */
.gs-radek-zare {
  position: relative; transition: background .15s;
  --gx: 50%; --zar: 0;
}
.tbl-row:last-child { border-bottom: none; }
.tbl-row:hover,
.gs-radek-zare:hover {
  /* Recept B, sekce 45 — jen s tím rozdílem, že linku nekreslí `box-shadow`,
     ale gradient v `::after`. Plná modrá linka tady byla do 26. 9. 2026
     a spolu se září dělala dvě věci najednou (Ondra: „nebude zvlášť glow
     gradient a zvlášť linka, myslel jsem, že linka bude sama o sobě
     gradient"). Podklad je od 29. 9. 2026 `--blue-hover` (den 5 %, noc 10 %
     modré), ne `--blue-lt`: ve dne byl hover stejný jako vybraný řádek. */
  background: var(--blue-hover); z-index: 1;
  --zar: 1;
}
.tbl-row.clickable { cursor: pointer; }
/* Vybraný řádek (hromadný výběr, vlna 3 — vzory-09). Do vlny 3 si ho psaly
   times.css a finance.css každý zvlášť; stránková kopie se v integraci maže.
   Stav, ne hover — proto podklad bez záře. */
.tbl-row.checked { background: var(--blue-lt); }

/* Záře řádku za kurzorem (24. 9. 2026, Ondra: „chtěl bych, aby podobný
   gradient efekt, který sleduje kurzor, byl i na řádcích tabulek").
   Přepracováno 26. 9. 2026 podle druhého zadání: „nebude zvlášť glow gradient
   a zvlášť linka, myslel jsem, že linka bude sama o sobě gradient… a ten glow
   bude mírnější a nebude clipnutý, bude vidět trochu overflow i nad řádkem."

   **Linka JE gradient.** Do 26. 9. 2026 kreslil `.tbl-row:hover` plnou modrou
   linku `box-shadow: inset …` a záře k ní jen přisvěcovala v místě kurzoru —
   byly to dvě vrstvy, které dělaly jednu věc, a plná linka tu proměnlivou
   přebíjela. Dnes je linka jediná: po celé šířce slabá modrá, pod kurzorem
   plná `--blue-txt`. Podklad `--blue-lt` a význam modré (= ukazatel myši)
   z receptu B (sekce 45) zůstávají.

   U tlačítka (sekce 14) svítí okraj dokola, u řádku jen vodorovně. Řádek je
   široký a nízký; kroužek kolem kurzoru by na něm nebyl k poznání a svislá
   složka by jen rozmazala linku.

   Polohu píše týž posluchač v `akce.js` jako u tlačítek (`ZARE_SEL`), proto se
   proměnná jmenuje stejně `--gx`. `--gy` řádek nepoužívá. Pozor: `--gx` se dědí,
   takže jeho změna přepočítá styl všech buněk řádku — proto se zapisuje jen na
   jeden řádek pod kurzorem, ne na tabulku.

   Dvě vrstvy, obě na pseudoprvcích, aby se do receptu B nemuselo sahat:
     ::before  záře kolem jasného místa. Box je o 10 px vyšší než řádek
               (`inset: -10px 0`) a elipsy mají střed na hranách řádku, takže
               světlo přeteče kousek nad něj a pod něj — to je ten „overflow",
               o který šlo. Přetečení unese `z-index: 1` na hoveru: svítí
               přes sousední řádek, ne pod ním. Mírnější je 20 % místo 35 %.
     ::after   samotná linka — gradient v pruhu vysokém 1 px, takže slábne jen
               do stran. Střed `--blue-txt` (modrá určená NA modrý podklad),
               konce 30% modrá, aby linka nikde nezmizela.

   Rozsvěcí se přes `--zar` na řádku, ne přes `opacity` v `:hover::after`.
   `opacity` na `.tbl-row` už nastavuje Sales (`crm.css`, `.status-converted`)
   a kontrola přebitých hoverů v `test/hover.test.js` pseudoprvek od prvku
   nerozliší — vlastní proměnná ty dva světy nemíchá. Hlídá
   `test/radek-zare.test.js`. */
.tbl-row::before,
.tbl-row::after,
.gs-radek-zare::before,
.gs-radek-zare::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  opacity: var(--zar); transition: opacity .15s;
}
.tbl-row::before,
.gs-radek-zare::before {
  inset: -10px 0;
  background:
    radial-gradient(ellipse 200px 10px at var(--gx) 10px,             var(--radek-zare), transparent),
    radial-gradient(ellipse 200px 10px at var(--gx) calc(100% - 10px), var(--radek-zare), transparent);
}
/* Poslední řádek nesmí přetéct dolů: v rolovacím `.tbl-body-wrap` dělalo
   neviditelných 10 px záře posuvník, i když se všechny řádky vešly (Tikety →
   Seznam, kolo testování 13. 10. 2026). Spodní elipsa má proto střed přímo
   na hraně a pod ní se ořízne. */
.tbl-row:last-child::before {
  bottom: 0;
  background:
    radial-gradient(ellipse 200px 10px at var(--gx) 10px,   var(--radek-zare), transparent),
    radial-gradient(ellipse 200px 10px at var(--gx) 100%,   var(--radek-zare), transparent);
}
.tbl-row::after,
.gs-radek-zare::after {
  background-repeat: no-repeat;
  background-position: top, bottom;
  background-size: 100% 1px;
  background-image:
    radial-gradient(circle 260px at var(--gx) 50%, var(--blue-txt) 0 22px, color-mix(in srgb, var(--blue) 30%, transparent) 100%),
    radial-gradient(circle 260px at var(--gx) 50%, var(--blue-txt) 0 22px, color-mix(in srgb, var(--blue) 30%, transparent) 100%);
}
/* Záře karty za kurzorem (návrh „Tikety — karta a detail", 12. 10. 2026).
   Týž recept jako tlačítko (sekce 14) — prstenec v `::before`, rozmazaná záře
   v `::after`, obojí maskované na okraj — jen s většími kruhy a s prstencem z rámečku místo paddingu (celé pixely tu stačí a mezery drží škálu), protože karta
   je velká plocha a 53px kroužek tlačítka by se na ní ztratil. Karta si drží
   vlastní okraj a stín; záře jen přisvěcuje okraj u kurzoru. Polohu píše
   `akce.js` podle `ZARE_SEL`. Karta nesmí mít `overflow: hidden`, jinak
   záři přes okraj uřízne. Čte: tickety.js (tkKartaHtml),
   test/zare-selektory.test.js. */
.gs-karta-zare { --gx: 50%; --gy: 50%; isolation: isolate; }
.gs-karta-zare::before,
.gs-karta-zare::after {
  content: '';
  position: absolute;
  z-index: -1;
  inset: -1px;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity .25s;
  -webkit-mask: linear-gradient(black 0 0) content-box, linear-gradient(black 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0);
}
.gs-karta-zare::before {
  border: 1px solid transparent;
  background: border-box radial-gradient(circle 170px at var(--gx) var(--gy), var(--blue) 0 36px, transparent);
}
.gs-karta-zare::after {
  inset: -1.5px;
  border: 2px solid transparent;
  filter: blur(3px);
  background:
    border-box radial-gradient(circle 60px at var(--gx) var(--gy), var(--blue) 0 14px, transparent),
    border-box radial-gradient(circle 180px at var(--gx) var(--gy), color-mix(in srgb, var(--blue) 55%, transparent) 0 30px, transparent);
}
.gs-karta-zare:hover::before,
.gs-karta-zare:hover::after { opacity: 1; }
.tbl-cell {
  font-size: var(--fs-md); color: var(--t1); min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}
/* Svislé linky mezi sloupci (29. 9. 2026, návrh „Výpis bez výplně", Ondra:
   „linky souvislé"). Jedna čára přes celou tabulku: v záhlaví se rozsvítí,
   přes řádky jde plná `--linka`, v posledním řádku zhasne — tentýž gradient
   jako `--linka-svisla` v KPI pásu, jen roztažený na celou tabulku.

   Kreslí ji `::before` buňky, ale jeho rámec je ŘÁDEK, ne buňka: buňka nemá
   `position`, takže absolutní pseudoprvek se měří k `.tbl-row`/`.tbl-header`
   a `overflow: hidden` buňky (trojtečka) ho neořízne. Vodorovně stojí na
   své statické poloze (levý okraj buňky) a `margin-left` ho posune doprostřed
   mezery 16 px. Výšku dává `top`/`bottom` vůči řádku.
   `display: block` je nutné: statickou polohu počítá prohlížeč podle původního
   (řádkového) `display`, takže v buňce `.right` by čára ujela na pravý okraj.
   Bez čáry: první sloupec, akce (`.tbl-acts` je flex zarovnaný doprava, statická
   poloha by ujela na pravý okraj), „+" skládání sloupců (má vlastní linku)
   a tlačítko přímo v mřížce — jeho `::before` je tělo záře (sekce 14).
   Stránka, která řádku přepíše `gap`, posune čáru ze středu: mezera sloupců
   má zůstat 16 px (proto `crm.css` u nabídek `gap` už nepíše). */
:is(.tbl-header, .tbl-row) > :not(:first-child, .tbl-acts, .gs-sloupce-btn, button, .ico-btn)::before {
  content: ''; display: block; position: absolute; width: 1px; margin-left: -8.5px;
  top: 0; bottom: -1px; background: var(--linka); pointer-events: none;
}
.tbl-header > :not(:first-child, .tbl-acts, .gs-sloupce-btn, button, .ico-btn)::before { top: 8px; background: linear-gradient(transparent, var(--linka)); }
.tbl-row:last-child > :not(:first-child, .tbl-acts, .gs-sloupce-btn, button, .ico-btn)::before { bottom: 6px; background: linear-gradient(var(--linka) 30%, transparent); }
.tbl-cell.muted    { color: var(--t2); }
.tbl-cell.bold     { font-weight: var(--fw-medium); }
.tbl-cell.right    { text-align: right; }
/* Číslo stojí vpravo i v záhlaví (10. 10. 2026, audit tabulek, nálezy 3 a 4):
   popisek sloupce s částkou, hodinami nebo počtem dostane `.right` stejně jako
   buňky pod ním. Tlačítko řazení je `inline-flex`, takže ho zarovná `text-align`
   buňky — žádné `width: 100%; justify-content: flex-end` v každé stránce zvlášť
   (tak to do té doby dělaly Finance třikrát jinak). */
.tbl-header > .right { text-align: right; }
.tbl-cell.center   { text-align: center; }
.tbl-cell.badge-cell { overflow: visible; padding: 2px 0; }
.tbl-cell.stack    { white-space: normal; line-height: 1.1; overflow: visible; }
/* Hlavní a vedlejší řádek buňky jsou každý jedna linka s trojtečkou (10. 10. 2026):
   `.stack` povolí zalomení buňce, ale název projektu nebo poznámka se v ní má
   oříznout, ne rozlít do třetího řádku — Výkazy to do té doby psaly inline. */
.tbl-cell-main     { font-size: var(--fs-md); font-weight: var(--fw-medium); color: var(--t1); }
.tbl-cell-sub      { font-size: var(--fs-xs); color: var(--t3); margin-top: 2px; }
.tbl-cell-main, .tbl-cell-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Nevyplněná hodnota (Ondra 26. 9. 2026: „pomlčky u nevyplněných informací
   budou uprostřed a budou menší nebo kratší"). Prázdno je stav, ne hodnota —
   proto se nezarovnává se sloupcem, ale stojí na středu buňky a je ztlumené.
   `display: block` s `text-align: center` přebije zarovnání sloupce
   (`.tbl-cell.right`), aniž by se na to muselo myslet u každého sloupce
   zvlášť. Píše se výhradně přes `prazdno()` v shared.js, aby byl znak
   i vzhled na jednom místě; uvnitř věty se pomlčka necentruje. */
.gs-prazdno { display: block; text-align: center; color: var(--t3); }
/* `.tbl-empty` (holá věta uprostřed výpisu) zanikla 10. 10. 2026: prázdný i chybový
   stav výpisu kreslí `.gs-stav` (sekce níž, `gsStav()` v shared.js); Admin byl
   poslední, kdo ji ještě psal. */
.tbl-acts          { display: flex; gap: 4px; justify-content: flex-end; }
/* Indikátor přílohy v řádku — spona vede na uložený doklad (PDF ve storage).
   Sloupec si stránka přidá do svého grid-template-columns; když příloha není,
   buňka zůstane prázdná (mřížka drží zarovnání sama, prázdný stav se nekreslí).
   Klik musí volat stopPropagation — řádek pod ním typicky otevírá detail. */
.row-attach {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: var(--r-sm);
  color: var(--t3); flex-shrink: 0; transition: background .12s, color .12s;
}
.row-attach:hover { background: var(--hover); color: var(--blue); }
.tbl-header .gs-sort-btn {
  color: var(--t3); font-size: var(--fs-xs); font-weight: var(--fw-medium);
  text-transform: uppercase; letter-spacing: .07em;
  /* Bez tohohle tlačítko svou šířku ubránit umí a z úzkého sloupce vyteče.
     Ořez pak dělá `overflow: hidden` buňky — natvrdo, bez tří teček, takže
     popisek končí v půlce písmene a nevypadá jako zkrácený, ale jako rozbitý. */
  max-width: 100%; min-width: 0;
}
/* Popisek je v tlačítku všechno kromě šipky řazení. V HTML už spanem obalený je
   (`<span data-i18n=…>`), ve Finance se doplnil 16. 9. 2026 — jinak by textový
   uzel skončil v anonymním flex boxu, na který `text-overflow` nedosáhne.
   Ořez patří sem, ne na tlačítko: ve flexu se ořezává položka, ne kontejner,
   a šipka má `flex-shrink: 0`, takže mizí popisek a indikace řazení zůstává. */
.tbl-header .gs-sort-btn > span:not(.gs-sort-arrow) {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tbl-header .gs-sort-btn:hover { color: var(--t1); }
/* Sloupec, podle kterého se řadí, je tmavší — ať je na první pohled vidět,
   podle čeho tabulka jede. Do 16. 9. 2026 to stejné pravidlo měly Finance
   třikrát ve vlastním CSS (`#tx-tbl-body`, `.tx-grp-hd`, `.vd-tbl-hd`). */
.tbl-header .gs-sort-btn.asc,
.tbl-header .gs-sort-btn.desc { color: var(--t1); }

/* „+" na konci záhlaví — kterým si člověk skládá sloupce (16. 9. 2026, Ondra:
   *„jako to má Toggl… v tom záhlaví tabulky je tlačítko, kterým se dá přidat
   sloupec"*). Vkládá ho `gsSloupceTlacitko()` v shared.js, ne stránka, a stopu
   pro něj si mřížka přidává sama — proto tady žádná šířka není, jen tvar.
   Svislá linka ho odděluje od posledního sloupce; `order` ho drží na konci
   i ve chvíli, kdy jsou sloupce přeskládané. */
.gs-sloupce-btn {
  order: 999; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; padding: 0; border: none; border-radius: 0;
  /* Linka odděluje tlačítko od posledního sloupce a musí jít přes celou výšku
     záhlaví — proto `stretch`. Záhlaví od 16. 9. 2026 svislý padding nemá,
     takže ho tady není co rušit. */
  align-self: stretch; border-left: 1px solid var(--border);
  background: none; color: var(--t3); cursor: pointer; transition: color .12s;
}
.gs-sloupce-btn:hover { color: var(--t1); }
.gs-sloupce-btn:focus-visible { outline: none; color: var(--blue); box-shadow: inset 0 0 0 2px var(--focus); }

/* Přeskládatelná nabídka: zaškrtávátko vlevo, úchyt vpravo. Sdílí ji nabídka
   sloupců (`gsSloupceNabidka()`) a nabídka bloků dashboardu (`gsBlokyNabidka()`,
   19. 9. 2026) — proto se třídy od té doby jmenují `gs-poradi-*` a ne
   `gs-sloupec-*`: je to jedna mechanika, ne dvě podobné.
   Řádek NENÍ `<label>` jako u ostatních zaškrtávacích nabídek — úchyt uvnitř
   popisku by se tahem choval jako klik na checkbox, takže popisek je vlastní
   `<label>` uvnitř řádku a úchyt stojí vedle něj.
   `.gs-tahne` je řádek, který se zrovna táhne; `draggable` se zapíná až stiskem
   na úchytu, aby tažení nešlo spustit omylem přes text. */
.gs-poradi-radek { cursor: default; position: relative; }
.gs-poradi-radek > .gs-cb { flex: 1; min-width: 0; font-size: var(--fs-sm); }
.gs-poradi-radek > .gs-cb > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gs-poradi-uchyt { --ms: var(--ms-sm); color: var(--t3); cursor: grab; flex-shrink: 0;
  display: inline-flex; padding: 0; border: 0; background: none; border-radius: var(--r-sm); }   /* tlačítko: šipky posouvají (klávesnice) */
.gs-poradi-uchyt:active { cursor: grabbing; }
/* Tažený řádek zůstává na svém místě a jen zesvětlá — říká *odkud* se táhne.
   Kam se pustí, říká modrá čára níž. Do 16. 9. 2026 se seznam přeskládával
   živě pod kurzorem a čára nebyla žádná (Ondra: *„není lepší to indikovat
   čárou, aby to bylo více UX friendly?"*). */
.gs-poradi-radek.gs-tahne { opacity: .4; }
/* Po dobu tažení se `:hover` celého seznamu vypíná. Prohlížeč ho totiž nechá
   viset na řádku, který se ocitne pod kurzorem, takže šedě svítil úplně jiný
   sloupec, než kam se táhlo — přesně to Ondra hlásil. */
.gs-poradi-list.gs-tahne-list .gs-pop-item:hover { background: none; }
/* Čára cíle leží v mezeře MEZI řádky (`.gs-pop-list` má gap 1px), ne uvnitř
   řádku — uvnitř by vypadala jako podtržení, ne jako místo vložení.
   `pointer-events: none`, aby nebrala `dragover` řádku pod sebou. */
.gs-poradi-radek.gs-cil-nad::after,
.gs-poradi-radek.gs-cil-pod::after {
  content: ''; position: absolute; left: 0; right: 0; height: 2px;
  background: var(--blue); border-radius: 1px; pointer-events: none;
}
.gs-poradi-radek.gs-cil-nad::after { top: -1px; }
.gs-poradi-radek.gs-cil-pod::after { bottom: -1px; }

/* Shared inline tags */
.type-tag {
  display: inline-block; font-size: var(--fs-xs); font-weight: var(--fw-medium); padding: 2px 8px;
  border-radius: var(--r-pill); background: var(--bg); color: var(--t2);
}
/* Pill v buňce tabulky je široký podle textu, ne podle sloupce. Od 16. 9. 2026
   jde šířka sloupce měnit tahem, takže tohle musí platit v obou směrech:
   v širokém sloupci pill neroste, v úzkém se ořízne třemi tečkami místo přetečení.
   `inline-block` je tu nutné podmínka obojího — `block` by pozadí roztáhl přes
   celou buňku (přesně tak to vypadalo v Projektech, viz projects.css ř. 42),
   holý `inline` zas neumí `text-overflow`. Selektor je schválně přímý potomek.
   Stavový štítek .gs-chip (vlna 3, dřív .pay-badge) se ořezává sám
   (max-width a .gs-chip-text, sekce 52), proto tu už není. */
.tbl-cell > .type-tag {
  display: inline-block; vertical-align: middle;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Malá tabulka `.gs-tabulka` (10. 10. 2026, audit tabulek, skupina D).
   Pět míst mělo každé svůj `<table>`: sazby a měsíční přehled hodin dodavatele
   (.vd-rate-table, .vd-h-hist table), alokace v projektu (.alloc-table),
   protokol importu (.tbl bez jediného pravidla, vzhled prohlížeče) a měsíční
   matice (.matrix-tbl). Tohle je společný základ: popisek sloupce jako
   v .tbl-header (fs-xs, verzálky, t3), buňka 8 px, dělicí linka, poslední
   řádek bez ní, součet v <tfoot> za silnější linkou. Čísla dostanou `.right`
   (tabular-nums), tlumený text `.muted` — stejná jména jako u .tbl-cell,
   scopovaná sem, aby se obě sady nepletly. Co chce stránka navíc (matice:
   přilepený první sloupec, barvy řádků), píše s dvojitou třídou
   `.gs-tabulka.matrix-tbl`: DS se načítá až za stránkovým CSS a shodnou váhu
   by přebil. Výpis s volbou sloupců a řazením je dál `.tbl-*` (výš). */
.gs-tabulka { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.gs-tabulka th {
  font-size: var(--fs-xs); font-weight: var(--fw-medium); text-transform: uppercase;
  letter-spacing: .06em; color: var(--t3); padding: 4px 8px 8px; text-align: left;
  white-space: nowrap; border-bottom: 1px solid var(--border);
}
.gs-tabulka td { padding: 8px; border-bottom: 1px solid var(--border); color: var(--t1); vertical-align: middle; }
.gs-tabulka tbody tr:last-child td { border-bottom: none; }
.gs-tabulka tfoot td { border-top: 1px solid var(--border-md); border-bottom: none; font-weight: var(--fw-medium); }
.gs-tabulka .right { text-align: right; font-variant-numeric: tabular-nums; }
.gs-tabulka .muted { color: var(--t2); }

/* ── 43. KPI DETAIL MODAL ────────────────────────────────────────────────────
   Sdílený plovoucí modal pro detail KPI karet.
   Použití: přidej třídu .open na .kpi-modal-overlay */
.kpi-modal-overlay{position:fixed;inset:0;z-index:var(--z-modal-nad);background:var(--scrim);display:none;align-items:center;justify-content:center}
.kpi-modal-overlay.open{display:flex}
.kpi-modal{background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--sh-lg);width:min(520px,calc(100vw - 32px));max-height:78vh;display:flex;flex-direction:column;overflow:hidden}
.kpi-modal-hd{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--border);flex-shrink:0}
.kpi-modal-title{font-size:15px;font-weight:var(--fw-medium);color:var(--t1)}
.kpi-modal-body{flex:1;overflow-y:auto;padding:8px 16px;display:flex;flex-direction:column;gap:4px}
/* Plátno jako u .modal-body (sekce 25, D6 13. 9. 2026): šedé tělo, řádky .kpi-rank-row jako bílé karty bez viditelného rámečku. */
.kpi-modal-body{background:var(--bg-2)}
.kpi-modal-body .kpi-rank-row{border-color:var(--surface)}
.kpi-modal-empty{padding:32px;text-align:center;color:var(--t3);font-size:var(--fs-md)}
.kpi-modal-total{padding:8px 16px;border-top:1px solid var(--border);font-size:var(--fs-md);font-weight:var(--fw-medium);color:var(--t1);display:flex;justify-content:space-between;flex-shrink:0}

/* ── 44. KPI RANK ROW ────────────────────────────────────────────────────────
   Box-styl řádek pro výpisy v modalech i panelech. Blue glow hover. */
.kpi-rank-row{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:var(--r-sm);border:1px solid var(--border);background:var(--surface)}
.kpi-rank-row.clickable{cursor:pointer;transition:background .15s,border-color .15s}
.kpi-rank-row.clickable:hover{background:var(--blue-lt);border-color:var(--blue)}  /* recept A, sekce 45 */
.kpi-rank-name{flex:1;font-size:var(--fs-md);font-weight:var(--fw-medium);color:var(--t1);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kpi-rank-telo{flex:1;min-width:0}   /* název + podřádek vedle pořadí a částky; čte projects.js (KPI okna) */
.kpi-rank-name > span + span{font-weight:var(--fw-regular);color:var(--t3);margin-left:4px}   /* doplněk za názvem (projekt za klientem), viz .gs-s-doplnkem */
.kpi-rank-sub{font-size:var(--fs-xs);color:var(--t3);margin-top:2px}
.kpi-rank-num{width:22px;text-align:center;font-size:var(--fs-sm);font-weight:var(--fw-medium);color:var(--t3);flex-shrink:0}
.kpi-rank-num.gold{color:var(--rank-gold)}
/* Pruh podílu vedle částky (Finance: žebříčky předplatných a subdodavatelů,
   Výkazy: rozpad nákladů po lidech) je .gs-dash-pruh.v-radku (sekce 59) —
   do 30. 9. 2026 vlastní zelený .kpi-rank-bar, 4 px (jazyk-17). */
.kpi-rank-row .gs-dash-pruh{width:70px}
.kpi-rank-amt{font-size:var(--fs-md);font-weight:var(--fw-medium);flex-shrink:0;white-space:nowrap}
.kpi-rank-amt.green{color:var(--green-txt)}.kpi-rank-amt.red{color:var(--red-txt)}
.kpi-rank-amt.amber{color: var(--amber-txt)}.kpi-rank-amt.blue{color:var(--blue)}

/* ── 45. HOVER — jak vypadá „na tohle se dá kliknout" (15. 9. 2026) ─────────
   Do 15. 9. 2026 měla appka osm různých hoverů na jednu a tu samou věc:
   .kpi-clickable, .kpi-rank-row.clickable, .lead-card, .recv-row, .bill-row,
   .tx-group-hdr, .tx-sub-row, .cf-slide. Lišily se rámečkem, prstencem, září,
   nadzvednutím i natvrdo psanými stíny. Od 15. 9. 2026 jsou RECEPTY TŘI a víc
   jich nepřibývá — kdo potřebuje čtvrtý, mění tuhle sekci, ne svoji stránku.
   Hlídá test/hover.test.js.

   A — box s rámečkem (.kpi-clickable): podklad zmodrá, rámeček zmodrá. Nic víc.
       Prstenec `0 0 0 1px var(--blue)` VEDLE `border-color` se sčítal do 2px
       obruby a to je řeč FOKUSU, ne hoveru; `translateY` posouval text.
   B — řádek bez rámečku (.tbl-row, .gs-dash-radek.clickable, .tx-*): rámeček
       nemá, takže ho zastoupí modrá linka nahoře a dole. `inset`, ne vnější
       stín — ten přetékal na sousední řádek. Výjimka je `.tbl-row`, viz níž.
   C — plovoucí karta bez modré (.sub-month-card, .pw-step-card, .tk-card):
       jen --sh-md. Používá se tam, kde je modrá vyhrazená jinému významu
       (vybraný měsíc, stav kroku, priorita tiketu) — a je to JMENNÝ SEZNAM
       v test/hover.test.js, ne volná výjimka. `.cf-slide` z Projektů tu stál
       do 19. 9. 2026 neprávem: modrou zabranou neměl (výběr svítil amber)
       a jeho výběr nic neovládal.

   Modrá tu vždycky znamená TOTÉŽ: ukazatel myši. Vybráno/aktivní se kreslí
   plnou barvou, fokus prstencem --focus. Tři různé věci, tři různé signály.

   24. 9. 2026: recept B má u `.tbl-row` navíc záři za kurzorem — linka v místě
   myši zesílí a rozzáří se do řádku (sekce 42, blok „Záře řádku za kurzorem").
   26. 9. 2026 se ta záře a linka slily v jedno: u `.tbl-row` linku nekreslí
   `box-shadow`, ale gradient, který je po celé šířce slabý a pod kurzorem
   plný. **Je to pořád recept B** — podklad `--blue-lt`, linka nahoře a dole,
   modrá = ukazatel myši; mění se jen to, ČÍM je linka nakreslená, protože
   plná linka a proměnlivá záře přes sebe dělaly jednu věc dvakrát. Ostatní
   komponenty receptu B (`.row-hover`) mají dál plnou linku
   `box-shadow: inset …`. `.gs-dash-radek.clickable` ji měl do 12. 10. 2026,
   dnes nese `.gs-radek-zare` jako výpis (Ondra: „stejný styl z DS"). */
.kpi-clickable{cursor:pointer;transition:background .15s,border-color .15s}
.kpi-clickable:hover{background:var(--blue-lt);border-color:var(--blue)}

/* Pagination */
.tbl-pagination { display: flex; align-items: center; justify-content: center; gap: 8px; flex-shrink: 0; padding: 4px 0; }
/* Šipky jsou ikony (vzory-20, 1. 10. 2026), proto inline-flex. */
.tbl-page-btn {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 5px 16px; border: 1px solid var(--border); border-radius: var(--r-ctrl);
  background: var(--surface); font-size: var(--fs-md); color: var(--t2); cursor: pointer; transition: .15s;
}
.tbl-page-btn:hover:not(:disabled) { background: var(--hover); color: var(--t1); }
.tbl-page-btn:disabled { opacity: .4; cursor: default; }
.tbl-page-info { font-size: var(--fs-md); color: var(--t2); }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 46 — gs-switcher (segmented pill control)
   ──────────────────────────────────────────────────────────────────
   Použití:
   <div class="gs-switcher">
     <button class="gs-sw-btn active" onclick="...">Billable</button>
     <button class="gs-sw-btn" onclick="...">Nebillable</button>
   </div>

   Funguje s libovolným počtem tlačítek (2, 3, …) — switcher se
   automaticky roztáhne. Aktivní položka dostane třídu .active.
   ══════════════════════════════════════════════════════════════════ */
.gs-switcher {
  display: flex;
  /* 14. 9. 2026: bylo #E9E9EB, sjednoceno na --bg-3 (#E9EBEE) — rozdíl 3/255. */
  background: var(--bg-3);
  border-radius: var(--r-ctrl);
  padding: 3px;
  gap: 2px;
  width: 100%;
}
.gs-sw-btn {
  flex: 1;
  padding: 9px 0;
  border: none;
  border-radius: var(--r-ctrl);
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  cursor: pointer;
  font-family: inherit;
  background: transparent;
  color: var(--t3);
  transition: background .18s, color .18s, box-shadow .18s;
  white-space: nowrap;
}
.gs-sw-btn.active {
  background: var(--inv-bg);
  color: var(--inv-fg);
  box-shadow: 0 1px 4px rgba(0,0,0,.22);
}
.gs-sw-btn:not(.active):hover {
  color: var(--t1);
}

/* ══════════════════════════════════════════════════════════════════
   SEKCE 47 — Modal navigation (prev/next arrows)
   ──────────────────────────────────────────────────────────────────
   Použití — vložit do .modal-hd:
   <div class="modal-nav" id="tx-modal-nav" style="display:none">
     <button class="modal-nav-btn" id="tx-nav-prev" ...><span class="ms">chevron_left</span></button>
     <span  class="modal-nav-info" id="tx-nav-info"></span>
     <button class="modal-nav-btn" id="tx-nav-next" ...><span class="ms">chevron_right</span></button>
   </div>
   ══════════════════════════════════════════════════════════════════ */
.modal-nav { display:flex; align-items:center; gap:2px; margin-left:auto; margin-right:8px; }
.modal-nav-btn {
  width:28px; height:28px; border:1px solid var(--border); border-radius:var(--r-ctrl);
  background:var(--surface); cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  color:var(--t2); transition:.12s; flex-shrink:0;
}
.modal-nav-btn:hover:not(:disabled) { background: var(--hover); color:var(--t1); border-color:var(--border-md); }
.modal-nav-btn:disabled { opacity:.35; cursor:default; }
.modal-nav-info { font-size:var(--fs-sm); color:var(--t3); white-space:nowrap; min-width:38px; text-align:center; }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 48 — gs-cb (zaškrtávací pole ve formuláři)
   ──────────────────────────────────────────────────────────────────
   Figma: Airine › Checkbox (4693:131). Čtverec 18×18, r5, bílý s šedým
   rámečkem; zaškrtnutý modrý s bílou fajfkou. Popisek Regular 14 / --t1.

   <label class="gs-cb">
     <input type="checkbox" onchange="…">
     Sloučit položky do 1 řádku
   </label>

   NEZAMĚŇOVAT s .gs-checkbox (sekce 7) — to je kulaté zelené kolečko
   „úkol splněn" v Sales, jiná komponenta i jiný význam.
   ══════════════════════════════════════════════════════════════════ */
.gs-cb {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: var(--fs-base);
  color: var(--t1);
}
.gs-cb input[type=checkbox] {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  margin: 0;
  padding: 0;
  border: 1.5px solid var(--border-pole);   /* hrana ovladače 3 : 1 (10a) */
  border-radius: var(--r-cb);
  background: var(--surface);
  cursor: pointer;
  transition: background .15s, border-color .15s, box-shadow .15s;
  --cb-okraj: linear-gradient(color-mix(in srgb, var(--blue-brand) 70%, var(--white)), var(--blue-dk));   /* okraj zaškrtnutého, jako --gb-okraj primárního */
  --cb-zare: 0 0 6px 1px color-mix(in srgb, var(--blue) 55%, transparent);   /* záře na hover */
}
/* Glow je výchozí (12. 10. 2026, Ondra v náhledu tiketu: „dej to do DS jako
   variantu glow a ne glow, ale primární bude s glow"). Zaškrtnutý má tělo
   primárního tlačítka: plochu `--btn-gradient`, okraj o stupeň světlejší
   nahoře (jako `--gb-okraj` u `.gs-btn-primary`) a `--btn-shadow`. Na hover
   kolem rámečku svítí měkká záře v barvě `--gb-zare` primárního tlačítka.
   Záře je `box-shadow`, ne pseudoprvek jako u tlačítek: <input> pseudoprvky
   ve Firefoxu nemá a na 18 px by poloha kurzoru stejně nebyla vidět.
   Bez záře je `.gs-cb-plochy` (plná modrá, tak jak checkbox vypadal do 12. 10.). */
.gs-cb input[type=checkbox]:hover {
  border-color: var(--blue);
  box-shadow: var(--cb-zare);
}
.gs-cb input[type=checkbox]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 18%, transparent);
}
.gs-cb input[type=checkbox]:checked {
  border-color: transparent;
  background:
    url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline points='2 6 5 9 10 3' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 11px 11px no-repeat padding-box,
    var(--btn-gradient) padding-box,
    var(--cb-okraj) border-box;
  box-shadow: var(--btn-shadow);
}
.gs-cb input[type=checkbox]:checked:hover { box-shadow: var(--btn-shadow), var(--cb-zare); }

/* Plochá varianta, bez záře a gradientu. Pro husté seznamy voleb (nabídky
   filtrů), kde by svítící okraj u každého řádku byl šum. */
.gs-cb-plochy input[type=checkbox]:hover { box-shadow: none; }
.gs-cb-plochy input[type=checkbox]:checked,
.gs-cb-plochy input[type=checkbox]:checked:hover {
  background: var(--blue) url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline points='2 6 5 9 10 3' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 11px 11px no-repeat;
  border-color: var(--blue);
  box-shadow: none;
}
/* Kulatá varianta (7. 10. 2026, Ondra přes Vercel u checklistu tiketu: „ať je
   checkbox kulatý, jako varianta checkboxu, i ve Figmě"). Jen tvar — rámeček,
   fajfka i stavy jsou tytéž. Odškrtává se jím bod seznamu, ne volba formuláře.
   Čte: public/tickety.js (checklist). Figma: Checkbox, varianta Round. */
.gs-cb-kulaty input[type=checkbox] { border-radius: 50%; }

/* ── .tbl-cb — výběr řádků v tabulce (22. 9. 2026) ─────────────────────
   Vizuálně `.gs-cb` ve zmenšené podobě: tvar, rámeček i fajfka jsou tytéž,
   liší se velikost a klid. Vznikl 19. 9. 2026 v Transakcích jako `.tx-sel-cb`
   (Ondra přes Vercel: „checkbox pro zaškrtnutí bude defaultně světlý s 50%
   opacitou a na hover s 100% ale s modrým border glow efektem") a 22. 9. 2026
   ho Ondra chtěl všude („všude musíme sjednotit zaškrtávání jako je to nyní
   v transakcích"). Nosí ho: Transakce (.tx-sel-cb), Faktury (.inv-row-cb),
   Výkazy (.te-row-cb), Projekty (.pv-row-cb) — ty třídy jsou už jen háčky
   pro JS. Ve sloupci, který je vidět u každého řádku a používá se jednou za
   čas, klid ustupuje; zaškrtnutý nikdy, jinak by se výběr ztratil.

   Buňka tabulky ořezává (`overflow: hidden` kvůli třem tečkám), takže by
   uřízla i záři kolem políčka — buňka s `.tbl-cb` proto ořez nemá (Vercel
   22. 9. 2026: „ořezává se gradient"). Hlídá test/tbl-cb.test.js. */
/* Vlna 3 (rozhodnutí 10a, pristupnost-15): plné krytí a hrana --border-pole.
   Na opacity .5 s --border-md mělo políčko asi 1,5 : 1 — výběr řádků šel
   přehlédnout. Klid drží tenká hrana a bílá výplň, ne průhlednost. */
.tbl-cb{appearance:none;-webkit-appearance:none;width:16px;height:16px;
  flex-shrink:0;margin:0;padding:0;cursor:pointer;opacity:1;vertical-align:middle;
  border:1.5px solid var(--border-pole);border-radius:var(--r-cb);background:var(--surface);
  transition:background .15s,border-color .15s,box-shadow .15s,opacity .15s}
.tbl-cb:hover{opacity:1;border-color:var(--blue);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}
.tbl-cb:focus-visible{outline:none;opacity:1;border-color:var(--blue);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--blue) 18%,transparent)}
.tbl-cb:checked,.tbl-cb:indeterminate{opacity:1;border-color:var(--blue);background:var(--blue)}
.tbl-cb:checked{background:var(--blue) url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline points='2 6 5 9 10 3' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 10px 10px no-repeat}
/* Částečný výběr (hlavička, když je zaškrtnutá jen část řádků) — pomlčka, ne
   fajfka: fajfka by tvrdila „vybráno vše". */
.tbl-cb:indeterminate{background:var(--blue) url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cline x1='3' y1='6' x2='9' y2='6' stroke='white' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / 10px 10px no-repeat}
.tbl-header > :has(> .tbl-cb), .tbl-row > :has(> .tbl-cb) { overflow: visible; }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 49 — gs-field-unit (pole s jednotkou)
   ──────────────────────────────────────────────────────────────────
   Figma: Airine › Input Field, vlastnost „Jednotka" (+ „Text jednotky").
   Přípona sedí u pravé hrany pole, hodnota zůstává vlevo.

   <div class="gs-field-unit">
     <input type="number" id="…">
     <span class="gs-field-unit-tag">Kč</span>
   </div>

   Pole si nechává globální styl <input> včetně sekční barvy focusu —
   přípona je jen položená navrch, proto absolutně a bez zachytávání
   kliknutí (jinak by kliknutí vedle čísla pole nezaostřilo).
   ══════════════════════════════════════════════════════════════════ */
.gs-field-unit {
  position: relative;
  display: block;
}
.gs-field-unit > input {
  width: 100%;
  /* Místo pro příponu — bez rezervy by na ni delší číslo najelo.
     38px pokryje jednotky do tří znaků (Kč, %, dní, h). */
  padding-right: 38px;
  font-variant-numeric: tabular-nums;
}
.gs-field-unit > .gs-field-unit-tag {
  position: absolute;
  right: 11px;
  top: 50%;
  transform: translateY(-50%);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--t3);
  pointer-events: none;
}

/* ── 50. FINANCE ITEM UTILITIES ──────────────────────────────────────────────
   Sdílené pomocné třídy pro finanční položky v project modalu a vendor detailu. */
.p-fin-sub { font-size: var(--fs-xs); color: var(--t3); margin-top: 1px; }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 51 — gs-avatar (avatar člena týmu)
   ──────────────────────────────────────────────────────────────────
   Figma: Airine › Avatar (4948:395). Kruh s iniciálami na --blue, nebo
   zástupná silueta, když člen fotku nemá. Tři velikosti: sm 24, md 32, lg 56.

   <span class="gs-avatar gs-avatar-sm" title="Jana Nováková">JN</span>
   <img class="gs-avatar gs-avatar-md" src="…" alt="Jana Nováková">

   Rozměr je pevný schválně: avatar se nesmí roztáhnout podle délky
   jména, jinak se rozjede řádek, ve kterém stojí.

   <img> variantu plní profilová fotka člena (migrace 052). Adresu skládá
   `avatarUrl()` v server.js a je to VŽDY `/soubor/avatar/<id>`, nikdy cesta
   do úložiště — vykreslují ji `tkAvatar()` v tickety.js a `_tmFoto()`
   v settings-panel.js. Bez fotky zůstávají iniciály.
   ══════════════════════════════════════════════════════════════════ */
.gs-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* `flex: 0 0 auto`, ne jen `flex-shrink: 0` (24.→26. 9. 2026). Kolečko se
     v přepínači workspace roztáhlo do elipsy, protože je tam `<span>` a první
     dítě řádku — chytil ho selektor pro jméno s `flex: 1` (o kus níž). Ten je
     opravený, ale zákaz růstu patří i sem: avatar je kruh o dané velikosti,
     nikde v appce nemá důvod se roztahovat podle volného místa. */
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--blue-plocha);
  color: var(--white);                      /* popředí na plné modré — proto --white, ne --surface */
  font-weight: var(--fw-medium);
  line-height: 1;
  overflow: hidden;
  object-fit: cover;                /* platí, když je prvek <img> */
  user-select: none;
}
/* Iniciály se centrují OPTICKY, ne matematicky (13. 9. 2026). Flexbox srovná
   na střed řádkový box, jenže velká písmena v něm nesedí uprostřed: baseline je
   asi 0,2 em nade dnem a nad velkými písmeny zbývá místo pro akcenty, takže
   „AG" vyjde vizuálně výš než střed kruhu. Posun o 0,08 em to srovná.
   Na <img> se použít nesmí — ten by se odsazením ořízl. */
.gs-avatar:not(img) { padding-top: .08em; }
.gs-avatar-sm { width: 24px; height: 24px; font-size: var(--fs-xs); }
.gs-avatar-md { width: 32px; height: 32px; font-size: var(--fs-sm); }
/* lg 56 přibylo 24. 9. 2026 pro Nastavení → Účet a → Workspace: tam se fotka
   nastavuje, ne jen připomíná, takže na 32 px by nebylo poznat, co se nahrálo. */
.gs-avatar-lg { width: 56px; height: 56px; font-size: var(--fs-lg); }
/* Bez fotky i bez iniciál — prázdný avatar má pořád držet místo v řádku. */
.gs-avatar-empty { background: var(--bg-2); }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 52 — gs-chip (štítek)
   ──────────────────────────────────────────────────────────────────
   Figma: Airine › Label Chip (4949:405). Pilulka s tečkou a textem.

   <span class="gs-chip gs-chip-red"><i></i>Chyba</span>

   Výchozí štítky z migrace 042 mají v datech hexy (Chyba #FF3A12,
   Od klienta #27A264 …); dva z nich paletě neodpovídají ani v Day.
   Na třídu gs-chip-* je převádí TK_BARVY (tickety.js) a tkBarvaCss
   (shared.js), takže se kreslí paletou a v Night se přebarví (night-07).
   Barva, která v paletě není, jde přes .gs-chip bez modifikátoru
   a `style="--chip:…"`, ne přidáním další třídy do tohohle souboru.
   ══════════════════════════════════════════════════════════════════ */
.gs-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px 3px 8px;
  border-radius: var(--r-ctrl);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  /* Výchozí je neutrální; modifikátory a inline --chip jen přebijí proměnné. */
  background: var(--chip-bg, var(--bg));
  color: var(--chip, var(--t2));
}
.gs-chip > i {
  width: 6px;
  height: 6px;
  flex-shrink: 0;
  border-radius: 50%;
  background: currentColor;
}
.gs-chip-blue   { --chip: var(--blue-txt);   --chip-bg: var(--blue-lt); }
.gs-chip-green  { --chip: var(--green-txt);  --chip-bg: var(--green-lt); }
.gs-chip-red    { --chip: var(--red-txt);    --chip-bg: var(--red-lt); }
.gs-chip-amber  { --chip: var(--amber-txt);  --chip-bg: var(--amber-lt); }
.gs-chip-purple { --chip: var(--purple-txt); --chip-bg: var(--purple-lt); }
.gs-chip-grey   { --chip: var(--t2);     --chip-bg: var(--bg); }

/* ── Kód záznamu (.gs-kod, Ondra 12. 10. 2026) ───────────────────────────────
   Označení typu TIK-2026-0005 nebo PRJ-2026-004: malý štítek s kulatým rámečkem,
   klik ho zkopíruje do schránky (gsKopirujKod), aby šel vložit Claudovi nebo
   do zprávy. Vždy <button>, takže se dá zkopírovat i z klávesnice.
   HTML skládá gsKod(text) v shared.js. */
.gs-kod {
  display: inline-flex;
  align-items: center;
  padding: 0 8px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: transparent;
  font-family: var(--ff-mono);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  line-height: 18px;
  color: var(--t3);
  white-space: nowrap;
  cursor: copy;
  transition: color .12s, border-color .12s;
}
.gs-kod:hover { color: var(--t1); border-color: var(--border-md); }
.gs-kod:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

/* ── Stavový štítek (vlna 3, rozhodnutí 2a; vzory-03, vykazy-08) ────────────
   .gs-chip je JEDINÝ štítek stavu v appce: projekt, faktura, platba, prospekt,
   nabídka, výkaz, tiket. Modul mapuje svůj výčet na VARIANTU podle mapy
   stav → barva (docs/design-system.md §3), ne na barvu. Barevné modifikátory
   výš (-blue, -red …) zůstávají štítkům, které si barvu volí uživatel (tikety).

     problem   červená  po splatnosti, přečerpáno, odmítnuto, neuhrazeno
     blizi     amber    čeká na schválení, částečně uhrazeno, k fakturaci
     hotovo    zelená   zaplaceno, dokončeno, vyhráno, schváleno
     bezi      modrá    odesláno, rozpracováno, v realizaci, aktivní
     koncept   šedá     koncept, storno, archiv, nefakturovatelné (s hranou)
     oznaceni  fialová  barter, nabídka — označení, ne stav

   Skládá ho `gsChip(text, varianta, volby)` v shared.js; platební stav faktury
   `invStavChip(inv)`, platba projektu a transakce `platbaChip(kod, text)`.
   Text je vždy role -txt nebo --t2, nikdy paleta (--amber jako text má 1,7 : 1).
   Inline `style="color:…"` a `cssText` ve štítku jsou zakázané — Night by je
   nepřebarvil (test/vlna3-komponenty.test.js). */
.gs-chip-problem  { --chip: var(--red-txt);    --chip-bg: var(--red-lt); }
.gs-chip-blizi    { --chip: var(--amber-txt);  --chip-bg: var(--amber-lt); }
.gs-chip-hotovo   { --chip: var(--green-txt);  --chip-bg: var(--green-lt); }
.gs-chip-bezi     { --chip: var(--blue-txt);   --chip-bg: var(--blue-lt); }
.gs-chip-oznaceni { --chip: var(--purple-txt); --chip-bg: var(--purple-lt); }
/* Koncept a storno: podklad --bg se na bílém řádku skoro ztratí, proto hrana
   --border jako u dřívějšího .pay-badge.x. Vnitřní stín, ne border — štítek
   se nesmí o pixel zvětšit proti ostatním variantám. */
.gs-chip-koncept  { --chip: var(--t2);         --chip-bg: var(--bg); box-shadow: inset 0 0 0 1px var(--border); }
/* Ikonová podoba (dřív .pay-badge.ikona): kolečko s glyfem místo slova, kde
   stav stojí u každého řádku (výpis transakcí). Význam nese jen barva a tvar,
   proto `title` a `aria-label` doplňuje gsChip() povinně. */
.gs-chip.ikona {
  justify-content: center; gap: 0;
  width: 16px; height: 16px; padding: 0; border-radius: var(--r-pill);
}
.gs-chip.ikona .ms { font-size: var(--fs-xs); line-height: 1; }
/* Úzký sloupec: štítek je široký podle textu (ne podle buňky, pill-v-bunce)
   a text se ořízne třemi tečkami. Flex s tečkou neumí text-overflow sám,
   proto gsChip() balí text do .gs-chip-text. */
.gs-chip { max-width: 100%; vertical-align: middle; }
.gs-chip-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* Štítek, kterým se stav přepíná (detail projektu, 10. 10. 2026): <select>
   oblečený jako .gs-chip, varianty -bezi/-blizi/-hotovo/-koncept nese stejně
   (stránka je přepíná podle hodnoty, projects.js dpHlavicka). Šipka je z
   currentColor, aby se v každé variantě i v Night barvila s textem; nativní
   šipka pole (--pole-sipka) a hover/fokus pole (sekce 35) jsou vyjmuté
   v jejich :not(). Fokus je prstenec jako u ovladačů, ne rámeček pole. */
.gs-chip-select {
  width: auto; min-height: 0; height: 26px; line-height: 26px; max-width: 100%;
  border: 0; border-radius: var(--r-ctrl); padding: 0 24px 0 8px;
  font-family: inherit; font-size: var(--fs-sm); font-weight: var(--fw-medium);
  cursor: pointer; appearance: none; -webkit-appearance: none;
  --pole-sipka: none;
  background-color: var(--chip-bg, var(--bg)); color: var(--chip, var(--t2));
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 12px) 11px, calc(100% - 8px) 11px;
  background-size: 4px 4px; background-repeat: no-repeat;
}
.gs-chip-select:focus {
  outline: none;
  background-color: var(--chip-bg, var(--bg));
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--blue) 55%, transparent);
}
.gs-chip-select.gs-chip-koncept:focus { box-shadow: inset 0 0 0 1px var(--border), 0 0 0 2px color-mix(in srgb, var(--blue) 55%, transparent); }

/* Štítek osoby u řádku výkazu (kdo): majitel modře, člen týmu fialově,
   dodavatel neutrálně. Do 10. 10. 2026 jen v times.css; detail projektu ho
   ukazuje u výkazů taky, proto tady (test/rodiny-trid: dvě stránky = DS). */
.te-tl-who { display: inline-flex; align-items: center; height: 20px; padding: 0 8px; border-radius: var(--r-pill); font-size: var(--fs-xs); font-weight: var(--fw-medium); white-space: nowrap; background: var(--bg); color: var(--t2); }
.te-tl-who.majitel { background: var(--blue-lt); color: var(--blue-txt); }
.te-tl-who.tym { background: var(--purple-lt); color: var(--purple-txt); }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 53 — gs-prio (priorita)
   ──────────────────────────────────────────────────────────────────
   Figma: Airine › Priority Badge (4949:418). Čtyři úrovně odpovídají
   sloupci `priority` v migraci 042 — třída se skládá z jeho hodnoty,
   takže `gs-prio-` + priority a nic se nemapuje ručně.

   <span class="gs-prio gs-prio-urgentni">Urgentní</span>

   Urgentní je záměrně jediná plná. Tři odstíny světlého pozadí vedle
   sebe splynou právě tam, kde na rozdílu záleží nejvíc.
   ══════════════════════════════════════════════════════════════════ */
.gs-prio {
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  border-radius: var(--r-ctrl);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  white-space: nowrap;
}
.gs-prio-nizka    { background: var(--bg);       color: var(--t2); }
.gs-prio-stredni  { background: var(--blue-lt);  color: var(--blue-txt); }
.gs-prio-vysoka   { background: var(--amber-lt); color: var(--amber-txt); }
.gs-prio-urgentni { background: var(--plocha-red); color: var(--white); }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 54 — gs-clp (ukazatel checklistu)
   ──────────────────────────────────────────────────────────────────
   Figma: Airine › Checklist Progress (4950:395). Dráha 40×4 a počet.

   <span class="gs-clp">
     <span class="gs-clp-track"><span class="gs-clp-fill" style="width:43%"></span></span>
     3/7
   </span>

   Dokončený se obarví na zeleno (.gs-clp-done na obalu) — jinak se
   „7/7" od „3/7" na první pohled neliší.
   ══════════════════════════════════════════════════════════════════ */
.gs-clp {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--t3);
  font-variant-numeric: tabular-nums;
}
.gs-clp-track {
  width: 40px;
  height: 4px;
  flex-shrink: 0;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;               /* drží zaoblený konec i u plné výplně */
}
.gs-clp-fill {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: var(--blue);
}
.gs-clp-done            { color: var(--green-txt); }
.gs-clp-done .gs-clp-fill { background: var(--green); }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 55 — gs-view (obal obsahu modulu pod hlavičkou)
   ──────────────────────────────────────────────────────────────────
   Layoutový prvek, ne vizuální — ve Figmě nemá protějšek a mít nemusí.
   Zabere zbytek výšky pod .hd + podnavigací a skládá děti do sloupce.
   `overflow:hidden` je záměr: modul je pevný rám, scrolluje se až
   v kontejnerech uvnitř (tabulka, board, sloupec), nikdy stránka.

   <div class="gs-view" id="view-projects">…</div>

   Do 12. 9. 2026 to byl `.view` opsaný slovo od slova v pěti stránkových
   CSS (contacts, projects, finance, times, tickety) — každý nový modul
   ho kopíroval znovu. Sem patří podle CLAUDE.md §13.4.
   ══════════════════════════════════════════════════════════════════ */
.gs-view {
  flex: 1;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* ══════════════════════════════════════════════════════════════════
   SEKCE 56 — části modalu na plátně (13. 9. 2026, z Times „Nový záznam")
   ──────────────────────────────────────────────────────────────────
   Do 13. 9. 2026 žily v times.css jako .te-icon-label, .nm-date-pill,
   .nm-billable-row/-info/-title/-sub a .te-hours-hero/-input/-lbl.
   Figma: Date Pill, Toggle Row, Hero Number, Label (Icon) — docs/figma.md §4.
   Čte: times.html (Nový záznam), projects.html, finance.html, crm.html,
   tickety.js (detail), test/design-modaly.test.js.
   ══════════════════════════════════════════════════════════════════ */

/* Label s ikonou vlevo (svg 12px, currentColor). */
.gs-label.has-icon { display: flex; align-items: center; gap: 4px; }

/* Datum jako pilulka s ikonou; nativní <input type=date> je schovaný uvnitř
   a klik na pilulku otevře kalendář (`gsKalPole`, sekce 60; do 21. 9. 2026
   systémové okno přes showPicker()). Text data se vykresluje do <span> JS
   funkcí stránky (viz nmUpdateDateDisplay v times.js). */
.gs-date-pill {
  position: relative; display: inline-flex; align-items: center; gap: 8px;
  background: var(--surface); border-radius: var(--r-ctrl); padding: 11px 12px;
  font-size: var(--fs-base); color: var(--t1); cursor: pointer; width: fit-content;
}
.gs-date-pill svg, .gs-date-pill .ms { color: var(--t1); flex-shrink: 0; }
.gs-date-pill > input[type=date] { position: absolute; opacity: 0; width: 1px; height: 1px; padding: 0; border: 0; pointer-events: none; }

/* Řádek s přepínačem: [toggle] titulek + podtitulek … [slot vpravo]. Bílá karta
   na plátně, toggle větší (44×26). Barvu „zapnuto" má od vlny 3 už sdílený
   .toggle-switch (--blue-plocha, rozhodnutí 10a); pravidla níž ji jen opakují. Selektor .gs-toggle-row .toggle-switch má
   vyšší specificitu než .toggle-switch — záměrně, jinak by vyhrálo 38×22. */
.gs-toggle-row {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface); border-radius: var(--r-lg); padding: 16px 16px;
}
.gs-toggle-row-info  { display: flex; flex-direction: column; gap: 2px; }
.gs-toggle-row-title { font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--t1); }
.gs-toggle-row-sub   { font-size: var(--fs-sm); color: var(--t3); }
.gs-toggle-row-right { margin-left: auto; align-items: flex-end; }
/* Pole ve slotu vpravo leží na BÍLÉ kartě řádku, takže samo bílé být nemůže —
   táž past jako u .gs-section-box (sekce 15): bílá na bílé zmizí. Dostane proto
   podklad plátna a plnou linku a zarovnává se doprava, ke své hraně karty.
   (Ondra 23. 9. 2026 nad sazbou v okně výkazu: „ta sazba je moc vlevo … a mělo
   by to mít ten field pozadí.") Čte: times.html (Fakturovatelné + Sazba). */
.modal-body .gs-toggle-row .fg > :is(input, select) {
  background-color: var(--pole-bg);
  border-color: var(--border);
  width: auto;
}
.modal-body .gs-toggle-row .fg > :is(input, select) {
  --pole-plocha: var(--pole-bg);
  --pole-okraj: var(--border-pole);
}
/* Průhledná linka: okraj pod myší kreslí vrstva `--pole-okraj` (sekce 35). */
.modal-body .gs-toggle-row .fg > :is(input, select):hover:not([aria-invalid="true"]) {
  background-color: var(--pole-bg);
  border-color: transparent;
}
.modal-body .gs-toggle-row .fg > :is(input, select):focus { border-color: var(--focus, var(--blue)); }
.gs-toggle-row .toggle-switch { width: 44px; height: 26px; }
.gs-toggle-row .toggle-slider:before { width: 20px; height: 20px; }
.gs-toggle-row .toggle-switch input:checked + .toggle-slider { background: var(--blue-plocha); }
.gs-toggle-row .toggle-switch input:checked + .toggle-slider:before { transform: translateX(18px); background: var(--white); }

/* ── Toggle s ikonou v jezdci (.toggle-ikona), tooltip (.gs-tip) a čip
   hodnoty (.gs-btn-cip) — 26. 9. 2026, řádek fakturace v okně „Čas ve výkazu"
   podle plátna (deska ZapisHodin, návrh 3), schváleno Ondrou (§13.3, a — DS).
   Toggle 56×32 je stejně vysoký jako čip sazby vedle něj (Ondra: „aby ten
   toggle byl stejně vysoký jako ten button s výběrem sazby"). Ikona v jezdci
   říká, CO se přepíná (bankovky = fakturace), takže řádek nepotřebuje titulek;
   co klik udělá, řekne `.gs-tip`. Selektory začínají `.toggle-switch.toggle-ikona`
   (dvě třídy), protože `.gs-toggle-row .toggle-switch input:checked + …` výš
   barví dráhu modře a se stejnou specificitou by vyhrálo pořadí v souboru.
   Čte: times.html (#nm-billable-cb, #nm-rate-cip), times.js (nmSazbaCip). */
.toggle-switch.toggle-ikona { width: 56px; height: 32px; }
.toggle-switch.toggle-ikona .toggle-slider { background: var(--border-pole); }
.toggle-switch.toggle-ikona .toggle-slider:before { content: none; }
.toggle-ikona .toggle-jezdec {
  position: absolute; top: 3px; left: 3px; width: 26px; height: 26px; border-radius: 50%;
  background: var(--white); box-shadow: 0 1px 3px rgba(0,0,0,.2);
  display: flex; align-items: center; justify-content: center;
  transition: transform .2s cubic-bezier(.22, 1, .36, 1);
}
.toggle-ikona .toggle-jezdec .ms { --ms: var(--ms-md); color: var(--t3); transition: color .2s; }
.toggle-switch.toggle-ikona input:checked + .toggle-slider { background: var(--blue-plocha); }
/* Zapnutý jezdec v Night: tmavé kolečko se zelenou ikonou na mentolové dráze
   (bílé kolečko s bílou -dk ikonou bylo prázdné, ds-01). */
.toggle-ikona input:checked + .toggle-slider .toggle-jezdec { transform: translateX(24px); background: var(--white); }
/* Ikona v zapnutém jezdci je modrá plocha na bílé: 4,85 : 1 v obou režimech. */
.toggle-ikona input:checked + .toggle-slider .toggle-jezdec .ms { color: var(--blue-plocha); }
.toggle-ikona input:focus-visible + .toggle-slider { box-shadow: 0 0 0 2px var(--focus); }

/* Tooltip: tmavý štítek nad prvkem, ukáže se po najetí nebo zaměření
   klávesnicí. Obal nese `.gs-tip-obal`; text je v DOM (ne `title`), takže ho
   jde přeložit a čtečka ho dostane přes `aria-describedby`. Zarovnaný
   k levé hraně prvku, ne na střed: přepínač stojí na začátku řádku a na
   středu by štítek přetekl přes okraj modalu (na telefonu i přes obrazovku). */
.gs-tip-obal { position: relative; }
.gs-tip {
  position: absolute; left: 0; bottom: calc(100% + 8px); z-index: var(--z-tip);
  padding: 4px 8px; border-radius: var(--r-sm); background: var(--inv-bg); color: var(--inv-fg);
  font-size: var(--fs-sm); font-weight: var(--fw-medium); line-height: 1.3; white-space: nowrap;
  pointer-events: none; opacity: 0; transition: opacity .15s;
}
.gs-tip-obal:hover > .gs-tip, .gs-tip-obal:has(:focus-visible) > .gs-tip { opacity: 1; }
/* Varianta pod prvkem, zarovnaná k pravé hraně (`.gs-tip-dole`, schválil
   Ondra 9. 10. 2026): ikony v hlavičce stojí u pravého okraje, štítek nad nimi
   nebo zarovnaný doleva by utekl z obrazovky. Menší odsazení než základní
   štítek, protože popisuje jen ikonu. Ve dne tmavý štítek (`--inv-*`) na světlé
   hlavičce; v Night od 9. 10. tmavý taky (viz úprava níž).
   Klávesová zkratka jde do `<kbd>` (lupa, ⌘K / Ctrl+K). Obalem je tu rovnou
   `.hd-icon-btn` (zaměřit jde tlačítko samo, proto `:focus-visible`, ne `:has`);
   s otevřeným panelem (`.gs-open`, notifikace) štítek mlčí. */
/* Úprava 9. 10. 2026 (Ondra: „musí to být veliké jako to systémové",
   „ukazovat se to má hned? není to otravné?", a v Night chtěl tmavý štítek):
   velikost jako systémový tooltip macOS (11 px, výška ~19 px), naskočí po
   půl vteřině a zmizí hned, v Night tmavá vystouplá plocha s prstenem místo
   světlého inverzu. Den zůstává tmavý na světlé hlavičce. */
.gs-tip.gs-tip-dole {
  bottom: auto; top: calc(100% + 6px); left: auto; right: 0;
  padding: 0 var(--sp-2); border-radius: var(--r-cb); font-size: var(--fs-xs); line-height: 19px;
  transition: opacity .1s;
}
:root[data-tema="night"] :is(.gs-tip.gs-tip-dole, .gs-cary-den > .gs-tip) { background: var(--bg); color: var(--t1); box-shadow: var(--sh-md); --inv-fg: var(--t1); }
/* Varianta s větou (`.gs-tip-text`, 12. 10. 2026): vysvětlivka, která dřív
   stála pod polem jako stálý šedý řádek. Ondra v detailu projektu: „jen
   tooltip při najetí" — u polí, která jsou jasná i bez ní. Zalamuje se do
   280 px, jinak by věta utekla přes okraj okna. Spouští ji buď celé pole
   (`.fg.gs-tip-obal`), nebo ikonka `.gs-tip-i` vedle nadpisu přepínače. */
.gs-tip.gs-tip-text {
  width: max-content; max-width: 280px; padding: var(--sp-2) var(--sp-3);
  white-space: normal; text-align: left; font-weight: var(--fw-regular); line-height: 1.45;
}
.gs-tip-obal:hover > .gs-tip.gs-tip-text { transition-delay: .3s; }
.gs-tip-i {
  display: inline-flex; align-items: center; padding: 0; border: 0; background: none;
  color: var(--t3); cursor: help; vertical-align: middle;
}
.gs-tip-i .ms { --ms: var(--ms-sm); }
.gs-tip-i:is(:hover, :focus-visible) { color: var(--t1); }
.gs-tip kbd {
  margin-left: 4px; padding: 0 4px; border-radius: 4px; font: inherit; font-family: var(--ff-mono);
  font-size: var(--fs-xs); background: color-mix(in srgb, var(--inv-fg) 16%, transparent);
}
.gs-tip kbd:empty { display: none; }
.hd-icon-btn { position: relative; }
.hd-icon-btn:not(.gs-open):is(:hover, :focus-visible) > .gs-tip { opacity: 1; transition-delay: .5s; }

/* Přehled klávesových zkratek (klávesa `?`, public/zkratky-widget.js; návrh
   schválil Ondra 9. 10. 2026, varianta a). Skořápka je `.modal.modal-xs`,
   skupiny `.gs-section-box` — nové jsou jen řádek a klávesa. `.gs-kbd` je
   klávesa obecně; štítek v hlavičce má vlastní `.gs-tip kbd`, protože sedí
   na inverzní ploše. Mezery mezi boxy dává `gap` těla okna. */
.gs-zkratky .gs-section-box { margin-bottom: 0; }
.gs-zkratky-radek {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 0; font-size: var(--fs-base); color: var(--t1);
}
.gs-zkratky-radek + .gs-zkratky-radek { border-top: 1px solid var(--border); }
.gs-section-box > .gs-zkratky-radek:last-child { padding-bottom: 0; }
.gs-zkratky-klavesy { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; }
.gs-zkratky-nebo { color: var(--t3); font-size: var(--fs-xs); padding: 0 4px; }
.gs-kbd {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 4px; border-radius: var(--r-cb);
  border: 1px solid var(--border); background: var(--surface); color: var(--t2);
  font-family: var(--ff-mono); font-size: var(--fs-xs); line-height: 1;
}

/* Čip hodnoty: tlačítko 32 px na podkladu plátna — název, šedá částka
   a šipka. Otevírá `gsPopover` (sekce 57); `gs-open` na kotvě šipku otočí. */
.gs-btn.gs-btn-cip { height: 32px; padding: 0 8px 0 12px; background: var(--bg); color: var(--t1); min-width: 0; transition: background .15s; }
.gs-btn.gs-btn-cip:hover { background: var(--hover); }
.gs-btn-cip-sub { color: var(--t3); font-weight: var(--fw-regular); font-variant-numeric: tabular-nums; }
.gs-btn-cip > .ms { --ms: var(--ms-md); color: var(--t3); transition: transform .15s; }
.gs-btn-cip.gs-open > .ms { transform: rotate(180deg); }
/* Položka nabídky se štítkem za názvem (např. „výchozí", stojí uvnitř prvního
   `<span>`) a částkou vpravo, před fajfkou. */
.gs-pop-tag { margin-left: 8px; font-size: var(--fs-xs); font-weight: var(--fw-regular); color: var(--t3); }
.gs-pop-num { flex: 0 0 auto; color: var(--t3); font-weight: var(--fw-regular); font-variant-numeric: tabular-nums; }
.gs-pop-num + .gs-pop-check { margin-left: 0; }
.gs-toggle-row-pozn { font-size: var(--fs-sm); color: var(--t3); }

/* Hero číslo: velký číselný input bez rámečku + uppercase label pod ním,
   zarovnané doprava (Hodin v Times, částka v Kč ve Financích). 40px nemá
   token (--fs-2xl je 20px) — jednorázová hero velikost, odsouhlaseno
   2026-09-01 (CLAUDE.md 13.3). Selektor nese i .modal-body .fg, protože
   pravidlo karet výše má specificitu (0,3,1) a input v hero je někdy přímo
   ve .fg. */
.gs-hero-num { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex-shrink: 0; margin-left: auto; }
.gs-hero-num > input, .modal-body .fg > .gs-hero-num > input, .modal-body .fg .gs-hero-num > input {
  border: none; background: transparent; padding: 0; width: 76px; text-align: right;
  font-size: 40px; font-weight: var(--fw-bold); color: var(--t1); line-height: 1;
  -moz-appearance: textfield; border-radius: 0;
}
.gs-hero-num > input:focus { outline: none; border: none; background: transparent; }
.gs-hero-num > input::-webkit-outer-spin-button, .gs-hero-num > input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
/* Číselné pole bez šipek prohlížeče — číslo se píše (Ondra 7. 10. 2026:
   šipky v Sazebníku se lepily k číslu). Čte Nastavení → Sazebník. */
.pole-bez-sipek { -moz-appearance: textfield; }
.pole-bez-sipek::-webkit-outer-spin-button, .pole-bez-sipek::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.gs-hero-num-lbl { font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--t3); text-transform: uppercase; letter-spacing: .05em; }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 57 — Popover, Toolbar, Prop Grid (13. 9. 2026, karta tiketu
   podle Trella; CLAUDE.md 13.3, odsouhlaseno Ondrou)
   ──────────────────────────────────────────────────────────────────
   Tři díly, které dohromady dělají „vlastnosti se přidávají tlačítky":
   - .gs-toolbar   řada sekundárních tlačítek pod nadpisem
   - .gs-prop-grid vyplněné vlastnosti jako popisek + hodnota, klik otevře
   - .gs-popover   plovoucí panel u tlačítka/hodnoty (výběr, datum, číslo)
   Popover otevírá gsPopover(anchor, title, html) v shared.js — jeden na
   stránce, zavírá Esc a klik mimo. Figma: protějšek zatím není (dluh,
   docs/design-system.md sekce 57).
   Čte: public/tickety.js (první uživatel); později karta v Projektech.
   ══════════════════════════════════════════════════════════════════ */
.gs-toolbar { display: flex; flex-wrap: wrap; gap: 8px; }
.gs-toolbar .gs-btn { gap: 8px; }
.gs-toolbar .gs-btn svg { width: 14px; height: 14px; flex-shrink: 0; }
.gs-toolbar .gs-btn .ms { --ms: var(--ms-sm); }

.gs-prop-grid { display: flex; flex-wrap: wrap; gap: 8px 16px; }
.gs-prop { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.gs-prop-k {
  font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--t3);
  text-transform: uppercase; letter-spacing: .04em;
}
/* Hodnota vypadá jako tlačítko — je to vstup do popoveru, ne text. */
.gs-prop-v {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 4px 8px; border: 1px solid transparent; border-radius: var(--r-sm);
  background: var(--bg); color: var(--t1); font-size: var(--fs-sm); font-weight: var(--fw-medium);
  cursor: pointer; text-align: left; font-family: inherit; max-width: 100%;
}
.gs-prop-v:hover { background: var(--hover); }
.gs-prop-v.gs-prop-v-bare { background: transparent; padding-left: 0; }
.gs-prop-v.gs-prop-v-bare:hover { background: var(--hover); padding-left: 8px; }
.gs-prop-v .gs-avatar { margin-left: -3px; }

.gs-popover {
  /* `--pop-pad` a `--pop-mlha` stojí na PANELU, ne na jeho těle: od 19. 9. 2026
     je pás hledání (`.gs-pop-hledat`) sourozencem těla, ne jeho dítětem, a obojí
     potřebuje tytéž hodnoty — stejné odsazení a výšku mlhy na jednom místě.
     Varianta pro `<select>` si odsazení přepisuje, pás se přizpůsobí sám. */
  --pop-pad: 10px; --pop-mlha: 20px;
  position: fixed; z-index: var(--z-popover); width: 300px; max-width: calc(100vw - 16px);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--sh-lg);
  display: flex; flex-direction: column; max-height: min(420px, calc(100vh - 16px));
  /* Aby se pás hledání (.gs-pop-hledat) i mlha pod ním ořízly do zaobleného
     rohu. Rolování to nebere — roluje `.gs-popover-body`, ne panel. */
  overflow: hidden;
}
/* Nadpis stojí VLEVO a na stejné svislici jako text položek pod ním (Ondra
   26. 9. 2026 přes Vercel toolbar nad Financemi: „Název toho boxu není
   zarovnaný doleva."). Odsazení se proto skládá z odsazení těla (`--pop-pad`,
   které si varianta pro `<select>` přepisuje) a vlastního odsazení položky —
   natvrdo napsané číslo by se v té variantě rozešlo. */
.gs-popover-hd {
  display: flex; align-items: center; position: relative;
  padding: 8px 36px 8px calc(var(--pop-pad) + 8px);
  font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--t2);
  border-bottom: 1px solid var(--border);
}
.gs-popover-close {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  width: 24px; height: 24px; border: none; background: none; border-radius: var(--r-ctrl);
  color: var(--t3); line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.gs-popover-close .ms { --ms: var(--ms-sm); }
.gs-popover-close:hover { background: var(--hover); color: var(--t1); }
.gs-popover-body {
  padding: var(--pop-pad); overflow-y: auto; display: flex; flex-direction: column; gap: 8px;
}
.gs-pop-list { display: flex; flex-direction: column; gap: 1px; }
.gs-pop-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 7px 8px; border: none; border-radius: var(--r-sm); background: none;
  color: var(--t1); font-size: var(--fs-sm); font-family: inherit; text-align: left; cursor: pointer;
}
.gs-pop-item:hover { background: var(--hover); }
/* Vybraná položka stojí ve velmi světle šedém boxu (Ondra 13. 9. 2026),
   ne v modrém: modrá plocha pod modrým textem a modrou fajfkou dělala
   ze záznamu tlačítko. Co je vybrané, říká text a fajfka; box jen ukazuje,
   kde to je. */
.gs-pop-item.active { background: var(--bg); color: var(--blue); }
.gs-pop-item .gs-pop-check { margin-left: auto; color: var(--blue); }
/* Jméno v řádku. Druhý selektor je pro řádky, které mají vlevo kolečko
   (přepínač workspace v panelu účtu) — tam jméno první dítě není, ale
   zkracovat se musí stejně.
   `:not(.gs-avatar)` je oprava z 26. 9. 2026: workspace bez fotky má místo
   `<img>` kolečko s iniciálami, a to je `<span>` — tedy první dítě řádku.
   Dostalo tím `flex: 1` a roztáhlo se do elipsy. */
.gs-pop-item > span:first-child:not(.gs-avatar):not(.ms),
.gs-pop-item > .gs-avatar + span,
.gs-pop-item > .ms:first-child + span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* `:not(.ms)` je oprava z 26. 9. 2026 (Ondra přes Vercel toolbar nad Financemi:
   „Ikonky jsou různě rozhozené."). Řádek s ikonou má tvar `ikona, text`, takže
   prvním dítětem je ikona — ta dostala `flex: 1`, roztáhla se přes zbytek řádku
   a text začínal tam, kde skončil její glyf. Glyfy mají různou šířku, takže
   každý řádek jinde. Růst má text, ikona si drží svou velikost.
   Ikona je vedlejší k popisku, proto `--t3`; vybraný řádek si svou modrou
   nechá, jinak by fajfka svítila a ikona u ní ne. */
.gs-pop-item > .ms:first-child { flex: 0 0 auto; }
.gs-pop-item:not(.active) > .ms:first-child { color: var(--t3); }
.gs-pop-item:not(.active):hover > .ms:first-child { color: var(--t2); }
.gs-pop-item-muted { color: var(--t3); }
/* Položka, která něco odešle (odhlášení v panelu účtu), stojí ve `<form>`.
   Ten by jinak přidal svůj výchozí okraj a řádek by z řady vypadl. */
.gs-pop-list form { margin: 0; }
.gs-pop-empty { padding: 8px; font-size: var(--fs-sm); color: var(--t3); text-align: center; }
/* Vysvětlivka nad seznamem (19. 9. 2026) — tři až čtyři řádky o tom, co
   ukazatel vlastně měří. Na rozdíl od `.gs-pop-empty` se láme přes víc řádků
   a je zarovnaná vlevo: je to text ke čtení, ne hláška „nic tu není".
   Čte: public/finance.js (`finDashAkceNabidka`). */
.gs-pop-note {
  margin: 0 0 8px; padding: 2px 8px 8px; font-size: var(--fs-sm); line-height: 1.45;
  color: var(--t2); border-bottom: 1px solid var(--border);
  /* Ikonka „i" vlevo (Ondra 26. 9. 2026): bez ní si text čtenář spletl s další
     položkou nabídky. Zarovnaná k prvnímu řádku textu, ne na střed odstavce. */
  display: flex; gap: 8px; align-items: flex-start;
}
.gs-pop-note > .ms { --ms: var(--ms-sm); flex: 0 0 auto; margin-top: 1px; color: var(--t3); }
.gs-pop-actions { display: flex; gap: 8px; align-items: center; }
.gs-pop-actions .gs-btn-ghost { margin-left: auto; }
/* Varianty z 13. 9. 2026 (přepínač nástěnek — oblíbené / nedávné / uzavřené,
   role Klient). Čte: public/tickety.js.
   - .gs-pop-h        nadpis skupiny v seznamu (Oblíbené, Nedávné, …)
   - .gs-pop-aux      vedlejší ikonové tlačítko na konci řádku (hvězdička);
                      řádek je pak <div role="button">, ne <button> — tlačítko
                      v tlačítku není platné HTML. .active = zapnuto (připnuto).
   - .gs-prop-v-static hodnota bez popoveru — jen ke čtení (klient) */
.gs-pop-h { padding: 8px 8px 2px; display: flex; align-items: center; gap: 8px; }
.gs-pop-h svg { width: 12px; height: 12px; color: var(--t3); }
.gs-pop-h .ms { --ms: var(--ms-xs); color: var(--t3); }
.gs-pop-aux {
  margin-left: auto; flex-shrink: 0; width: 24px; height: 24px; display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: var(--r-sm); background: none; color: var(--t3); cursor: pointer; opacity: 0;
}
.gs-pop-aux svg { width: 14px; height: 14px; }
.gs-pop-aux .ms { --ms: var(--ms-sm); }
.gs-pop-item:hover .gs-pop-aux, .gs-pop-item:focus-within .gs-pop-aux, .gs-pop-aux.active { opacity: 1; }
.gs-pop-aux:hover { background: var(--hover); color: var(--t1); }

/* Varianta pro `<select>` (15. 9. 2026, `gsSelect` v shared.js). Rozbalený
   `<select>` kreslí operační systém a na macOS vypadá jako cizí prvek uvnitř
   appky; tohle je jeho náhrada ze stejných dílů jako popover na kartě tiketu.
   - šířku dává pole, ne pevných 300 px (nastavuje se inline)
   - hlavička s názvem a křížkem se nekreslí: popisek pole je vidět nad ním
   - zaměřená položka musí být vidět, protože po nabídce jezdí šipky */
.gs-popover-sel { width: auto; min-width: 160px; --pop-pad: 6px; }
.gs-popover-sel .gs-popover-body { padding: var(--pop-pad); gap: 8px; }
.gs-pop-item:focus-visible { outline: none; background: var(--bg); box-shadow: inset 0 0 0 2px var(--focus); }
.gs-pop-search { font-size: var(--fs-sm); }
/* Hledání zůstává nahoře a nabídka mu zajíždí pod ruku (16. 9. 2026, Ondra:
   *„hledat bude sticky a obsah bude pod tím zajíždět. Ale nebude to crop úplně
   plochý, dáme tam ze spoda menší fade bílý, aby to zajíždělo ta nabídka jakoby
   do mlhy"*). Do té doby pole rolovalo se seznamem a hrana panelu ho cestou
   ořízla napůl — u nabídky, kvůli které se hledání vůbec kreslí (nad deset
   položek), tedy nešlo filtrovat bez vyrolování zpátky.

   Pás NEROLUJE, protože v rolovací části vůbec nestojí: `gsPopover()` ho
   přesune mezi hlavičku a `.gs-popover-body`. Dvě předchozí podoby byly lepivé
   a obě prosvítaly — nejdřív skulinou nad polem (záporný horní okraj: lepivý
   prvek se přisává okrajem margin boxu, ne rámečku), pak i kolem něj, jakmile
   rolování vyvezlo pruh z jeho vlastního boxu (19. 9. 2026, Ondra: *„za search
   se ukazuje obsah položek"*). Mimo rolovací část se ani jedno stát nemůže:
   pod pásem se nic nehýbe, takže nemá co překrývat.

   Mlhu kreslí `::after` pásu, ne jeho pozadí — pás končí na spodní hraně pole,
   takže přechod musí viset pod ním, přes první pixely seznamu. Průhlednou barvu
   míchá `color-mix` z `--surface`, ne klíčové slovo `transparent`: to je
   průhledná ČERNÁ a přechod by přes půl pásu zešedl (CLAUDE.md §13.2).
   Mlha nesmí brát kliknutí položce, která pod ní leží — proto `pointer-events`.

   Obal musí zůstat obalem, ne polem — `<input>` nemá `::after`, takže by mlhu
   nemělo co kreslit. Čte: gsPopHledat() v public/shared.js. */
/* Pás nese i místo na záři pole ve fokusu (`0 0 6px 1px`, ~7 px): do 13. 10. 2026
   končil spodní hranou pole, takže záři zdola přemalovala mlha a zprava ji ořízl
   panel (Vercel 12. 10. 2026, výběr klienta v Nové faktuře). Proto 8 px dole
   a nejméně 8 px po stranách. */
.gs-pop-hledat {
  flex: none; position: relative; z-index: 1;
  padding: var(--pop-pad) max(var(--pop-pad), 8px) 8px;
  background: var(--surface);
}
/* Mlha visí POD pásem, přes první pixely rolovací části — pás sám roluje s
   ničím, takže ji nemůže kreslit vlastním pozadím jako dřív. `pointer-events`
   pryč, ať se přes ni dá kliknout na položku pod ní. */
.gs-pop-hledat::after {
  content: ''; position: absolute; left: 0; right: 0; top: 100%;
  height: var(--pop-mlha); pointer-events: none;
  background: linear-gradient(to bottom,
    var(--surface),
    color-mix(in srgb, var(--surface) 0%, transparent));
}
.gs-pop-aux.active { color: var(--amber-txt); }
.gs-pop-item .gs-pop-check + .gs-pop-aux { margin-left: 0; }
.gs-prop-v.gs-prop-v-static, .gs-prop-v.gs-prop-v-static:hover { cursor: default; background: var(--bg); }
.gs-prop-v.gs-prop-v-bare.gs-prop-v-static:hover { background: transparent; padding-left: 0; }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 58 — gs-tabs (záložky uvnitř panelu, 13. 9. 2026;
   CLAUDE.md 13.3, odsouhlaseno Ondrou)
   ──────────────────────────────────────────────────────────────────
   Rozcestník UVNITŘ obsahu — detail dodavatele, diskuse na kartě tiketu.
   Hraje podle STEJNÝCH pravidel jako hlavní navigace a podnavigace: pruh
   sám nic nemaluje, aktivní záložku nese JEZDEC, který mezi nimi popojíždí
   a veze rovinu obsahu pod sebou i zuby spoje do ní. Žádné podtržení —
   appka má jeden jazyk pro „tady jsi", a ten jazyk je žebřík rovin.

   Od 15. 9. 2026 hraje i GEOMETRICKY stejně jako .sub-nav — stejné odsazení
   shora i zleva, stejné zuby, stejný krajní roh (zadání Ondry: „moduly
   nesdílejí stejný CSS a design, chceme držet stejné přístupy"). Do té doby
   měla sekce dvě vědomé odchylky a obě byly chyba:

   - **Pruh neměl vlastní pozadí** a spoléhal na to, na čem leží. V detailu
     dodavatele to byla --bg-2 a aktivní záložka --surface — dva odstíny,
     které se od sebe liší o procento. Záložky se pak nečetly jako patro,
     ale jako holý text s tučným aktivním slovem (nahlášeno 15. 9. 2026,
     screenshot z Financí). Rovinu
     pod pruhem proto kreslí pruh sám (--tabs-ground) a stojí vždy o patro
     níž než plocha obsahu; kontrast tím nezávisí na tom, kam se komponenta
     vloží.
   - **První záložka stála na hraně pruhu** a zub jezdce v krajní poloze
     přetékal ven, takže ho pruh musel ořezávat (overflow: hidden). Jenže
     s useknutým levým zubem nevypadá krajní záložka jako záložka, ale jako
     uříznutý obdélník. Pruh má proto odsazení zleva (--tabs-pad) — přesně
     jako .hd a .sub-nav — a zub se do něj vejde.

   Zbývá jediný rozdíl proti .sub-nav, a ten nutný je: rovina pod záložkami
   není závoj nad oblohou, ale konkrétní plocha (--tabs-into). Uvnitř panelu
   se nestojí na obloze, ale na desce.

   Tři tokeny, všechny přeladitelné na libovolném předkovi (stojí v :root,
   protože panel je SOUROZENEC pruhu a z pruhu by hodnotu nepřevzal):
     --tabs-into    plocha obsahu, do které se aktivní záložka spojuje
     --tabs-ground  rovina POD pruhem; musí se od --tabs-into lišit
     --tabs-pad     odsazení pruhu po stranách; sedí na gutter panelu

   Použití:
     <div class="gs-tabs">
       <button class="gs-tab active" onclick="…">Komentáře</button>
       <button class="gs-tab" onclick="…">Aktivita</button>
     </div>
     <div class="gs-tab-pane active">…</div>
     <div class="gs-tab-pane">…</div>

   Přepnutí = přehodit .active na tlačítku i na panelu (vzor: vdShowTab()
   v public/finance.js, tkDiskusePrepni() v public/tickety.js). Jezdec se
   veze sám — geometrii měří nav-slider.js (initTabSliders), který pruhy
   najde i po překreslení. Panel bez .active se nevykresluje vůbec.
   POZOR: přepínat se musí PŘEHOZENÍM TŘÍD, ne překreslením celého bloku —
   nový pruh začíná bez naměřené geometrie, takže jezdec nemá odkud přijet.

   Barvu roviny přeladí --tabs-into na jakémkoli předkovi; stojí v :root,
   protože panel je SOUROZENEC pruhu a z pruhu by hodnotu nepřevzal.

   Vzniklo sloučením `.vd-tab-*` z finance.css (vendor detail), kde u toho
   stálo TODO „consolidate with DS" — čte tedy public/finance.html i
   public/tickety.js. Figma: protějšek zatím není (dluh, viz sekce 57).
   ══════════════════════════════════════════════════════════════════ */
:root {
  --tabs-into:   var(--surface);  /* plocha obsahu, do níž se záložka spojuje */
  --tabs-ground: var(--bg);       /* rovina pod pruhem — o patro níž */
  --tabs-pad:    20px;            /* odsazení po stranách, jako .sub-nav */
  --tabs-r:      var(--r);        /* zaoblení vrchu roviny; 0 tam, kde nad pruhem stojí hlavička */
}
.gs-tabs {
  position: relative;            /* kotva pro jezdec */
  display: flex;
  align-items: stretch;
  /* Mezera mezi záložkami musí uživit zuby z obou stran (2× --joint) —
     stejná rovnice jako v .nav-tabs. */
  gap: calc(2 * var(--joint));
  /* Rovina pod pruhem. Shora --nav-inset, aby se záložka nedotkla patra nad
     sebou a byl vidět stupínek; zdola nula, tam se naopak spojit musí.
     Zleva a zprava --tabs-pad: krajní záložka se nesmí opřít o hranu, jinak
     nemá kam dát zaoblení ani zub (zadání 15. 9. 2026). Zdůvodnění výš. */
  background: var(--tabs-ground);
  padding: var(--nav-inset) var(--tabs-pad) 0;
  /* Rovina pruhu je vrchol bloku, a vrchol se zaobluje (15. 9. 2026). Kde nad
     pruhem stojí na TÉŽE rovině ještě něco (hlavička panelu), patří zaoblení
     tomu hornímu a pruh ho má nulové — viz .vd-det-hd / .vd-tab-bar ve
     finance.css. Dole nula: tam se rovina spojuje s plochou obsahu.
     Přes token, ne přes přepis pravidla: design-system.css se načítá AŽ ZA
     stránkovým CSS, takže `.vd-tab-bar{border-radius:0}` má stejnou sílu
     selektoru a prohrálo by pořadím. Vlastní vlastnost žádného protivníka
     mimo :root nemá, takže se přeladí odkudkoli. */
  border-radius: var(--tabs-r) var(--tabs-r) 0 0;
  flex-shrink: 0;
}
.gs-tab {
  position: relative;
  z-index: 1;                    /* text nad jezdcem */
  align-self: stretch;           /* doběhne na spodní hranu pruhu */
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border: none;
  /* Zaoblení jen nahoře, dole se záložka spojí s obsahem — stejné pravidlo
     jako u .nav-tab a .sub-tab. Barvu veze jezdec, ne záložka. */
  border-radius: var(--r) var(--r) 0 0;
  background: transparent;
  font-family: inherit;
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  color: var(--t2);
  white-space: nowrap;
  cursor: pointer;
  transition: color .18s;
}
.gs-tab:hover  { color: var(--t1); }
.gs-tab.active { color: var(--t1); }
.gs-tab:focus { outline: none; }
.gs-tab:focus-visible { outline: 2px solid var(--focus); outline-offset: -3px; }   /* recept sekce 65, jen dovnitř */

/* Jezdec. Geometrii (--sl-x, --sl-w) měří nav-slider.js a zapisuje ji na
   .gs-tabs; zuby spoje jsou společné s navigací (jedno pravidlo výš).
   Dokud první měření nedoběhne, chybí data-sl-ready a jezdec je skrytý bez
   přechodu — jinak by při otevření přijel zleva od nuly. */
.gs-tab-slider {
  position: absolute;
  /* POZOR na top, stejná past jako u .sub-slider: obsahující blok absolutního
     potomka je *padding box*, takže `top: 0` posadí jezdce NAD odsazení pruhu,
     ne pod něj. Záložka pak vyplní celou výšku pruhu, stupínek k patru nad ní
     zmizí a její horní roh se srazí s hlavičkou nad pruhem — přesně to, co
     Ondra nahlásil 18. 9. 2026 na modalu předplatného („ten roh má vypadat
     jako v podnavigaci"). Sekce 58 přitom slibuje, že .gs-tabs hraje
     geometricky stejně jako .sub-nav; do té doby to platilo o všem kromě
     tohohle jednoho čísla. */
  top: var(--nav-inset);
  bottom: 0;
  left: 0;
  width: var(--sl-w, 0px);
  transform: translateX(var(--sl-x, 0px));
  border-radius: var(--r) var(--r) 0 0;
  background: var(--tabs-into);
  --join-into: var(--tabs-into);
  pointer-events: none;
  z-index: 0;
  transition: transform .34s cubic-bezier(.22, 1, .36, 1),
              width     .34s cubic-bezier(.22, 1, .36, 1);
}
.gs-tabs:not([data-sl-ready]) .gs-tab-slider { opacity: 0; transition: none; }
/* Než jezdec doskočí (a kdyby JS neproběhl vůbec), drží aktivní stav záložka
   sama — bez zubů, ale se správnou plochou. Žádný rozcestník bez signálu. */
.gs-tabs:not([data-sl-ready]) .gs-tab.active { background: var(--tabs-into); }

/* Panel je rovina, do které se aktivní záložka spojuje.
   Levý horní roh si od 15. 9. 2026 drží VŽDY: první záložka už nestojí na
   hraně pruhu, ale za odsazením (--tabs-pad), takže na tom rohu nikdy
   nestojí a rovina ho má proč mít. Do té doby ho sourozenecký selektor
   `.gs-tabs + .gs-tab-pane.active` srážel na nulu — se zarovnanou krajní
   záložkou to bylo správně, s odsazenou by zůstal useknutý roh bez důvodu. */
.gs-tab-pane { display: none; }
.gs-tab-pane.active {
  display: block;
  background: var(--tabs-into);
  border-radius: var(--r);
}


/* ============================================================
   SEKCE 59 — gs-dash (bloky přehledu, 19. 9. 2026)

   Skořápka dashboardu: mřížka, karta bloku, její hlavička, velké číslo,
   podtitulek, proužek podílu, žebříček a dlaždice „přidat". Vzniklo na
   Financích jako `.fd-*` v `finance.css`; sem se to přestěhovalo ve chvíli,
   kdy tentýž přehled dostaly i Projekty (zadání Ondry: „chceme, aby se
   dashboardy komponentizovaly, ať držíme design systém a konzistenci").

   Co sem NEPATŘÍ: konkrétní vizualizace jednoho modulu — ciferník cíle,
   sloupcový graf, cesta peněz. Ty zůstávají v CSS své stránky, dokud je
   nechce druhá obrazovka. Sem patří to, co má každý dashboard stejné.

   Vzhled boxu (bílá, zaoblení, stín) nese `.dash-card` (sekce 18 + 38);
   `.gs-dash-blok` přidává jen šířku a odsazení. Skládá `gsDashVykresli()`
   v public/shared.js. Čte: public/finance.js, public/projects.js.
   ============================================================ */

.gs-dash { display: grid; grid-template-columns: repeat(12, 1fr); gap: 8px; }
/* Karty v řádku se natahují na stejnou výšku (výchozí `stretch`) — bento má
   rovný spodek řádku, ne roztřepaný. `.gs-dash` navíc nikdy není prázdné:
   vždy nese aspoň dlaždici „přidat ukazatel". */
.gs-dash-blok {
  position: relative;
  grid-column: span var(--gs-dash-span, 4);
  padding: 16px 20px 20px;
  min-width: 0;
}
/* Hover klikacího bloku nese `.kpi-clickable` (recept A, sekce 45) — podklad
   i rámeček zmodrají. Karta ale v klidu rámeček nemá (sekce 38: primární box
   drží stín), takže z receptu zbyl jen modrý fill a vypadalo to jako čtvrtý
   vymyšlený hover. Průhledná hrana v klidu to řeší: vzhled se nemění a
   `border-color` má na čem zabrat. `box-sizing: border-box` drží rozměr. */
.gs-dash-blok.kpi-clickable { border: 1px solid transparent; }
/* Hover se musí zopakovat: pravidlo nad ním má stejnou specificitu jako
   `.kpi-clickable:hover` a stojí níž, takže průhledná hrana přebila modrou
   i při najetí myší — zbyl zase jen fill (Vercel komentář 22. 9. 2026).
   Hlídá test/hover.test.js („hover nepřebije pozdější pravidlo"). */
.gs-dash-blok.kpi-clickable:hover { border-color: var(--blue); }

/* Hlavička. `-rezim` je to, co na starém přehledu chybělo: jestli se blok
   řídí filtrem období, nebo je to stav ke dni. Bez toho filtr vypadal, že
   platí na všechno, a přitom hýbal pěti kartami ze třinácti. */
.gs-dash-hd { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
/* Vzhled názvu bloku stojí níž, u bloku „Nadpis bloku je nadpis" — 26. 9. 2026
   se z 10px verzálek stala 14px věta a dvě pravidla pro jednu věc by se
   rozešla. Tady zůstává jen ta hlavička kolem něj. */
.gs-dash-hd-rezim { font-size: var(--fs-xs); color: var(--t3); white-space: nowrap; }
/* Souhrnné číslo panelu, který má uvnitř vlastní seznam — stojí na konci
   řádku hlavičky, ne pod ní. */
.gs-dash-hd-doprava {
  margin-left: auto; font-size: var(--fs-md); font-weight: var(--fw-medium);
  color: var(--blue); font-variant-numeric: tabular-nums; white-space: nowrap;
}

.gs-dash-num {
  font-size: var(--fs-num); font-weight: var(--fw-medium); letter-spacing: -.03em; line-height: 1.1;
  font-variant-numeric: tabular-nums; color: var(--t1);
}
.gs-dash-num.pos { color: var(--green-txt); }
.gs-dash-num.neg { color: var(--red-txt); }
/* Menší sourozenec velkého čísla — pro bloky, kde číslo není hlavní sdělení. */
.gs-dash-val {
  font-size: var(--fs-num-sm); font-weight: var(--fw-medium); letter-spacing: -.025em;
  font-variant-numeric: tabular-nums; color: var(--t1);
}
.gs-dash-val.pos { color: var(--green-txt); }
.gs-dash-val.neg { color: var(--red-txt); }
.gs-dash-val.warn { color: var(--amber-txt); }
.gs-dash-sub { font-size: var(--fs-xs); color: var(--t3); margin-top: 8px; font-variant-numeric: tabular-nums; }

/* Proužek podílu. Výška 6 px na zadání Ondry — do 19. 9. 2026 byl 3 px a na
   bílé kartě splýval s okolím. */
.gs-dash-pruh {
  display: flex; align-items: center; height: 6px; background: var(--pruh-bg);
  margin-top: 8px; overflow: hidden; border-radius: 3px;
}
.gs-dash-pruh i {
  display: block; height: 100%; border-radius: 3px;
  background: var(--pruh-plny); transition: width .3s;
}
/* Jediný pruh průběhu v appce (jazyk-17, 30. 9. 2026). Do té doby deset
   implementací s výškou 4–10 px, žlabem --bg / --border / --pruh-bg a barvou,
   která jednou nesla stav a jindy jen míru (zelený podíl příjmů, červená
   vyplněnost kontaktů). Barva teď nese JEN stav čerpání: .pozor (blíží se),
   .pres (přečerpáno), .hotovo (splněno). Podíl a vyplněnost jsou vždy modře.
   Čtou: domu.js, finance.js (kpiZebricek, burn subdodavatele), projects.js
   (alokace, rozpočet hodin), contacts.js, times.js, settings-panel.js, shared.js. */
.gs-dash-pruh i.pozor { background: var(--amber); }
.gs-dash-pruh i.pres { background: var(--red); }
.gs-dash-pruh i.hotovo { background: var(--green); }
/* V řádku vedle textu: bez odstupu nahoře, nezmenšuje se. Šířku dává kontext. */
.gs-dash-pruh.v-radku { margin-top: 0; flex-shrink: 0; }
/* Tlumený proužek je v Night bílý, ne modrý (Figma 5154:6567) — viz :root. */
.gs-dash-pruh i.tlumeny { background: var(--pruh-tlumeny); }
/* Druhý segment: co ještě přijde, ale není to hotová koruna. Do 19. 9. 2026
   to říkalo šrafování a poloviční výška — při 3 px neviditelné, při 6 px
   hlučné. Dnes stačí světlejší odstín. */
.gs-dash-pruh i.ocekavane { background: color-mix(in srgb, var(--blue) 28%, var(--mix-bg)); }

/* Žebříček uvnitř bloku. */
.gs-dash-celkem {
  font-size: 17px; font-weight: var(--fw-medium); font-variant-numeric: tabular-nums;
  margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid var(--border);
}
.gs-dash-radek {
  display: flex; align-items: baseline; gap: 8px; padding: 8px 0;
  border-bottom: 1px solid var(--bg); font-size: var(--fs-md);
}
.gs-dash-radek:last-child { border-bottom: none; }
/* Klikací řádek bloku — recept B (sekce 45). Vlastní třídu si na tohle stránka
   nedělá; do 19. 9. 2026 měly Projekty v jednom přehledu dva různé hovery
   (`.bill-row` a `.kpi-rank-row.clickable`) na tentýž druh řádku.
   Od 12. 10. 2026 má klikací řádek hover výpisu tabulek, tedy gradientovou
   linku a záři za kurzorem (Ondra přes Vercel: „stejné hover efekty jako
   v tabulkách"). Nekreslí ho tady, ale `.gs-radek-zare` (sekce 42), kterou
   k `clickable` přidávají `gsDashRadek` (shared.js) a Přehled (domu.js).
   Plná linka `box-shadow: inset …` by se se září sčítala. */
.gs-dash-radek.clickable { cursor: pointer; }
/* Když se řádek nevejde, ustupuje podtext, ne název: název má šířku svého
   textu, podtext dostane jen zbytek (zarovnaný doprava k částce, jak stál dřív)
   a vlastní trojtečku. Do 13. 10. 2026 měl název základ 0 a podtext se zúžit
   nesměl, takže dlouhý výčet („Správa sítí 133 %, SEO paušál 99 %…“ na Domů)
   stlačil název na nulu a vytekl přes okraj karty (kolo testování). Řádek proto
   vždy nese `-sb`, i prázdný — kreslí ho gsDashRadek (shared.js), domuRadek
   (domu.js) a úložiště v settings-panel.js. */
.gs-dash-radek-nm { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gs-dash-radek-sb { flex: 1 1 0%; min-width: 0; overflow: hidden; text-overflow: ellipsis; text-align: right; font-size: var(--fs-xs); color: var(--t3); white-space: nowrap; }
.gs-dash-radek-am { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: var(--fw-medium); }
.gs-dash-radek-am.neg { color: var(--red-txt); }
.gs-dash-radek-am.muted { color: var(--t3); font-weight: var(--fw-regular); }
.gs-dash-prazdno { font-size: var(--fs-sm); color: var(--t3); padding: 16px 0; }

/* Graf měsíců — dvojice sloupců (přijato / vydáno) na měsíc. Sem se přesunul
   19. 9. 2026 z finance.css: Projekty měly na téže věci vlastní kopii
   v zelené a červené, takže dva přehledy téže firmy mluvily jinou barvou.
   Projekce tu není — přehled ukazuje, co se stalo, ne co si appka domýšlí. */
.gs-graf{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:8px;
         height:130px;align-items:end;margin-top:8px}
.gs-graf-par{display:flex;gap:2px;align-items:flex-end;height:100%}
.gs-graf-bar{flex:1;min-height:2px;border-radius:2px 2px 0 0}
/* Graf jede v odstínech modré s gradientem (zadání Ondry 19. 9. 2026), ne
   v zelené a červené. Dvojici rozlišuje sytost, ne barva: přijato je plná
   modrá, vydáno je zesvětlená. Gradient je svislý — `--gradient-blue` je
   diagonální a na osmipixelovém sloupci by vyšel naplocho. */
/* Přijato nese --graf-in (v obou režimech do bílé), vydáno --graf-out:
   v Day světle modré, v Night do inkoustu. Hodnoty v :root a sekci 1. */
.gs-graf-bar-in{background:var(--graf-in)}
.gs-graf-bar-out{background:var(--graf-out)}
.gs-graf-x{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:8px;margin-top:8px;
           font-size:var(--fs-xs);color:var(--t3);text-align:center;font-variant-numeric:tabular-nums}
/* Letopočet pod zkratkou měsíce — vlastní řádek, ať se osa nerozšiřuje. */
.gs-graf-rok{display:block;font-style:normal;font-size:var(--fs-xs);color:var(--t3);
  letter-spacing:.04em;min-height:11px}
.gs-graf-legenda{display:flex;gap:16px;flex-wrap:wrap;font-size:var(--fs-xs);color:var(--t3);margin-top:12px}
.gs-graf-pozn{color:var(--t3)}
.gs-graf-teck{display:inline-block;width:9px;height:9px;margin-right:8px;vertical-align:-1px}
.gs-graf-teck-in{background:var(--blue)}
.gs-graf-teck-out{background:var(--graf-teck-out)}


/* Plus v rohu karty — vysvětlivka, akce bloku, přidat další, skrýt tenhle.
   Karta má vlastní odsazení, takže tlačítko stojí absolutně; proto má
   `.gs-dash-blok` position: relative. */
.gs-dash-akce {
  position: absolute; top: 12px; right: 12px; width: 26px; height: 26px;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: none; border-radius: var(--r-ctrl); cursor: pointer;
  color: var(--t3); opacity: 0; transition: opacity .15s, background .15s, color .15s;
}
.gs-dash-blok:hover .gs-dash-akce, .gs-dash-akce:focus-visible { opacity: 1; }
.gs-dash-akce:hover { background: var(--hover); color: var(--t1); }
/* Na dotyku hover neexistuje — tam je ikona vidět pořád, jinak by se k akcím
   nedalo dostat. */
@media (hover: none) { .gs-dash-akce { opacity: 1; } }

/* Dlaždice „přidat ukazatel" na konci mřížky. Drží nejmenší šířku bloku,
   aby se řadila za poslední kartu, ne pod ni. Do 12. 10. 2026 měla
   přerušovaný rámeček; Ondra chtěl všude místo čárkovaných rámečků plný okraj
   se září jako u tlačítek, takže plochu, okraj i hover dává .gs-btn-secondary
   (shared.js ji přidává spolu s touto třídou). */
.gs-dash-pridat {
  grid-column: span 3; display: flex; align-items: center; justify-content: center;
  gap: 8px; min-height: 96px; padding: 16px 20px; cursor: pointer;
  border-radius: var(--r);
  font-family: var(--ff); font-size: var(--fs-md); font-weight: var(--fw-medium);
}

/* Klikací karta nese `arrow_outward` u popisku — stejně jako `.stat-card`.
   Glyf z ikonového fontu, ne typografická šipka (sekce 4). */
.gs-dash-blok.kpi-clickable .gs-dash-hd-nazev::after {
  content: 'arrow_outward'; font-family: 'Material Symbols Rounded';
  font-variation-settings: 'FILL' 0; font-size: var(--fs-xs); opacity: .5;
  text-transform: none; letter-spacing: normal; margin-left: 2px;
}

/* Zlom mřížky: na užší obrazovce půlka, na telefonu celá šířka. Blok, který
   potřebuje celou šířku dřív (graf, časová osa), si to řekne sám v CSS své
   stránky přes `[data-blok="…"]`. */
@media (max-width: 1100px) { .gs-dash-blok { grid-column: span 6; } }
@media (max-width: 600px)  { .gs-dash-blok, .gs-dash-pridat { grid-column: span 12; } }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 60 — gs-obd + gs-kal (filtr období a kalendář, 21. 9. 2026;
   CLAUDE.md 13.3, návrh schválený Ondrou)
   ──────────────────────────────────────────────────────────────────
   Návrh: design artifact „Kalendář" a Figma sekce DATE PICKER (5183:502,
   docs/figma.md §4). Logika: shared.js „Kalendář a filtr období".

     .gs-obd        filtr období (návrh 2, 22. 9. 2026) — šipky po stranách
                    a jeden box `.gs-obd-k`, zavřený i otevřený (`.gs-open`)
                    stejný; markup skládá server (lib/obdobi-html.js), stav
                    drží skrytá pole `input[data-obd]`, `gsObdInit()` jen napojí
     .gs-obd-pop    panel filtru: průhledný obal dvou boxů — zkratky
                    (`.gs-obd-zkratky`) a kalendář; předvolby stránky jsou
                    od 22. 9. 2026 jen tyhle zkratky (gsObdPredvolby)
     .gs-obd-dl     box s obdobím: `.gs-obd-cast` = datum (den + měsíc/rok),
                    přes víc měsíců dvě s `.gs-obd-pomlcka`; `.cele` = kraj
                    dat u prázdného pole (bez vlastního vzhledu), `.akt` = panel je otevřený
     .gs-kal-pop    panel kalendáře (varianta `.gs-popover`, sekce 57)
     .gs-valec      váleček číslic — každá číslice je sloupec 0–9, který
                    odjede na svou hodnotu (jen transform, žádný časovač)

   Modře je jen to, co člověk vybral: začátek a konec (přechod), období
   a měsíce, přes které vede (--blue-lt). Dnešek má jen pulzující kroužek,
   aktuální měsíc se nezvýrazňuje — vypadal by jako předvybraný (Ondra).
   Tvar dnů, dlaždic a čipů je --kal-r (6px): menší než pole (--r-field),
   protože jich stojí 42 vedle sebe.
   ══════════════════════════════════════════════════════════════════ */
.gs-obd, .gs-kal-pop { --kal-r: 6px; --kal-zare: color-mix(in srgb, var(--blue) 28%, transparent); }

/* ── Filtr období ─────────────────────────────────────────────────── */
/* Markup přichází hotový (lib/obdobi-html.js), takže není co schovávat:
   do 22. 9. 2026 tu stála pravidla, která před postavením karty schovávala
   stará pole Od/Do, křížek a přepínač předvoleb (problikávaly po refreshi). */
/* Šedý box bez vlastní karty — stojí přímo v bílé liště (návrh 2). Jeden
   box vždy, i otevřený a i přes víc měsíců (Ondra 22. 9. 2026). */
.gs-obd { display: inline-flex; align-items: center; gap: 8px; }
/* Úzké šipky: období o měsíc (celé měsíce o svou délku) zpět / dál,
   gsObdPosun. Výška dlaždice. */
.gs-obd-sip {
  width: 20px; height: 48px; padding: 0; border: none; border-radius: var(--kal-r);
  background: var(--bg); color: var(--t2); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; transition: background .15s;
}
.gs-obd-sip:not(:disabled):hover { background: var(--hover); color: var(--t1); }
/* Vypnutá je šipka jen do prvního vykreslení skriptem (lib/obdobi-html.js).
   Tlumená ani poloprůhledná není — Ondra 22. 9. 2026: „nebude tam snížená
   opacita" (do té doby .6 a --gray-4 a u „Tento rok" navíc nešla kliknout). */
.gs-obd-sip:disabled { cursor: default; }
.gs-obd-pomlcka { font-size: var(--fs-xl); font-weight: var(--fw-medium); color: var(--t1); }
.gs-obd-dl {
  height: 48px; min-width: 104px; padding: 0 16px; border: none; border-radius: var(--kal-r);
  background: var(--bg); color: var(--t1); font-family: inherit; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  transition: background .15s, box-shadow .15s;
}
.gs-obd-dl:hover { background: var(--hover); }
.gs-obd.gs-open .gs-obd-dl.akt {
  background: var(--surface);
  box-shadow: 0 0 0 2px var(--blue), 0 0 0 6px color-mix(in srgb, var(--blue) 14%, transparent),
              0 8px 24px var(--kal-zare);
}
.gs-obd-obsah { display: flex; align-items: center; gap: 16px; }
.gs-obd-cast { display: flex; align-items: center; gap: 8px; }
/* `.cele` (pole je prázdné, box ukazuje kraj dat) už tlumené není: do
   22. 9. 2026 bylo --t3, a „Tento rok" ve Financích tak vypadal jako vypnutý
   filtr (Ondra přes Vercel: „barvy u dat nebudou potlačené"). Třídu dál
   nastavuje gsObdKresliKompakt — nese význam, ne vzhled. */
.gs-obd-den {
  display: inline-flex; justify-content: flex-end;
  font-size: 28px; line-height: 1; font-weight: var(--fw-bold); letter-spacing: -.035em;
  font-variant-numeric: tabular-nums;
}
.gs-obd-my { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.gs-obd-mes, .gs-obd-rok { display: inline-flex; font-size: var(--fs-xs); line-height: 1; font-weight: var(--fw-medium); }
.gs-obd-mes { text-transform: uppercase; letter-spacing: .08em; }
.gs-obd-rok { color: var(--t3); font-variant-numeric: tabular-nums; }

/* ── Váleček ──────────────────────────────────────────────────────── */
.gs-valec {
  display: inline-block; height: 1.1em; line-height: 1.1em; overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 16%, #000 84%, transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0, #000 16%, #000 84%, transparent 100%);
}
/* Obal válečků. Nasazuje ho `gsKalValec()` sám, protože na něm stojí účaří
   celého řádku a zapomenout se nesmí (§14.7 — mechanismus, ne kázeň).
   Proč vůbec: `inline-block` s `overflow: hidden` má v řádkové sazbě účaří na
   SPODNÍ hraně boxu (CSS 2.1 §10.8.1), ne na účaří písma. Vedle postavený
   holý znak (`:` mezi hodinami a minutami, „min" za délkou, „Po" před datem)
   se tedy zarovná o ~0,18 em níž — na 26px písmu 4,6 px, a vypadá to jako
   tečka u paty čísla. Uvnitř flex kontejneru se ale `display` válečku
   povýší na blokový, čímž §10.8.1 přestane platit a váleček nabídne účaří
   svého písma — stejné jako holý znak vedle. Přesně tak to má i návrh
   („ZapisHodin", `<span style="display:inline-flex">` kolem okének).
   Hlásil Ondra z produkce 23. 9. 2026 na `11:15`. */
.gs-valec-rada { display: inline-flex; align-items: baseline; }
.gs-valec-cis { width: .62em; }
/* Nečíslice (tečka za dnem, čárka v desetinné délce) se nikam neválí, takže
   nepatří do maskovaného okénka — jinak jim vytrácení na spodní hraně ukrojí
   dotah. Stejné rozhodnutí má návrh. */
.gs-valec-holy { overflow: visible; -webkit-mask-image: none; mask-image: none; }
.gs-valec-pas { display: block; transition: transform .7s cubic-bezier(.22, 1, .36, 1); will-change: transform; }
.gs-valec-znak { display: block; height: 1.1em; text-align: center; white-space: nowrap; }

/* ── Panel kalendáře ──────────────────────────────────────────────── */
.gs-popover.gs-kal-pop {
  width: 320px; max-height: none; overflow: visible;
  box-shadow: 0 16px 40px color-mix(in srgb, var(--gray-9) 10%, transparent),
              0 30px 70px -30px color-mix(in srgb, var(--blue) 45%, transparent);
  transition: left .35s cubic-bezier(.22, 1, .36, 1);
}
.gs-kal-pop .gs-popover-body { padding: 12px; overflow: visible; }
.gs-kal { display: flex; flex-direction: column; gap: 8px; }
.gs-kal-hd { display: flex; align-items: center; gap: 8px; padding-left: 4px; position: relative; }
.gs-kal-tecka {
  width: 6px; height: 6px; border-radius: 50%; background: var(--blue);
  box-shadow: 0 0 8px color-mix(in srgb, var(--blue) 60%, transparent);
}
.gs-kal-titul { flex-grow: 1; font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--t1); }
.gs-kal-rok-btn {
  height: 32px; padding: 0 8px; border: none; border-radius: var(--kal-r); background: transparent;
  color: var(--t1); font-family: inherit; font-size: 15px; font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums; cursor: pointer; display: flex; align-items: center; gap: 8px;
  transition: background .15s, box-shadow .15s;
}
.gs-kal-rok-txt { min-width: 4ch; text-align: right; }   /* rok se při přepnutí nezúží */
.gs-kal-rok-btn:hover { background: var(--hover); }
.gs-kal-rok-btn.on {
  background: var(--blue-lt); color: var(--blue-txt);
  box-shadow: inset 0 0 0 1.5px var(--blue), 0 0 14px color-mix(in srgb, var(--blue) 22%, transparent);
}

.gs-kal-obsah.gs-kal-vstup { animation: gs-kal-vstup .28s cubic-bezier(.22, 1, .36, 1) both; }
@keyframes gs-kal-vstup { from { opacity: 0; transform: translateY(6px) scale(.985); } to { opacity: 1; transform: none; } }

/* Měsíce: všech dvanáct najednou. Klik jen přepne dny pod nimi. */
.gs-kal-mesice {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 3px; padding: 3px;
  margin-bottom: 8px; border-radius: var(--r-sm); background: var(--bg);
}
.gs-kal-mes, .gs-kal-den, .gs-kal-rok, .gs-kal-mesv {
  border: none; border-radius: var(--kal-r); background: transparent; font-family: inherit; cursor: pointer;
  transition: box-shadow .15s, background .15s;
}
.gs-kal-mes { height: 28px; font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--t2); }
.gs-kal-mes.v-obdobi { background: var(--blue-lt); color: var(--blue-txt); }
.gs-kal-mes.zobrazeny {
  background: var(--surface); color: var(--t1);
  box-shadow: 0 1px 3px color-mix(in srgb, var(--gray-9) 12%, transparent);
}
/* Kraj období tohle pravidlo vynechává: tři třídy by přebily bílé písmo
   čipu a „Led" byl modrý na modrém (22. 9. 2026). */
.gs-kal-mes.zobrazeny.v-obdobi:not(.obd-zac, .obd-kon) { color: var(--blue-txt); }
/* Kraje období vypadají přesně jako vybraný den (`.gs-kal-den.vybrany` níž),
   ať je začátek vidět i z konce období. Zobrazený kraj se nijak neodlišuje —
   bílá vnitřní linka působila jako jiný prvek (21. 9. 2026). `obd-pred/po` =
   období jde přes hranu roku, čip vybledne k tomu kraji (jako pás dní). */
.gs-kal-mes.obd-zac, .gs-kal-mes.obd-kon {
  position: relative; z-index: 1;
  background: linear-gradient(180deg, color-mix(in srgb, var(--blue) 92%, var(--mix-bg)), var(--blue-dk));
  color: var(--white);
  box-shadow: 0 4px 14px color-mix(in srgb, var(--blue) 45%, transparent),
              0 0 0 3px color-mix(in srgb, var(--blue) 12%, transparent);
}
.gs-kal-mes.obd-pred:not(.obd-zac) { background: linear-gradient(90deg, transparent, var(--blue-lt) 70%); }
.gs-kal-mes.obd-po:not(.obd-kon) { background: linear-gradient(270deg, transparent, var(--blue-lt) 70%); }
.gs-kal-mes.zobrazeny:is(.obd-pred, .obd-po):not(.obd-zac, .obd-kon) { background: var(--surface); }

/* Režim měsíce (`<input type="month">`, 12. 10. 2026): dvanáct měsíců
   zobrazeného roku v mřížce 3 × 4. Vybraný a letošní měsíc mají stejný
   vzhled jako vybraný den a dnešek (pravidla níž). */
.gs-kal-mesmrizka { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; }
.gs-kal-mesv { height: 44px; font-size: var(--fs-md); font-weight: var(--fw-medium); color: var(--t1); }
.gs-kal-mesv:disabled { opacity: .35; cursor: default; }

/* Dny: šest týdnů od pondělí. Pás období běží pod tlačítky (`.pas`)
   a zaobluje se na krajích období i na krajích týdne. */
.gs-kal-mrizka { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); grid-template-rows: 26px repeat(6, 34px); }
.gs-kal-tyd {
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-xs); font-weight: var(--fw-medium); letter-spacing: .06em; text-transform: uppercase; color: var(--t3);
}
.gs-kal-bunka { display: flex; align-items: center; justify-content: center; }
.gs-kal-bunka.pas { --pas: var(--blue-lt); background: var(--pas); }
.gs-kal-bunka.pas.nahled { --pas: color-mix(in srgb, var(--blue) 7%, transparent); }
/* Pás pokračuje za kraj týdne: vybledne místo zaoblení, jinak kraj řádku
   vypadá jako začátek období (21. 9. 2026). */
.gs-kal-bunka.pas-dal-l { background: linear-gradient(90deg, transparent, var(--pas) 75%); }
.gs-kal-bunka.pas-dal-p { background: linear-gradient(270deg, transparent, var(--pas) 75%); }
.gs-kal-bunka.pas-l { border-top-left-radius: var(--kal-r); border-bottom-left-radius: var(--kal-r); }
.gs-kal-bunka.pas-p { border-top-right-radius: var(--kal-r); border-bottom-right-radius: var(--kal-r); }
.gs-kal-den {
  width: 34px; height: 32px; font-size: var(--fs-md); font-variant-numeric: tabular-nums; color: var(--t1);
}
.gs-kal-den.cizi { color: color-mix(in srgb, var(--gray-4) 60%, var(--mix-bg)); }
.gs-kal-den.v-rozsahu { color: var(--blue-txt); font-weight: var(--fw-medium); }
.gs-kal-den.v-rozsahu.cizi { color: color-mix(in srgb, var(--blue) 50%, var(--mix-bg)); }
.gs-kal-den:disabled { opacity: .35; cursor: default; }
/* Vybraný den leží nad sousedními buňkami — jinak mu pás dalšího řádku
   (vykreslený později) usekne záři (21. 9. 2026, produkce). */
.gs-kal-den.vybrany, .gs-kal-den.nahled-konec { position: relative; z-index: 1; }
.gs-kal-den.vybrany, .gs-kal-rok.vybrany, .gs-kal-mesv.vybrany {
  background: linear-gradient(180deg, color-mix(in srgb, var(--blue) 92%, var(--mix-bg)), var(--blue-dk));
  color: var(--white); font-weight: var(--fw-medium);
  box-shadow: 0 4px 14px color-mix(in srgb, var(--blue) 45%, transparent),
              0 0 0 3px color-mix(in srgb, var(--blue) 12%, transparent);
}
.gs-kal-den.nahled-konec {
  background: var(--surface); color: var(--blue-txt); font-weight: var(--fw-medium);
  box-shadow: inset 0 0 0 1.5px var(--blue), 0 2px 10px color-mix(in srgb, var(--blue) 22%, transparent);
}
/* Dnešek je jen tichá šedá linka, bez pulsu a bez modré (Ondra 22. 9. 2026:
   „modré je tam moc"). Puls přesahoval buňku a pás dalšího řádku ho usekl.
   Modrá patří výběru, ne orientačnímu bodu. */
.gs-kal-den.dnes, .gs-kal-rok.dnes, .gs-kal-mesv.dnes {
  font-weight: var(--fw-medium); box-shadow: inset 0 0 0 1.5px var(--border-md);
}
.gs-kal-den:not(:disabled):hover, .gs-kal-mes:hover, .gs-kal-rok:hover, .gs-kal-mesv:not(:disabled):hover {
  box-shadow: inset 0 0 0 1.5px var(--blue), 0 0 14px var(--kal-zare);
}
/* Záře přesahuje buňku; nad sousedy, jinak ji pás dalšího řádku usekne. */
.gs-kal-den:not(:disabled):hover { position: relative; z-index: 1; }

/* Rok: malá nabídka pod tlačítkem, kalendář zůstává vidět (jako Toggl, Ondra
   22. 9. 2026). Jen roky, ze kterých jsou data, a letošek (gsKalRoky) — do té
   doby mřížka dvanácti let přes celý kalendář, i s rokem 2032. Víc let roluje. */
.gs-kal-roky {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 2;
  min-width: 96px; max-height: 232px; overflow-y: auto; padding: 4px;
  display: flex; flex-direction: column; gap: 2px;
  background: var(--surface); border-radius: var(--r-sm); box-shadow: var(--sh-lg);
}
.gs-kal-rok {
  height: 36px; flex-shrink: 0; font-size: var(--fs-base); font-variant-numeric: tabular-nums;
  color: var(--t1); font-weight: var(--fw-medium);
}

/* Pata: Vymazat · počet dní · Dnes. */
.gs-kal-ft { display: flex; align-items: center; gap: 4px; padding-top: 8px; border-top: 1px solid var(--bg); }
.gs-kal-akce {
  height: 32px; padding: 0 8px; border: none; border-radius: var(--kal-r); background: transparent;
  color: var(--t3); font-family: inherit; font-size: var(--fs-md); font-weight: var(--fw-medium); cursor: pointer;
}
.gs-kal-akce:hover { background: var(--hover); }
.gs-kal-dnes { color: var(--blue); margin-left: auto; }
.gs-kal-pocet { flex-grow: 1; display: flex; align-items: baseline; justify-content: center; gap: 4px; }
.gs-kal-pocet[hidden] { display: none; }
.gs-kal-cislo {
  display: inline-flex; font-size: var(--fs-2xl); line-height: 1; font-weight: var(--fw-bold);
  letter-spacing: -.02em; font-variant-numeric: tabular-nums; color: var(--t1);
}
.gs-kal-pocet.ceka .gs-kal-cislo { color: var(--blue); }
.gs-kal-jedn { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--t3); }
.gs-kal-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* Pole, které kalendář spravuje, nemá systémovou ikonu — otevírá se klikem
   kamkoli do pole a ikona by slibovala systémové okno. */
input:is([type=date], [type=month]):not([data-gs-nativni="1"])::-webkit-calendar-picker-indicator { display: none; }

/* ── Panel filtru období: zkratky + kalendář ─────────────────────── */
.gs-popover.gs-kal-pop.gs-obd-pop {
  width: auto; background: transparent; border: none; box-shadow: none; border-radius: 0;
}
.gs-obd-pop .gs-popover-body { padding: 0; }
.gs-obd-panely { display: flex; align-items: stretch; gap: 8px; }
.gs-obd-zkratky, .gs-obd-pop .gs-kal {
  box-sizing: border-box; padding: 12px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: 0 16px 40px color-mix(in srgb, var(--gray-9) 10%, transparent),
              0 30px 70px -30px color-mix(in srgb, var(--blue) 45%, transparent);
}
.gs-obd-pop .gs-kal { width: 320px; }
.gs-obd-zkratky { width: 212px; display: flex; flex-direction: column; gap: 2px; }
.gs-obd-zkr-hd {
  display: flex; align-items: center; height: 32px; padding-left: 8px; margin-bottom: 8px;
  font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--t1);
}
.gs-obd-zkr-oddel { height: 8px; }
.gs-obd-zkr {
  height: 34px; padding: 0 8px; border: none; border-radius: var(--r-sm); background: transparent;
  color: var(--t1); font-family: inherit; font-size: var(--fs-base); font-weight: var(--fw-medium);
  cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  text-align: left; transition: background .15s, color .15s;
}
.gs-obd-zkr:hover { background: var(--hover); }
.gs-obd-zkr.on { background: var(--blue-lt); color: var(--blue-txt); }
/* Pulzující bod = právě zvolená zkratka. */
.gs-obd-bod {
  width: 7px; height: 7px; border-radius: 50%; background: var(--blue); flex-shrink: 0;
  animation: gs-obd-bod 1.8s ease-out infinite;
}
@keyframes gs-obd-bod {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--blue) 50%, transparent); }
  70%  { box-shadow: 0 0 0 6px color-mix(in srgb, var(--blue) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--blue) 0%, transparent); }
}
/* Telefon: boxy pod sebou, kalendář první — zkratky jsou až pod ním. */
@media (max-width: 600px) {
  .gs-obd-panely { flex-direction: column-reverse; }
  .gs-obd-zkratky { width: 320px; max-width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .gs-valec-pas, .gs-popover.gs-kal-pop { transition: none; }
  .gs-kal-obsah.gs-kal-vstup, .gs-obd-bod { animation: none; }
}

/* ══════════════════════════════════════════════════════════════════
   SEKCE 61 — RESPONSIVITA (19. 9. 2026, na zadání „chceme, aby to
   fungovalo všude i na mobilu")
   ──────────────────────────────────────────────────────────────────
   Tři zlomy. Víc jich appka mít nebude:

     ≤ 1100px  úzký desktop — mřížky přehledu z šesti stop na tři, karta
               detailu přestane stát vedle okna (existovalo už dřív)
     ≤  900px  tablet — z hlavičky odejdou popisky záložek a název appky
     ≤  600px  telefon — jeden sloupec, výpisy se posouvají do strany,
               modál na celou plochu

   Číslo se do `@media` píše natvrdo, protože CSS proměnná tam nefunguje —
   proto ta tři a ne třicet. Kdo potřebuje čtvrté, řeší to zlomem
   komponenty, ne oknem: `minmax()`, `auto-fit`, `flex-wrap`. Těch se
   appka drží i na širokém okně, takže většina obsahu se zúží sama a
   tahle sekce dorovnává jen to, co má pevný rozměr.

   **Zlom nikdy neschová data ani akci.** Schovat smí popisek, který
   nese i ikona vedle něj, a ozdobu. Nesmí schovat sloupec s číslem ani
   tlačítko — od toho je posuv do strany a zalomení. Hlídá
   `test/responsivita.test.js`.
   ────────────────────────────────────────────────────────────────── */

/* ── ≤ 900px — tablet ─────────────────────────────────────────────── */
@media (max-width: 900px) {
  /* Pruhy se stlačí. Výšky jsou tokeny, takže se s nimi posunou i roviny
     (.pl-2/.pl-3 na ně počítají `top`) — přepsat je tady stačí jednou. */
  :root { --hd-h: 60px; --subnav-h: 44px; }

  .hd      { padding-left: 12px; padding-right: 12px; gap: 8px; }
  .sub-nav { padding-left: 12px; padding-right: 12px; }

  /* Záložky na ikony. Popisek mizí jen proto, že vedle něj stojí ikona,
     která říká totéž; `title` zůstává. Odsazení 34px bylo počítané na
     text vedle ikony — bez něj by byla záložka širší než vysoká. */
  .nav-tab { padding: 8px 16px; }
  .nav-tab > span:not(.ms) { display: none; }

  /* Odsazení obsahu od kraje: 22px bylo na plátno přes celé okno. */
  .kpi-filter-card { margin: 16px 12px 0; }
  .kpi-grid { padding: 12px; }
  body[data-page="projects"] #pv-section-projekty { padding: 16px; }
}

/* ── ≤ 600px — telefon ────────────────────────────────────────────── */
@media (max-width: 600px) {
  /* Šest modulů se do 375px nevejde ani jako ikony — pruh se posouvá.
     Jezdec je uvnitř `.nav-tabs` absolutně pozicovaný, takže jede s ním
     a spoj do roviny pod sebou se nerozpadne. Posuvník se nekreslí: pruh
     je vysoký 60px a vodorovná lišta by v něm zabrala pětinu. */
  .nav-tabs {
    flex: 1; min-width: 0;
    /* Odstup od značky (20px na desktopu) tady mizí — pruh se na telefonu
       posouvá a každý pixel je záložka navíc. */
    margin-left: 0;
    overflow-x: auto; overflow-y: hidden;
    scrollbar-width: none; -ms-overflow-style: none;
    overscroll-behavior-x: contain;
  }
  .nav-tabs::-webkit-scrollbar { display: none; }
  .nav-tab { flex-shrink: 0; }

  /* Podnavigace stejně — je to týž pruh o patro níž. */
  .sub-nav { overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
  .sub-nav::-webkit-scrollbar { display: none; }
  .sub-tab { flex-shrink: 0; }

  .hd { gap: 4px; padding-left: 8px; padding-right: 8px; }
  /* Na 375px stojí vedle sebe značka, šest záložek a čtyři kolečka. Logotyp
     se zmenší přesně na dokumentované minimum 90px (docs/brand.md) a níž ne:
     pod ním se značka přestává číst. Zbytek místa si vezme pruh záložek,
     který se posouvá. Schovat značku nepřipadá v úvahu — je to jediné místo
     v appce, kde stojí. */
  .hd-logotyp { width: 90px; }
  .kpi-filter-card { margin: 8px 8px 0; }
  .kpi-grid { padding: 8px; gap: 8px; }

  /* Filtrační lišta: akce se na telefonu nevejdou vedle hledání, takže
     `margin-left: auto` přestane platit a skupina spadne pod něj celá.
     Zmizet nesmí — je v ní hlavní akce stránky. */
  .gs-time-filter { padding: 8px; }
  .ftf-actions { margin-left: 0; width: 100%; }

  /* Výpis se do 375px nezúží — má pevné stopy sloupců a schovat sloupec
     s číslem sekce nedovoluje. Posouvá se tedy do strany uvnitř svého
     rámu, ne celým oknem: `min-width: max-content` drží řádku její šířku,
     `overflow-x` na obalu ji nechá odjet. Záhlaví zůstává přilepené
     nahoře, svisle. */
  .tbl-wrap { overflow-x: auto; }
  .tbl-header, .tbl-row { min-width: max-content; }

  /* Modál: 700px na 375px okně je celá obrazovka i tak — ať to aspoň
     přizná a nenechá kolem sebe 20px rám. Zůstává na středu; „list
     zespoda" je jiná komponenta, ne zlom téhle (§13.3). */
  .modal-overlay { padding: 8px; }
  .modal, .modal.modal-sm, .modal.modal-lg { max-width: none; max-height: 94vh; }

  /* Nastavení stojí na dvou sloupcích vedle sebe (kategorie | obsah).
     Na telefonu jsou nad sebou a kategorie se listují do strany — je to
     táž navigace jako pruh záložek nahoře, jen v modálu. */
  .modal-bento { height: 100%; max-height: none; }
  .settings-modal { flex-direction: column; }
  .settings-sidebar {
    width: 100%; flex-direction: row; overflow-x: auto; overflow-y: hidden;
    border-right: none; border-bottom: 1px solid var(--border);
    padding: 8px; gap: 4px; scrollbar-width: none;
  }
  .settings-sidebar::-webkit-scrollbar { display: none; }
  .settings-cat-item { flex-shrink: 0; white-space: nowrap; }
  /* Dno panelu je na telefonu jeho pravý konec — odhlášení tedy odtlačí
     vodorovný `auto` a linku nad sebou vymění za linku vedle sebe. */
  .settings-sidebar-odhlasit {
    margin-top: 0; margin-left: auto; padding-top: 0; padding-left: 8px;
    border-top: none; border-left: 1px solid var(--border);
  }

  /* Panely s pevnou šířkou. `.ind-mgr-panel` si strop `calc(100vw - 40px)`
     nese sám, ale jeho širší varianty ho přebíjejí vlastním `width`, a
     `.fak-panel`/`.fak-picker-modal` strop nikdy neměly — na 375px okně
     tedy visely 45 px přes kraj a konec formuláře nešel vidět ani
     doscrollovat, protože overlay je `position: fixed`. */
  .ind-mgr-panel--wide, .scraping-panel, .invoicing-panel,
  .fak-panel, .fak-picker-modal { width: 100%; max-width: calc(100vw - 24px); }
  .fak-panel-overlay { padding: 12px; }
}

/* ══════════════════════════════════════════════════════════════════
   SEKCE 62 — gs-cas + gs-osa (čas ve výkazu na ose dne, 23. 9. 2026;
   CLAUDE.md 13.3, návrh schválený Ondrou)
   ──────────────────────────────────────────────────────────────────
   Návrh: design artifact „Čas ve výkazu — modal" (ZapisHodin.dc.html).
   Logika: times.js „Osa dne". Válečky číslic a kalendář jsou ze sekce 60 —
   tohle je nestaví znovu, jen je používá.

     .gs-cas        řádek dlaždic: datum · od · šipka · do · délka
     .gs-cas-dl     dlaždice 72 px (datum, od, do) — šedá plocha, ne pole:
                    píše se do ní klikem na číslo, ne kurzorem
     .gs-cas-seg    hodiny nebo minuty zvlášť; klik je vymění za `input`
     .gs-cas-pm     krokování, vidět až pod myší nebo při fokusu dlaždice
     .gs-cas-cipy   rychlé délky (15 min … 2 h)
     .gs-osa        pravítko dne: ryska po 15 min, celá hodina vyšší
     .gs-osa-blok   vybraný úsek s úchyty na obou koncích
     .gs-osa-mimo   záznamy, které ten den na ose už stojí

   Proč pravítko a ne plný blok: výběr je vidět na obarvených ryskách
   a popiskách, takže pod ním zůstane čitelné, co na ose už je. Šířka okna
   je 12 h z 24 — celý den by měl rysku po 1,5 px a nedal by se trefit.
   Akcentní barva je jedna (`--osa-akcent`) a při překryvu nebo průchodu
   půlnocí se přepne na červenou; nastavuje ji times.js na `.gs-osa-obal`,
   aby se obarvilo pravítko, blok i popisky jedním zápisem.
   ══════════════════════════════════════════════════════════════════ */
/* Mezery v celé sekci povolil Ondra 23. 9. 2026 („v tom detailu záznamu je vše
   hrozně blízko u sebe"): dlaždice, čipy, pravítko a popisky hodin stály na
   6–10 px a čtyři vrstvy nad sebou pak splývaly v jednu šedou plochu. */
.gs-cas { display: flex; align-items: center; gap: 8px; }

.gs-cas-dl {
  position: relative; flex: 0 0 116px; height: 72px; padding: 0 3px;
  box-sizing: border-box; border: none; border-radius: var(--r-lg);
  background: var(--bg); color: var(--t1); font-family: inherit;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; line-height: 1; text-align: center; cursor: default; outline: none;
  transition: background .15s;
}
.gs-cas-dl:hover, .gs-cas-dl:focus-visible, .gs-cas-dl:focus-within {
  background-image: linear-gradient(var(--hover), var(--hover));
}
/* Datum je tlačítko (otevírá kalendář ze sekce 60), proto širší kurzor
   i vlastní šířka podle obsahu — „Po 1." a „Čt 28." nejsou stejně široké. */
.gs-cas-datum { flex: 0 0 auto; padding: 0 12px; cursor: pointer; }
/* Datum drží pořád `input[type=date]` — kalendář sekce 60 do něj píše a formulář
   ho čte. Je schovaný stejně jako v `.gs-date-pill`, ne `hidden`: skrytý prvek
   nejde zaostřit a panel po výběru dne vrací fokus zpátky do pole. */
.gs-cas > input[type=date] { position: absolute; opacity: 0; width: 1px; height: 1px; padding: 0; border: 0; pointer-events: none; }
.gs-cas-datum-hl { display: flex; align-items: baseline; gap: 4px; }
.gs-cas-datum-dt { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--t3); }

.gs-cas-cislo {
  font-size: var(--fs-num-sm); font-weight: var(--fw-bold); letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; display: inline-flex; align-items: baseline;
  /* Záporné prostrkání ubere mezeru i ZA poslední číslicí, takže je box o ni
     užší než to, co je vidět, a vycentrovaný text sedí kousek vpravo. Padding
     tu mezeru vrací zpátky. (Ondra 23. 9. 2026: „čísla jsou víc v pravo a ne
     na středu.") Zbytek nesouměrnosti dělá glyf `1`, který má v tabulkových
     číslicích širší levý okraj — ten se CSS srovnat nedá. */
  padding-right: .03em;
}
.gs-cas-pop { font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--t3); }
/* Dvojtečka je holý znak, přesně jako v návrhu — žádná vlastní krabička.
   Že nespadne pod číslice, řeší `.gs-valec-rada` u sousedního válečku
   (sekce 60). První pokus 23. 9. 2026 dával dvojtečce tutéž výšku i
   `overflow` jako válečku; uvnitř flex kontejneru se ale `inline-block`
   povýší na blokový, §10.8.1 přestane platit a box nabídne účaří písma —
   takže se tím nezměnilo nic a rozdíl 4,6 px zůstal.
   Zbývá jen vzduch kolem: znak `:` je v Geistu užší než okénko číslice,
   takže bez něj se čas slepí (Ondra 23. 9. 2026: „letter spacing rozhozený"). */
.gs-cas-dvoj { padding: 0 .04em; }

/* Segment se chová jako text, který jde přepsat — proto kurzor `text`
   a o stupeň tmavší podklad pod myší, ne rámeček pole (§13.2: pole má
   --r-field, tohle polem není, dokud se do něj neklikne). */
.gs-cas-seg { border-radius: var(--kal-r, 6px); cursor: text; transition: background .15s; }
.gs-cas-seg:hover { background: var(--hover); }
.gs-cas-vstup {
  width: 1.36em; height: 1.15em; padding: 0; border: none; border-radius: var(--kal-r, 6px);
  background: var(--surface); color: var(--t1); font: inherit; letter-spacing: inherit;
  text-align: center; outline: none; box-shadow: inset 0 0 0 1.5px var(--blue);
}

/* Krokování se schválně neukazuje pořád: tři dlaždice po dvou tlačítkách je
   šest terčů, které při prvním pohledu nic neříkají. Klávesnice je má vždy
   (↑↓ na dlaždici), myš až když nad ní je. */
.gs-cas-pm {
  position: absolute; top: 10px; bottom: 10px; right: 4px;
  display: flex; flex-direction: column; justify-content: space-between;
  opacity: 0; transition: opacity .15s;
}
.gs-cas-dl:hover .gs-cas-pm, .gs-cas-dl:focus-within .gs-cas-pm,
.gs-cas-delka:hover .gs-cas-pm, .gs-cas-delka:focus-within .gs-cas-pm { opacity: 1; }
.gs-cas-krok {
  width: 18px; height: 18px; padding: 0; border: none; border-radius: var(--r-ctrl);
  background: color-mix(in srgb, var(--ink) 4%, var(--bg)); color: var(--t1);
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: background .15s, color .15s;
}
.gs-cas-krok:hover { background: var(--blue-plocha); color: var(--white); }
/* Krok je +/− podle návrhu. Do 23. 9. 2026 tu stály šipky s odůvodněním, že
   appka nemá glyf `remove` — jenže sada ikon není daná, je to subset, který se
   staví z kódu (`scripts/ikony-subset.sh`). Chybějící glyf je důvod subset
   přegenerovat, ne měnit návrh. */
.gs-cas-krok .ms { font-size: var(--fs-sm); }

.gs-cas-sip { color: var(--t3); flex-shrink: 0; font-size: var(--fs-2xl); }

/* Délka je poslední a dotáhne řádek doprava — je to výsledek, ne vstup.
   Modrý rámeček pod myší (v návrhu byl) 23. 9. 2026 zrušen: dlaždice od–do
   pod myší jen ztmavnou a číslo délky vedle nich svítilo jako jediné pole. */
.gs-cas-delka {
  position: relative; flex: 1 1 auto; min-width: 114px; height: 72px;
  /* Vystředěná ve výšce dlaždic, ne na řádku s jejich čísly. Do 26. 9. 2026
     tu bylo spodní odsazení `calc(var(--fs-xs) + 6px)`, které délku zvedlo
     na účaří časů (Ondra 23. 9. 2026: „ani to celkové číslo ti tam nesedí na
     řádku s těmy časy."). Po prvním ostrém použití to rozhodnutí otočil:
     „výsledný čas dát na střed s boxy, ne zarovnaný s čísly" — vedle tří
     dlaždic je to samostatný údaj, ne čtvrtá hodnota v řádku. Tím zmizel
     i jeden výpočet vázaný na `--fs-xs` a mezeru v `.gs-cas-dl`. */
  padding: 0 26px 0 0; box-sizing: border-box;
  border-radius: var(--r-lg);
  color: var(--t1); display: flex; align-items: center; justify-content: flex-end;
  gap: 4px; line-height: 1; white-space: nowrap; outline: none;
}
.gs-cas-delka-v { font-size: 38.5px; font-weight: var(--fw-bold); letter-spacing: -.03em; font-variant-numeric: tabular-nums; display: inline-flex; align-items: baseline; gap: 4px; }
.gs-cas-jedn { font-size: 17.6px; font-weight: var(--fw-medium); color: var(--t3); }

/* Čipy jsou široké skoro poměrově k délce, kterou nabízejí — „2 h" je širší
   než „15 min" (Ondra 26. 9. 2026, návrh „Čas ve výkazu"). Doslova poměrově to
   být nemůže: 15 z 315 minut je 5 % řádku a popisek by se tam nevešel. Proto
   každý čip stojí na `flex-basis` 64 px a poměr rozděluje až to, co po nich
   zbude — `flex-grow` je počet minut a nese ho inline styl z times.js
   (`NM_DELKY`), aby délky zůstaly na jednom místě (§15.1). Odsazení 5 px +
   `gap` z `.fg` = 10 px k dlaždicím: čipy jsou jejich ovládání, patří k nim
   blíž než k pravítku pod sebou. */
.gs-cas-cipy { display: flex; gap: 8px; margin-top: 4px; }
.gs-cas-cip {
  flex: 0 1 64px; min-width: 0;
  height: 28px; border: none; border-radius: var(--r-ctrl); background: var(--bg);
  color: var(--t1); font-family: inherit; font-size: var(--fs-xs);
  font-weight: var(--fw-medium); cursor: pointer; opacity: .5; transition: opacity .15s;
}
.gs-cas-cip:hover, .gs-cas-cip.akt { opacity: 1; }
/* Mřížka čipů (`.gs-cas-cipy.mrizka`, 8. 10. 2026): rychlý výběr období vedle
   filtru `.gs-obd` v okně „Report hodin" — šest voleb 3 × 2, menší čip
   (Ondra na plátně: „budou menší ty labely", „dej 6 možností 3 a 3 pod sebe").
   Sloupce jsou stejně široké, delší popisek se zkrátí třemi tečkami. */
.gs-cas-cipy.mrizka { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; margin-top: 0; min-width: 0; }
.gs-cas-cipy.mrizka .gs-cas-cip { height: 24px; padding: 0 8px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ── Pravítko dne ─────────────────────────────────────────────────── */
.gs-osa-obal { --osa-akcent: var(--blue); position: relative; margin-top: 20px; }
.gs-osa-obal.kolize { --osa-akcent: var(--red); }
/* Vytrácení na krajích má pravítko i řádek hodin pod ním — jinak popisky končí
   ostrým řezem tam, kde rysky nad nimi už vybledly (23. 9. 2026). Jedno pravidlo
   pro obě vrstvy, ať se náběh nerozejde. */
.gs-osa, .gs-osa-popisky {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 14%, #000 86%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 14%, #000 86%, transparent 100%);
}
.gs-osa {
  position: relative; height: 36px; overflow: hidden;
  cursor: grab; touch-action: none; user-select: none;
  /* Pozadí pravítko nemá — splývá s tělem okna. Bílá plocha na šedém `--bg-2`
     z něj dělala pruh, který vypadal jako samostatné pole (Ondra 23. 9. 2026). */
  background: transparent;
}
.gs-osa:active { cursor: grabbing; }
/* Ryska po 15 min. `.cela` = celá hodina (vyšší a tmavší), `.akt` = leží uvnitř
   vybraného úseku. Inline styl nese jen polohu — barva ani výška do něj nepatří. */
.gs-osa-ryska { position: absolute; bottom: 0; width: .5px; height: 11px; margin-left: -.25px; border-radius: 1px; pointer-events: none; background: var(--border); }
.gs-osa-ryska.cela { height: 22px; background: var(--border-md); }
.gs-osa-ryska.akt { background: color-mix(in srgb, var(--osa-akcent) 45%, transparent); }
.gs-osa-ryska.cela.akt { background: var(--osa-akcent); }
.gs-osa-mimo { position: absolute; bottom: 0; height: 22px; border-radius: 2px; background: color-mix(in srgb, var(--border-md) 40%, transparent); }
.gs-osa-blok { position: absolute; top: 0; bottom: 0; display: flex; justify-content: space-between; cursor: grab; background: color-mix(in srgb, var(--osa-akcent) 10%, transparent); }
.gs-osa-uchyt { width: 12px; display: flex; align-items: center; cursor: ew-resize; }
.gs-osa-uchyt.do { justify-content: flex-end; }
.gs-osa-uchyt i { width: 2.5px; height: 100%; border-radius: 2px; background: var(--osa-akcent); transition: box-shadow .15s; }
.gs-osa-uchyt:hover i, .gs-osa-uchyt:active i {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--osa-akcent) 18%, transparent),
              0 0 12px 1px color-mix(in srgb, var(--osa-akcent) 60%, transparent);
}
/* Čára „teď" smí přečuhovat nad i pod pravítko — je to jiná vrstva než den.
   1px a rysky .5px (Ondra 26. 9. 2026 na plátně „Čas ve výkazu": „Tato linka
   bude jenom jeden px široká"; rysky zúžil sám). Linky v appce jsou 1px. */
.gs-osa-ted { position: absolute; top: -12px; bottom: -4px; width: 1px; margin-left: -.5px; border-radius: 1px; background: var(--blue); opacity: .55; pointer-events: none; }
/* `margin-bottom` je vzduch pod pravítkem, ne pod popiskami: řádek hodin
   dosedal rovnou na první pole formuláře (Ondra 26. 9. 2026 „Pod timeline více
   místa o 10 px"). */
.gs-osa-popisky { position: relative; height: 18px; margin-top: 8px; margin-bottom: 8px; }
.gs-osa-popisky span { position: absolute; font-size: var(--fs-xs); font-variant-numeric: tabular-nums; color: var(--t3); font-weight: var(--fw-medium); }
/* Hodina uvnitř výběru. Rozlišuje ji jen barva — tučná pod 18 px se nesmí
   (§13.2, Bold patří textu od --fs-xl výš) a obcházet to tím, že je to
   „číslo, ne text", by pravidlo zrušilo pro každé druhé místo v appce.
   Rysky pod popiskem zesílí zároveň (`.gs-osa-ryska.akt`), takže na sebe
   vybraný úsek upozorní i bez váhy. */
.gs-osa-popisky span.akt { color: var(--osa-akcent); }

@media (prefers-reduced-motion: reduce) {
  .gs-cas-dl, .gs-cas-seg, .gs-cas-krok, .gs-cas-delka, .gs-cas-cip, .gs-osa-uchyt i { transition: none; }
}


/* ═══════════════════════════════════════════════════════════
   SEKCE 63 — Domů: ukazatele z čárek (26. 9. 2026)

   Vzniklo na plátně „Airine — Domů, bold návrh". Zadání Ondry bylo
   dvojí: **nadpis boxu má být nadpis** (ne verzálková mikropopiska,
   jakou měla sekce 59 od Financí), a **graf se má skládat z čárek** —
   „čárky jsou pro nás docela jasné věci". Odtud tři vizualizace, které
   mluví stejným jazykem:

     `.gs-cifernik`  60 čárek po obvodu = procento (přišel z Financí)
     `.gs-cary`      jedna svislá čárka = jeden den
     `.gs-cary-radek` vodorovný pás čárek = částka po krocích
     (`.gs-spojnice`, měsíce jako lomená čára, do 12. 10. 2026 — dnes
     `.gs-krivka`, sekce 63 níž)

   Do DS to jde celé, ne jen na Domů: ciferník už chtěla druhá obrazovka
   (§13.2 — opsat rodinu tříd z jiné stránky se nesmí) a zbytek chtějí
   Finance a Projekty v dalším kole redesignu přehledů.

   Čte: public/domu.{js,css}, public/finance.js (ciferník).
   ============================================================ */

/* ── Nadpis bloku je nadpis ──────────────────────────────────
   Do 26. 9. 2026 byl `.gs-dash-hd-nazev` 10px verzálky s prostrkáním.
   Na Financích to fungovalo jako štítek nad číslem; jakmile má blok
   vlastní obsah (graf, seznam, řádky), chybí mu hlava. Velikost je
   `.gs-h6` (14px medium), u velkých bloků `.gs-h5` (16px) — proto
   modifikátor na bloku, ne druhá třída na nadpisu. Mění vzhled i
   Financím a Projektům; to je záměr, dashboardy mají jeden jazyk. */
.gs-dash-hd-nazev { margin: 0; font-size: var(--fs-base); font-weight: var(--fw-medium); text-transform: none; letter-spacing: normal; color: var(--t1); line-height: 1.4; }
.gs-dash-blok.velky .gs-dash-hd-nazev { font-size: var(--fs-lg); }

/* ── Plný blok ───────────────────────────────────────────────
   Modrá deska `.inverzni` (hero Domů, 26. 9. 2026) zmizela 28. 9. 2026:
   přehledy jsou všude na linkách (rozhodnutí 1b), hlavní číslo nese
   velikost, ne barevná plocha. */

/* ── Hlavní číslo stránky ────────────────────────────────────
   Větší sourozenec `.gs-dash-num`. 72px proto, že v bloku vysokém
   248 px musí zbýt na graf pod ním; `.gs-hero-num` (sekce 56) je něco
   jiného — to je formulářové pole. */
.gs-dash-hero { display: flex; align-items: flex-end; gap: 16px; margin-top: 8px; flex-wrap: wrap; }
.gs-dash-hero-num {
  font-size: var(--fs-hero); line-height: 1; font-weight: var(--fw-medium);
  letter-spacing: -.045em; font-variant-numeric: tabular-nums;
}
.gs-dash-hero-jed { font-size: var(--fs-2xl); font-weight: var(--fw-medium); padding-bottom: 8px; opacity: .62; }

/* Jednotka uvnitř velkého čísla („Kč", „h"). Je to popisek, ne hodnota,
   takže se tlumí a nesmí lézt do tabulkového účaří číslic — proto `em`
   a vlastní `letter-spacing` (velké číslo má záporné). Nejmenší písmo appky
   (`--fs-xs`, 11 px) je spodní mez: u malého čísla vycházelo `.44em` pod něj
   (rozhodnutí Ondry 9. 10. 2026). */
.gs-dash-num i {
  font-style: normal; font-size: max(.44em, var(--fs-xs)); font-weight: var(--fw-medium);
  color: var(--t3); letter-spacing: normal;
}

/* ── Přehled na linkách (rozhodnutí 1b, 27. 9. 2026) ──────────
   Ondra nad náhledem přehledu Financí (v15): místo šesti karet se stínem
   jeden panel, v něm hlavní číslo, pás metrik a graf, oddělené linkami,
   které na koncích mizí. Bloky s vlastním obsahem (seznam) mají panel samy.
   Skládá `gsDashVykresli({ linky: true })` → `gsDashLinky()` v shared.js;
   metriky kreslí `gsDashMetrika()`. Pravidla uvnitř platí jen pod `.linky`,
   takže karty Projektů se nemění, dokud se na linky nepřepnou.

   Co tu platí (Ondra, náhled v15):
   · metrika: verzálkový štítek bez podkladu, číslo, šedý popisek;
   · blok s obsahem: normální nadpis, období v kulatém štítku s šedým
     obrysem, součet bíle vpravo, řádky šedě a regular;
   · hlavní číslo Bold, jednotka šedá. */
/* Linky jsou od 28. 9. 2026 token celé appky, ne jen přehledu: KPI pás,
   řádky Kontaktů a Domů je berou taky. Na `:root`, protože `--t1` se
   mění s tématem právě tam (`data-tema` na <html>). */
:root {
  --linka: color-mix(in srgb, var(--t1) 9%, transparent);
  --linka-vodor: linear-gradient(90deg, transparent, var(--linka) 12%, var(--linka) 88%, transparent);
  --linka-svisla: linear-gradient(180deg, transparent, var(--linka) 15%, var(--linka) 85%, transparent);
}

/* ── KPI pás na linkách (28. 9. 2026, audit jazyk-10, vzory-12) ──
   Do té doby byl pás box v boxu: každá `.stat-card` s vlastní hranou na
   bílém pásu. Přehledy už jsou na linkách, takže pás nad výpisem (Projekty,
   Výkazy, Sales, Finance) mluví stejně: čísla vedle sebe, mezi nimi svislá
   linka s mizejícími konci. Klikací dlaždice (recept A) nemá desku, kterou
   by obtáhla — hover i aktivní stav nese popisek a číslo barvou textu. */
:is(.kpi-grid, .vd-kpi) { gap: 0; }
:is(.kpi-grid, .vd-kpi) > .stat-card {
  background: none; border: 0; border-radius: 0; box-shadow: none; padding: 4px 24px;
}
:is(.kpi-grid, .vd-kpi) > .stat-card:first-child { padding-left: 0; }
:is(.kpi-grid, .vd-kpi) > .stat-card:last-child { padding-right: 0; }
:is(.kpi-grid, .vd-kpi) > .stat-card + .stat-card { border-left: 1px solid; border-image: var(--linka-svisla) 1; }
:is(.kpi-grid, .vd-kpi) > .stat-card.kpi-clickable:hover { background: none; }
:is(.kpi-grid, .vd-kpi) > .stat-card.kpi-clickable:hover .stat-label,
:is(.kpi-grid, .vd-kpi) > .stat-card.active .stat-label,
:is(.kpi-grid, .vd-kpi) > .stat-card.active .stat-val { color: var(--blue-txt); }
.gs-dash-panel {
  grid-column: span var(--gs-dash-span, 12); min-width: 0;
  background: var(--surface); border-radius: var(--r); box-shadow: var(--sh-box);
  padding: 24px 24px;
}
.gs-dash-panel.samostatny { padding: 20px 24px; }
.gs-dash-rada { display: grid; grid-template-columns: repeat(12, 1fr); }
.gs-dash-rada + .gs-dash-rada {
  margin-top: 24px; padding-top: 24px;
  border-top: 1px solid; border-image: var(--linka-vodor) 1;
}
.linky .gs-dash-blok { padding: 0 24px; }
.linky .gs-dash-blok:first-child { padding-left: 0; }
.linky .gs-dash-blok:last-child { padding-right: 0; }
.linky .gs-dash-blok + .gs-dash-blok { border-left: 1px solid; border-image: var(--linka-svisla) 1; }
.linky .samostatny > .gs-dash-blok { padding: 0; }
/* Klikací buňka nemá desku, kterou by šlo obtáhnout (recept A) — hover
   proto nese nadpis: zmodrá, šipka u něj už je. */
.linky .gs-dash-blok.kpi-clickable { border-width: 0; cursor: pointer; }
.linky .gs-dash-blok + .gs-dash-blok.kpi-clickable { border-left-width: 1px; }
.linky .gs-dash-blok.kpi-clickable:hover { background: none; }
.linky .gs-dash-blok.kpi-clickable:hover .gs-dash-hd-nazev { color: var(--blue-txt); }
.linky .gs-dash-akce { top: -6px; right: 12px; }
.linky .gs-dash-blok:last-child > .gs-dash-akce { right: -8px; }

/* Štítek metriky: verzálky, šedě, bez podkladu. */
.linky .gs-dash-hd.lbl { align-items: center; gap: 8px; margin-bottom: 8px; }
.linky .gs-dash-hd.lbl .gs-dash-hd-nazev {
  font-size: var(--fs-xs); font-weight: var(--fw-medium); letter-spacing: .07em; text-transform: uppercase; color: var(--t3);
}
/* Kulatý štítek s šedým obrysem: růst u metriky, období u nadpisu bloku. */
.gs-dash-stitek,
.linky .gs-dash-hd-rezim {
  display: inline-flex; align-items: center; padding: 3px 8px; border-radius: var(--r-ctrl);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--t1) 16%, transparent);
  font-size: var(--fs-xs); color: var(--t3); line-height: 1.2; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.gs-dash-stitek.pos { color: var(--green-txt); font-weight: var(--fw-medium); }
.gs-dash-stitek.neg { color: var(--red-txt); font-weight: var(--fw-medium); }
.linky .gs-dash-hd-rezim:empty { display: none; }
.linky .gs-dash-hd { align-items: center; gap: 8px; }
.linky .gs-dash-hd-nazev { font-size: var(--fs-lg); }
.linky .gs-dash-hd-doprava { font-size: var(--fs-base); color: var(--t1); }

/* Čísla. Hlavní je Bold (≥ 18 px, §13.2), jednotka šedá a menší. */
.linky .gs-dash-hero { margin-top: 0; gap: 8px; align-items: baseline; }
.linky .gs-dash-hero-num { font-size: var(--fs-hero); font-weight: var(--fw-bold); }
.linky .gs-dash-hero-jed { padding-bottom: 0; opacity: 1; color: var(--t3); }
.linky .gs-dash-sub.hero { font-size: var(--fs-md); color: var(--t2); margin-top: 12px; }
/* Číslo uvnitř věty podtitulku (výsledek v hero): o stupeň výš, barva jen
   znaménkem — zelená a červená jsou stav, ne ozdoba. */
.linky .gs-dash-sub b { font-weight: var(--fw-medium); color: var(--t1); }
.linky .gs-dash-sub b.pos { color: var(--green-txt); }
.linky .gs-dash-sub b.neg { color: var(--red-txt); }
.linky .gs-dash-val { letter-spacing: -.03em; line-height: 1.1; }
.gs-dash-val i {
  font-style: normal; font-size: var(--fs-base); font-weight: var(--fw-medium);
  color: var(--t3); letter-spacing: normal; margin-left: 4px;
}

/* Dva stavy pod sebou v jedné buňce (čeká na zaplacení / po splatnosti). */
.gs-dash-dvojice { display: grid; grid-template-rows: 1fr 1fr; height: 100%; }
.gs-dash-dvojice > div { display: flex; flex-direction: column; justify-content: center; padding: 16px 0; }
.gs-dash-dvojice > div:first-child { padding-top: 0; }
.gs-dash-dvojice > div:last-child { padding-bottom: 0; }
.linky .gs-dash-dvojice > div + div { border-top: 1px solid; border-image: var(--linka-vodor) 1; }

/* Řádky seznamu: šedě a regular, mezi nimi linka s mizejícími konci. */
.linky .gs-dash-radek { border-bottom: 0; color: var(--t2); }
.linky .gs-dash-radek + .gs-dash-radek { border-top: 1px solid; border-image: var(--linka-vodor) 1; }
.linky .gs-dash-radek-am { color: var(--t2); font-weight: var(--fw-regular); }
.linky .gs-dash-radek-am.neg { color: var(--red-txt); }
.linky .gs-dash-radek-am.muted { color: var(--t3); }

/* ── Křivka dvou řad ─────────────────────────────────────────
   Graf „Přijato a vydáno" přehledu na linkách (rozhodnutí 1b, náhled v15).
   Bez plochy pod čarou, mřížka plnou linkou, čára 1,5 px. Hlavní řada svítí
   pod kurzorem jako tlačítko: gradient z `--krivka-od` přes `--blue` zpět,
   ve dne z bledší modré (bílá by na bílém boxu zmizela), v noci téměř bílé.
   Kreslí `gsKrivka()` v shared.js. */
.gs-krivka { --krivka-od: color-mix(in srgb, var(--blue) 45%, var(--white)); }
:root[data-tema="night"] .gs-krivka { --krivka-od: color-mix(in srgb, var(--blue) 20%, var(--white)); }
.gs-krivka-plocha { position: relative; height: 260px; outline: none; }
.gs-krivka-plocha:focus-visible { box-shadow: 0 0 0 2px var(--blue); border-radius: var(--r-sm); }
.gs-krivka-plocha svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.gs-krivka .mrizka { stroke: color-mix(in srgb, var(--t1) 9%, transparent); stroke-width: 1; }
.gs-krivka .mrizka-txt,
.gs-krivka .osa-txt { fill: var(--t3); font-size: var(--fs-xs); font-family: var(--ff); font-variant-numeric: tabular-nums; }
.gs-krivka .osa-txt.rok { opacity: .7; }
.gs-krivka .osa-txt.akt { fill: var(--t1); font-weight: var(--fw-medium); }
.gs-krivka .cara-a,
.gs-krivka .cara-b { fill: none; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.gs-krivka .cara-b { stroke: color-mix(in srgb, var(--t1) 28%, transparent); }
.gs-krivka .vodit { stroke-width: 1.5; }
.gs-krivka .bod-a { fill: var(--surface); stroke: var(--blue); stroke-width: 2.25; }
.gs-krivka .bod-b { fill: var(--surface); stroke: color-mix(in srgb, var(--t1) 35%, transparent); stroke-width: 1.5; }
.gs-krivka .puls {
  fill: var(--blue); transform-box: fill-box; transform-origin: center;
  animation: gs-krivka-puls 2.4s ease-out infinite;
}
@keyframes gs-krivka-puls { 0% { transform: scale(1); opacity: .35; } 100% { transform: scale(3.4); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .gs-krivka .puls { animation: none; opacity: 0; } }
/* Bublina nad bodem: měsíc, +přijato bíle, −vydáno šedě. */
.gs-krivka-bublina {
  position: absolute; transform: translate(-50%, calc(-100% - 12px)); pointer-events: none;
  padding: 8px 12px; border-radius: var(--r-sm); background: var(--surface);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--t1) 12%, transparent), var(--sh-md);
  font-variant-numeric: tabular-nums; white-space: nowrap; line-height: 1.35;
}
:root[data-tema="night"] .gs-krivka-bublina { background: var(--bg-2); }
.gs-krivka-bublina span { display: block; }
.gs-krivka-bublina .m { font-size: var(--fs-xs); color: var(--t3); margin-bottom: 2px; }
.gs-krivka-bublina .a { font-size: var(--fs-md); font-weight: var(--fw-medium); color: var(--t1); }
.gs-krivka-bublina .b { font-size: var(--fs-sm); color: var(--t3); }
.gs-krivka-leg { display: flex; gap: 16px; font-size: var(--fs-sm); color: var(--t3); margin-top: 12px; }
.gs-krivka-leg i {
  display: inline-block; width: 14px; height: 2px; border-radius: 1px;
  background: var(--blue); vertical-align: 3px; margin-right: 8px;
}
.gs-krivka-leg i.b { background: color-mix(in srgb, var(--t1) 28%, transparent); }

/* ── Ciferník procenta ───────────────────────────────────────
   Šedesát čárek 2×6 px po obvodu; „rozsvícené" jsou splněná část.
   Vznikl 19. 9. 2026 na Financích jako `.fd-cifernik` (zadání Ondry
   přes Vercel), 26. 9. 2026 ho chtělo i Domů na fakturovatelnost —
   tím přestal být vizualizací jednoho modulu a přestěhoval se sem.
   Šedesát dílků je dělitelné dvanácti i deseti, takže se dá počítat
   očima; kruh z bodů (dřívější návrh Domů) se počítat nedá.
   Kreslí `gsCifernik()` v shared.js. */
.gs-cil { display: flex; align-items: center; gap: 16px; margin-top: 8px; }
.gs-cil-text { min-width: 0; flex: 1; }
.gs-cil .gs-dash-num { margin-top: 0; }
/* Popisek vedle ciferníku. Vlastní třída, protože `.gs-dash-radek-nm` (řádek
   žebříčku) ořezává třemi tečkami — v úzkém sloupci z „Fakturovatelnost"
   zbylo „Fakturovat…" (26. 9. 2026, Domů). Tady je to nadpis ukazatele, ne
   buňka výpisu: smí se zalomit, ořezat ne. */
.gs-cil-nm { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--t1); line-height: 1.3; }
.gs-cifernik { position: relative; width: 96px; height: 96px; flex-shrink: 0; }
.gs-cifernik svg { width: 100%; height: 100%; display: block; }
.gs-cifernik line { stroke-width: 2; stroke-linecap: round; }
/* Zhasnutá čárka je hrana karty, ne silná šedá (Figma 5154:6926/6567). */
.gs-cifernik line.off { stroke: var(--border); }
.gs-cifernik line.on {
  stroke: var(--blue);
  /* „Bude se načítat" — čárky naskakují po směru hodin, každá o 12 ms
     později. Jednorázové naplnění při vykreslení, ne smyčka: ukazatel má
     říct stav, ne poutat pozornost napořád. */
  animation: gs-cifernik-in .28s ease-out both;
}
@keyframes gs-cifernik-in { from { stroke: var(--border); opacity: 0; } to { opacity: 1; } }
.gs-cifernik-pct {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-xl); font-weight: var(--fw-bold); color: var(--t1);
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
.gs-cifernik-pct i { font-style: normal; font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--t3); margin-left: 1px; }
/* Kdo si vypnul animace, dostane hotový ciferník — ne prázdný. */
@media (prefers-reduced-motion: reduce) { .gs-cifernik line.on { animation: none; } }

/* ── Pás čárek ───────────────────────────────────────────────
   Svisle: jedna čárka = jeden den, výška = odpracované hodiny. Den bez
   výkazu je `.prazdna` — pahýl v barvě hrany, ne mezera: prázdno je taky
   údaj a mezera by ho schovala. Výšku počítá stránka a dává ji inline,
   protože je to hodnota dat, ne vzhled. */
.gs-cary { display: flex; align-items: flex-end; gap: 2px; width: 100%; }
/* Slot dne na plnou výšku pásu (12. 10. 2026): hover chytí i den s pahýlem
   a štítek `.gs-tip` stojí nad pásem vždy ve stejné výšce. V pravé půlce
   (`.vpravo`) se štítek kotví k pravé hraně slotu. Velikost štítku jako
   `.gs-tip-dole` — systémová, popisuje jen jeden den. */
.gs-cary-den { flex: 1; min-width: 1px; height: 100%; display: flex; align-items: flex-end; }
.gs-cary-den > .gs-tip {
  bottom: calc(100% + 6px); padding: 0 var(--sp-2); border-radius: var(--r-cb);
  font-size: var(--fs-xs); line-height: 19px; transition: opacity .1s;
}
.gs-cary-den.vpravo > .gs-tip { left: auto; right: 0; }
.gs-cary i { display: block; flex: 1; min-width: 1px; border-radius: 2px; background: var(--blue); }
.gs-cary-den:hover > i { filter: brightness(1.15); }
.gs-cary i.prazdna { background: var(--border); }
.gs-cary i.vikend { background: color-mix(in srgb, var(--blue) 45%, var(--mix-bg)); }
.gs-cary-osa { display: flex; align-items: baseline; font-size: var(--fs-xs); color: var(--t3); margin-top: 8px; }
.gs-cary-osa span:last-child { margin-left: auto; }

/* Vodorovně: jedna čárka = pevný krok částky (u pipeline 50 000 Kč).
   Řádek je čitelný bez os a bez legendy — čárky se dají spočítat. */
.gs-cary-radek { display: flex; align-items: center; gap: 16px; padding: 8px 0; }
.gs-cary-radek + .gs-cary-radek { border-top: 1px solid var(--bg); }
.gs-cary-radek-nm { width: 150px; flex-shrink: 0; font-size: var(--fs-md); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gs-cary-radek-nm span { color: var(--t3); }
.gs-cary-pas { flex: 1; display: flex; align-items: center; gap: 4px; min-width: 0; overflow: hidden; }
.gs-cary-pas i { display: block; width: 2px; height: 26px; flex-shrink: 0; border-radius: 1px; background: var(--blue); }
.gs-cary-radek-am { width: 110px; text-align: right; font-size: var(--fs-md); font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; }

/* Varianta `.gs-cary-pas.dily` — pás rozdělený na díly (8. 10. 2026, Ondra:
   „bude součástí design systému"; vznikl 7. 10. v Tiketech jako vyřízeno /
   nevyřízeno). Jedna čárka = jedna položka, díl = úsek pásu ve vlastní
   barvě (`--c`, výchozí modrá; `.sede` je zbytek). Sloupce mřížky skládá
   `gsCaryDily()` v poměru počtu čárek, takže je rozestup stejný v celém
   pásu i přes hranici dílů; první čárka začíná na levém okraji, poslední
   končí na pravém. Pod pásem čísla dílů v jednom řádku přes celou šířku —
   pod úsekem by se u dílu bez čárek (šířka 0) překryla.
   Úsek i popisek jsou tlačítka (klik = filtr stránky). `.ztlumit` na pásu
   + `.zvyr` na dílu = najetí myší. Čte: public/shared.js (gsCaryDily),
   public/tickety.js (tkRenderPruh, tkPruhNajet). */
.gs-cary-pas.dily { flex: none; display: grid; gap: 8px 0; align-items: stretch; overflow: visible; }
.gs-cary-usek {
  --c: var(--blue);
  display: flex; align-items: stretch;
  height: 12px; padding: 0; border: none;
  background: color-mix(in srgb, var(--c) 16%, transparent);
  cursor: pointer; transition: opacity .15s;
}
.gs-cary-usek.sede { --c: var(--border-md); }
.gs-cary-pas.dily .gs-cary-usek i { width: auto; height: auto; flex: 1 1 0; min-width: 3px; border-radius: 0; background: linear-gradient(var(--c), var(--c)) center / 2px 100% no-repeat; }
.gs-cary-pas.dily .gs-cary-usek i.kraj-l { flex-grow: .5; min-width: 1.5px; background-position: left; }
.gs-cary-pas.dily .gs-cary-usek i.kraj-p { flex-grow: .5; min-width: 1.5px; background-position: right; }
.gs-cary-pas.dily .gs-cary-usek i.kraj-l.kraj-p { flex-grow: 1; background-position: left; }
.gs-cary-popisky { grid-column: 1 / -1; display: flex; justify-content: space-between; gap: 16px; min-width: 0; }
.gs-cary-popisek {
  min-width: 0; padding: 0; border: none; background: transparent;
  font-family: inherit; text-align: left; cursor: pointer; transition: opacity .15s;
}
.gs-cary-popisek:last-child:not(:first-child) { text-align: right; }
.gs-cary-popisek-cislo {
  font-size: var(--fs-2xl); font-weight: var(--fw-bold); line-height: 1; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--t1);
}
.gs-cary-popisek-cislo small { margin-left: 8px; font-size: var(--fs-sm); font-weight: var(--fw-regular); letter-spacing: 0; color: var(--t3); }
.gs-cary-popisek[aria-pressed="true"] .gs-cary-popisek-cislo small { color: var(--t1); }
.gs-cary-pas.dily.ztlumit .gs-cary-usek:not(.zvyr) { opacity: .28; }
.gs-cary-pas.dily.ztlumit .gs-cary-popisek:not(.zvyr) { opacity: .45; }
@media (prefers-reduced-motion: reduce) { .gs-cary-usek, .gs-cary-popisek { transition: none; } }

/* `.gs-spojnice` (lomená čára měsíců na Domů) zrušena 12. 10. 2026: Domů
   kreslí měsíce `.gs-krivka` jako Projekty a Finance (Ondra přes Vercel). */

/* ── Řádek události ──────────────────────────────────────────
   Co se v appce stalo: kdo, co, kdy. Používá ho deník práce agenta a
   ochutnávka na Přehledu; je to jiný tvar než `.gs-dash-radek` (ten je
   „název — doplněk — číslo", tohle je „ikona — věta — čas — akce"). */
.gs-udalost { display: flex; align-items: flex-start; gap: 8px; padding: 8px 0; }
.gs-udalost + .gs-udalost, .gs-udalost:first-child { border-top: 1px solid var(--bg); }
.gs-udalost-ikona {
  width: 26px; height: 26px; border-radius: var(--r-pill); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--blue-lt); color: var(--blue-txt);
}
.gs-udalost-telo { flex: 1; min-width: 0; }
.gs-udalost-nm { font-size: var(--fs-md); }
.gs-udalost-nm strong { font-weight: var(--fw-medium); }
.gs-udalost-sb { font-size: var(--fs-xs); color: var(--t3); margin-top: 2px; }
.gs-udalost.ceka .gs-udalost-ikona { background: var(--amber-lt); color: var(--amber-txt); }
.gs-udalost.ceka .gs-udalost-sb { color: var(--amber-txt); }
.gs-udalost-akce { align-self: center; flex-shrink: 0; }

/* ══════════════════════════════════════════════════════════════════
   SEKCE 64 — lišta hromadného výběru a stav bloku (vlna 3, 27. 9. 2026)
   ──────────────────────────────────────────────────────────────────
   Stavový štítek .gs-chip je v sekci 52. Tady jsou dvě komponenty, které
   do vlny 3 měl každý modul po svém (vzory-08, vzory-09, rozhodnutí 3a a 4a).
   Reference: docs/design-system.md → „Stav, výběr a štítky (vlna 3)".
   ══════════════════════════════════════════════════════════════════ */

/* ── Lišta hromadných akcí (.gs-vyber-lista, rozhodnutí 3a) ───────────────
   Plovoucí pilulka dole uprostřed podle Transakcí (.tx-sel-bar): nepřeskládá
   layout, takže tabulka pod ní po zaškrtnutí neposkočí. Nahrazuje .te-bulk-bar
   (Výkazy), .inv-bulk-bar (Faktury, 1:1 kopie) a .tx-sel-bar (Transakce).

   <div class="gs-vyber-lista" id="…" role="toolbar" aria-label="…" hidden>
     <span class="gs-vyber-pocet" aria-live="polite"></span>
     <div class="gs-vyber-akce">
       <button class="gs-vyber-btn" data-gs-vyber-akce data-on-click="…()">…</button>
       <button class="gs-vyber-btn druha" data-gs-vyber-akce data-gs-vyber-min="2">…</button>
     </div>
     <button class="gs-vyber-zavri" data-on-click="…()" aria-label="Zrušit výběr"><span class="ms ms-sm">close</span></button>
   </div>

   Ukazuje, schovává a zamyká ji `gsVyberLista(lista, pocet, volby)` v shared.js:
   bez výběru jsou tlačítka `disabled` (a lišta schovaná, pokud ji stránka
   nedrží), `data-gs-vyber-min` odemkne akci až od N vybraných. Plocha je
   aplikace (varianta B, Ondra 8. 10. 2026 na plátně „Report hodin a lišta
   výběru"): ve dne bílá jako okno, v Night `--bg`, aby se od černé plochy
   stránky odlepila. Tlačítka jsou DS tlačítka se září (sekce 14): první akce
   primární, `.druha` sekundární, křížek ghost s linkou. Třídy `.gs-vyber-*`
   zůstaly, aby se markup tří stránek nemusel přepisovat — záři jim dává
   výčet `:is(…)` v sekci 14 a `ZARE_SEL` v akce.js. */
.gs-vyber-lista {
  position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
  z-index: var(--z-lista); display: flex; align-items: center; gap: 12px;
  max-width: calc(100vw - 48px);
  /* Plný pill (6. 10. 2026, Ondra přes Vercel: „zcela kulaté rohy") — lišta je
     ovladač jako tlačítka v ní, a ty mají `--r-ctrl` (CLAUDE.md §13.2). */
  padding: 8px 8px 8px 16px; border-radius: var(--r-ctrl);
  background: var(--surface); color: var(--t1);
  box-shadow: inset 0 0 0 1px var(--border), var(--sh-lg);
  font-size: var(--fs-sm); white-space: nowrap;
}
:root[data-tema="night"] .gs-vyber-lista { background: var(--bg); }
.gs-vyber-pocet { font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; }
.gs-vyber-akce { display: flex; align-items: center; gap: 8px; }
/* Plochu, okraj i záři kreslí sekce 14; tady jen rozměr a proměnné varianty. */
.gs-vyber-btn {
  display: inline-flex; align-items: center; gap: 8px;
  height: 30px; padding: 0 16px; border-radius: var(--r-ctrl);
  font: inherit; font-weight: var(--fw-medium); cursor: pointer; transition: opacity .15s;
  --gb-plocha: var(--btn-gradient);
  --gb-okraj: linear-gradient(color-mix(in srgb, var(--blue-brand) 70%, var(--white)), var(--blue-dk));
  --gb-linka: var(--white);
  --gb-zare: color-mix(in srgb, var(--blue) 70%, var(--white));
  color: var(--white);
}
/* Druhá akce: sekundární tlačítko, aby hlavní akce zůstala jedna. */
.gs-vyber-btn.druha {
  --gb-plocha: linear-gradient(var(--surface), var(--surface));
  --gb-okraj: linear-gradient(var(--border-md), var(--border-md));
  --gb-linka: var(--blue);
  --gb-zare: color-mix(in srgb, var(--blue) 55%, transparent);
  color: var(--t1);
}
.gs-vyber-btn:disabled, .gs-vyber-btn:disabled:hover { opacity: .45; cursor: default; }
.gs-vyber-btn:disabled::after { display: none; }
/* Křížek: ghost s linkou (Ondra 8. 10. 2026: „by měl mít border"). */
.gs-vyber-zavri {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: var(--r-pill); cursor: pointer;
  --gb-okraj: linear-gradient(var(--border), var(--border));
  --gb-linka: var(--blue);
  --gb-zare: color-mix(in srgb, var(--blue) 55%, transparent);
  color: var(--t2);
}
.gs-vyber-zavri:hover { color: var(--t1); }
.gs-vyber-btn:focus-visible, .gs-vyber-zavri:focus-visible { outline: 2px solid var(--focus, var(--blue)); outline-offset: 2px; }
/* Toast vpravo dole nesmí na lištu najet — zvedne se nad ni. */
body:has(.gs-vyber-lista:not([hidden])) .toast { bottom: 76px; }

/* ── Pole se štítky (.gs-pole-stitky, 8. 10. 2026) ─────────────────────────
   Pole formuláře, ve kterém stojí vybrané položky jako štítky s křížkem
   (projekty v okně „Report hodin", plátno schválené Ondrou 8. 10. 2026).
   Vypadá jako pole v okně (sekce 9: `--pole-bg`, linka, `--r-field`, výška
   selectu), klik na prázdné místo otevře nabídku (`gsFiltrDd`).

   <div class="gs-pole-stitky" role="group">
     <span class="gs-pole-stitek"><span class="gs-chip-text">Název</span>
       <button type="button" class="gs-pole-stitek-x" aria-label="…"><span class="ms">close</span></button></span>
     <button type="button" class="gs-pole-stitky-pridat" aria-label="…"><span class="ms">expand_more</span></button>
   </div>
   Čte: projects.html (#pv-rep-projekty), projects.js (pvRepKresliProjekty). */
.gs-pole-stitky {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-width: 0;
  position: relative; min-height: 48px; box-sizing: border-box; padding: 6px 36px 6px 8px;
  background: var(--pole-bg); border: 1px solid var(--border); border-radius: var(--r-field);
  cursor: pointer;
}
.gs-pole-stitky:hover { border-color: var(--border-pole); }
.gs-pole-stitky-prazdne { padding-left: 4px; font-size: var(--fs-base); color: var(--t3); }
.gs-pole-stitek {
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%; min-width: 0;
  height: 26px; padding: 0 4px 0 8px; border-radius: var(--r-ctrl);
  background: var(--bg); color: var(--t1); font-size: var(--fs-md); cursor: default;
}
/* V Night je pole `--bg` samo, štítek jde o stupeň výš (plátno: „projekty
   nemají žádné pozadí v night režimu"). */
:root[data-tema="night"] .gs-pole-stitek { background: var(--bg-3); }
.gs-pole-stitek-x, .gs-pole-stitky-pridat {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  padding: 0; border: none; border-radius: var(--r-pill); background: none; cursor: pointer;
}
.gs-pole-stitek-x { width: 18px; height: 18px; color: var(--t1); opacity: .55; transition: opacity .15s; }
.gs-pole-stitek-x:hover { opacity: 1; }
.gs-pole-stitek-x .ms { font-size: var(--fs-base); }
.gs-pole-stitky-pridat {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 28px; height: 28px; color: var(--t3);
}
.gs-pole-stitky-pridat:hover { color: var(--t1); }

/* ── Stav bloku a výpisu (.gs-stav, rozhodnutí 4a) ────────────────────────
   Jedna komponenta pro pět stavů, které do vlny 3 kreslilo asi dvacet
   stránkových tříd (.tbl-empty, .pros-empty, .cv-empty, .te-tl-empty …):

     nacitani  točící se ikona + „Načítám…"          (role=status, aria-busy)
     prazdno   ikona, titulek, věta a hlavní akce     (bez filtru: založit;
                                                        s filtrem: zrušit filtr)
     dobre     dobrá zpráva — „nic nečeká", zelená ikona
     malo      málo dat na graf nebo přehled
     chyba     červená ikona, věta a „Zkusit znovu"   (role=alert)

   Kreslí ho `gsStav(el, druh, {titulek, text, akce, ikona, maly})` v shared.js
   do bloku i do výpisu (.tbl-body-wrap) — v tabulce <tbody> dá řádek
   s colspan. Ručně psaný prázdný stav je od vlny 3 chyba. */
.gs-stav {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 32px 24px 32px; text-align: center;
  font-size: var(--fs-base); line-height: 1.5; color: var(--t2);
}
/* Verze 3 náhledu: ikona v barevném kolečku, titulek o stupeň větší. */
.gs-stav-ikona {
  --ms: 26px; width: 52px; height: 52px; border-radius: 50%;
  display: grid; place-items: center; margin-bottom: 8px;
  background: var(--bg); color: var(--t2);
}
.gs-stav-titulek { font-size: var(--fs-lg); font-weight: var(--fw-medium); color: var(--t1); }
.gs-stav-text { max-width: 40ch; color: var(--t2); }
.gs-stav-akce { margin-top: 16px; display: flex; gap: 8px; justify-content: center; align-items: center; }
.gs-stav.dobre .gs-stav-ikona { background: var(--green-lt); color: var(--green-txt); }
.gs-stav.chyba .gs-stav-ikona { background: var(--red-lt); color: var(--red-txt); }
.gs-stav.nacitani .gs-stav-ikona { background: none; }
/* Malý: dlaždice přehledu, popover, sekce v detailu — řádek místo sloupce. */
.gs-stav.maly { flex-direction: row; justify-content: flex-start; gap: 12px; padding: 12px 0; text-align: left; font-size: var(--fs-sm); }
.gs-stav.maly .gs-stav-ikona { --ms: 18px; width: 32px; height: 32px; margin: 0; flex: none; }
.gs-stav.maly .gs-stav-titulek { font-size: var(--fs-base); }
.gs-stav.maly .gs-stav-akce { margin: 0 0 0 auto; }
/* Ve výpisu je stav místo řádků — hranu ani mřížku řádku nemá. */
.tbl-body-wrap > .gs-stav, td.gs-stav-bunka { padding: 48px 24px; }

/* ═══════════════════════════════════════════════════════════════
   SEKCE 65 — přístupnost: fokus, skrytý text, pohyb, nízké okno
   (vlna 4, 27. 9. 2026; pristupnost-16, vzory-22, pristupnost-21,
   klavesnice-02, nastaveni-11)
   ═══════════════════════════════════════════════════════════════ */
/* Jeden recept fokusu z klávesnice: prstenec --focus 2 px vně prvku.
   `:where()` má nulovou specificitu, takže komponenta, která fokus kreslí
   jinak (vnitřní stín položky popoveru, řádek), ho přebije bez !important.
   Role a tabindex doplňuje klikacím prvkům akce.js (sekce „Přístupnost"),
   takže recept platí i pro řádky a karty psané jako div. */
:where(button, a[href], summary, [role="button"], [role="tab"], [tabindex]:not([tabindex="-1"])):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
/* Řádek výpisu a karta sahají k hraně rodiče, který je ořezává —
   prstenec jde dovnitř. */
:where(.tbl-row, .gs-radek-zare, .tk-card)[tabindex]:focus-visible { outline-offset: -2px; }
/* Pole: k přebarvené hraně prstenec, jinak je fokus jen změna 1 px linky. */
:where(input, select, textarea):focus-visible {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--focus) 22%, transparent);
}

/* Text jen pro čtečku: skrytý h1 modulu (akce.js), počet výsledků hledání,
   ohlášení přesunu karty. Standardní „visually hidden". */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Skrytý nativní <input type=file>, který zůstane fokusovatelný (nastaveni-11).
   `display:none` ho vyřadí z pořadí Tabu, takže fotka a import nešly
   z klávesnice. Fokus pak kreslí label, ve kterém pole je. */
.gs-skryte-pole {
  position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%);
}
label:has(> .gs-skryte-pole:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Nízké okno (klavesnice-02). Appka neroluje stránkou: hlavička, podnavigace,
   KPI a filtry stojí a roluje jen tělo výpisu. Při výšce 1280 × 720 v prohlížeči
   (≈ 610 px) výpisu zbude ~300 px, to stačí. Pod 560 px (zvětšení 200 %,
   menší okno, škálování 125 %) by ale na řádky nezbylo nic a zbytek by nešel
   doscrollovat (WCAG 1.4.10). Tam se roluje celou stránkou jako
   v Projektech (projects.css, #pv-section-projekty) a hlavička výpisu lepí
   k hornímu okraji. */
@media (max-height: 560px) {
  /* html bez `visible`, jinak by se overflow těla přenesl na okno a obloha
     (pozadí těla, výška 100 %) by pod prvním oknem skončila. */
  html { overflow: hidden; }
  body { overflow-y: auto; }
  .gs-view, .fin-wrap, .fin-subview, .tbl-wrap { flex: none; overflow: visible; min-height: auto; }
  .tbl-body-wrap { flex: none; overflow: visible; min-height: 0; }
  .tbl-header { position: sticky; top: 0; z-index: 1; background: var(--surface); }
  .tbl-wrap:has(> .tbl-body-wrap) > .tbl-header { overflow-y: visible; scrollbar-gutter: auto; }
}

/* Vypnutý pohyb: tečka běžící časomíry a vlna načítání se zastaví. Pojistka
   pro každou další nekonečnou animaci je poslední pravidlo bloku. */
@media (prefers-reduced-motion: reduce) {
  .rec-dot, .gs-skeleton { animation: none; }
  *, *::before, *::after { animation-iteration-count: 1 !important; scroll-behavior: auto !important; }
}

/* ── Tisk (night-09, rozhodnutí 13a) ─────────────────────────────
   Night blok v sekci 1 platí jen pro obrazovku, takže tokeny jsou tu
   denní samy a podklad stránky je papír. Obal appky (lišta, podnavigace,
   roviny oblohy, toast) se netiskne; noční varianta obrázku taky ne, jinak
   by na bílém papíře vyšel bílý logotyp. Blok je na konci souboru, aby
   přebil display pruhů bez !important. */
@media print {
  body { background: var(--papir); }
  .hd, .sub-nav, .pl-1, .pl-2, .pl-3, .toast, .gs-vyber-lista, .jen-night { display: none; }
  /* List A4 = stránka tisku: bez zmenšení, mezer a stínu, každý na nové stránce. */
  .gs-a4-stoh { display: block; zoom: 1 !important; }
  .gs-a4 { box-shadow: none; break-after: page; }
  .gs-a4:last-child { break-after: auto; }
}
