Binding rules of the canon, rendered from RULES.md (authored in Czech).
Pravidla projektu — Datamart & CRM
0. Jednoduchost především — „containment budget" (META-PRAVIDLO)
Tohle pravidlo je nad všemi ostatními. Cílem není mít hodně prvků — cílem je mít právě jeden, a ten perfektně vyladěný (Apple/Attio). Méně rámečků = víc přehlednosti a prostoru.
Containment budget — maximálně 1 úroveň rámování. Rám (okraj / pozadí / dlaždice) si MUSÍ zasloužit místo jako skutečná hranice: krok onboardingu, input, pravý preview panel, opravdový overlay. Jinak ne.
- Nikdy rámeček kvůli „uspořádání" seznamu. Položky seskupuj prostorem + hierarchií (váha / barva / velikost), ne krabičkami. Seznam = ikona + text oddělený mezerou — žádný okraj kolem každého řádku.
- Ikona je ikona, ne dlaždice. Žádné pozadí/okraj kolem ikony jen aby „seděla". Barevná ikona, hotovo.
- Zákaz „rámeček v rámečku v rámečku". Když je obsah už uvnitř karty/zóny, jeho položky jsou ploché.
Proč to píšu (a proč se to opakovalo): instinkt „seskup → zabal do boxu; ikona → na dlaždici" se vrací u každé nové obrazovky. DS dosud popisoval jen slovník (tokeny + jak nakreslit okraj), ne gramatiku zdrženlivosti (kdy okraj NEpřidat). Bez viditelného anti-patternu a bez kontroly před publikací ten habit vždycky vyhrál. Tahle sekce + DO/DON'T karta + checklist to mění z prózy na vynutitelnou bránu.
Povinná self-review PŘED publikací KAŽDÉ obrazovky:
- Spočítej úrovně zanoření (karta → zóna → položka → …). >1 dekorativní rám = STOP a zploštit.
- U každého okraje/pozadí/dlaždice řekni jednou větou „jakou skutečnou hranici tvoří". Když to nejde → pryč.
- „Šlo by to jen prostorem a hierarchií?" Pokud ano → udělej to tak.
Referenční anti-pattern: karta Layout · Containment (DO / DON'T). Referenční flat implementace: Registrace · Propojení Google + _ds/auth.css.
0.1 Portuj z reálné appky — NEimprovizuj (META-PRAVIDLO)
Zdroj pravdy je reálná appka apps/web/src/, ne obrázek před tebou. Než postavíš nebo přestyluješ JAKÝKOLIV prvek (dialog, picker, ovládací prvek, karta, seznam, tabulka), nejdřív prohledej appku:
apps/web/src/components/*.tsx+ balíček@acrm/ui(komponenty),apps/web/src/ds.css(sdílené.acrm-*třídy) aapps/web/src/ds/*.css(screen vrstvy), tokeny vpackages/ui/src/tokens/tokens.css. Grepuj podle názvu funkce (SaveSegment,IconPicker,seg-ic,dlg-,segpick…).
Když kanonická implementace existuje → portuj ji 1:1 do bundle: stejné názvy tříd, stejné velikosti, stejná paleta (tokeny / tone-třídy, NIKDY natvrdo hex), stejná struktura i chování. CSS zkopíruj doslova ze zdrojové vrstvy (ds.css / ds/*.css).
Zakázáno: paralelní třídní systém (.ssg-*, ad-hoc hex, vlastní velikosti) pro něco, co appka už řeší; natvrdo barvy tam, kde jsou --ic-* / pill tóny / tone-třídy; velikost dlaždice „od oka" (segment tile = 20 px v navigaci/Home, 40 px editovatelný picker trigger v save dialogu).
Teprve když v appce NIC není, navrhuj nově — i tak s DS tokeny a nejbližším existujícím vzorem. Krok „prohledej appku jako první" je povinný a jde PŘED prvním řádkem kódu. (Doloženo: Save dialog jsem improvizoval místo portu save-segment-dialog.tsx + segment-icon-picker.tsx → muselo se zahodit.)
1. App Shell je MASTER pro všechny obrazovky (bez výjimky)
Pravidlo. App Shell (_ds/app-shell.js + _ds/app-shell.css, komponenta DS.AppShell) je jediná master šablona aplikačního rámu. Každá obrazovka, kterou aplikace obsahuje, se vykresluje skrz DS.AppShell — topbar (logo · přepínač Datamart/CRM · hledání · notifikace · účet) a levou navigaci nesmí žádná obrazovka kreslit sama. Strukturální změna v App Shell se musí promítnout do všech obrazovek automaticky.
Jak to dodržet:
- Obrazovka renderuje
<DS.AppShell mode="datamart|crm" active="<nav-key>" …>{obsah}</DS.AppShell>a doDS.AppShellvkládá pouze svůj obsah (centrální plocha) a případnědrawer(pravý náhledový panel). - Sdílené obrazovkové enginy jdou taky přes shell:
DS.SegmentScreen(tabulky Lidé/Firmy, Průvodci) vykresluje obsah doDS.AppShell(viz_ds/segment-screen.js).DS.PersonDetail(detail osoby) vykresluje doDS.AppShell(viz_ds/person-detail.js).- Žádné lokální
gbar/sidebar/pd-gbarrámy v jednotlivých souborech. Každá obrazovka musí načíst_ds/app-shell.css+_ds/app-shell.js. - Drawery (record / preview) se dokují do slotu
.as-drawershellu — elevaci (stín) určuje jen slot, jednotlivé drawery vlastní stín nemají.
Hranice pojmu „obrazovka". Obrazovka = navigovatelný pohled aplikace (Domů, Pipeline, Lidé, Firmy, Company/Deal/Person drawer, Person detail, Průvodci). Referenční katalogy stavů a komponent (Prázdné stavy, Chybové stavy, Loading, Notifikace, Toasty) nejsou obrazovky — dokumentují stavební prvky v izolovaných rámech; samotné stavy (loading/empty/error) se v reálných obrazovkách už dnes zobrazují uvnitř shellu.
Výjimka — plnoplošné brány mimo shell. Registrace / login / onboarding a podobné fokusní brány (před vstupem do aplikace) shell NEpoužívají; řídí se pravidlem 4 (čisté plochy). Vše ostatní jde přes shell.
2. Bonita — barvy odvozuj z ratingu (DS tokeny)
Barva bonity se odvozuje z písmena ratingu, nikdy se nezapisuje natvrdo u dat. Kanonická mapa (zdroj pravdy: DS.SegData.BONITA_BANDS):
| Tón (DS token) | Ratingy |
|---|---|
green (--bonita-green) | AAA, AA |
lime (--bonita-lime) | A, BBB |
amber (--bonita-amber) | BB, B |
rose (--bonita-rose) | CCC, CC, C |
grey (--bonita-grey) | D |
Helper: DS.gradeTone(grade) (v _ds/segment-screen.js). Vizuál = tlumená „pill" .grade <tón> (světlé pozadí + barevný text z DS tokenů) — stejně v tabulkách, scale i detailech.
3. Avatary — DS styl (hashHue)
Avatary používají DS treatment: světlé pozadí --surface-75, 1.5px barevný okraj a barevný iniciál z hsl(var(--av-hue) …), kde --av-hue = hashHue(jméno). Kruh pro osoby, zaoblený čtverec pro firmy. Žádné plné syté pozadí s bílým iniciálem.
4. Čisté plochy — bílé pozadí, tenký rámeček, vzdušné (Attio)
Fokusní plochy mimo aplikační shell (přihlášení, registrace, onboarding kroky, dialogy) musí působit čistě a vzdušně jako Attio:
- Pozadí = bílá (
--surface-100). Šedý--shell-bgje vyhrazen JEN pro aplikační rám (topbar + sidebar), nikdy pod fokusní obsah. - Každý krok ohranič tenkým jemným rámečkem —
1px solid var(--border),--radius-xl, velký a vzdušný (štědrý padding). Přesně jako kroky onboardingu v Attio. (Tohle Štěpán chtěl — rámeček ano, jen tenký a bez stínu.) - Žádný stín — vůbec. Rámeček = jen tenká linka (
box-shadow: none). Drop-shadow (--shadow-pop) patří jen skutečným overlayům (pop-upy, menu, drawery), nikdy fokusním kartám. - Vzdušnost přes DS spacing (
--sp-*): štědré mezery, méně prvků, restraint (Apple/Attio). Hierarchie váhou + barvou. - Vnitřní prvky (inputy, řádky zdrojů, preview panely) mají jemný hairline
--bordernebo tlumené pozadí--surface-75.
Referenční implementace: _ds/auth.css (.au-card) + karty Registrace · *.
5. Tlačítka — vždy DS tlačítko v jeho definované velikosti
Tlačítka jsou jediná DS komponenta (Components · Buttons): kanonická třída .acrm-btn v apps/web/src/ds.css (.btn je alias), v Reactu ji emituje @acrm/ui <Button>. Žádná obrazovka si nevyrábí vlastní (větší) tlačítka ani nepředefinovává .btn per-screen.
- Velikost =
--control-h(≈28–30px), label 12–13px,--radius-sm. Nikdy nevymýšlej „velká" 40–44px tlačítka pro login/marketing. Plnou šířku řešwidth:100%, ne zvětšováním výšky. - Varianty:
primary=--accent+ okraj--accent-press(label 500 12px Inter);default/sekundární = bílé + okraj--line-300+--shadow-sm;ghost= transparentní (hover--hover-surface). Google =defaultlook + G. - Tvar = rounded-square (
--radius-sm/md); nikdy pill/kruh (ty jsou jen pro avatary, status-dots a pill-badge).
6. Titulky a podtitulky — JEDEN zdroj jsou type tokeny
⛔ Verzálky (ALL CAPS) jsou globálně zakázané. Nikdy nepoužívej uppercase „eyebrow"/overline styl sám od sebe — pouze když si o to uživatel explicitně řekne. Platí pro titulky, labely, tlačítka, menu, názvy sekcí v navigaci i mikro-eyebrow.
text-transform: uppercasese v UI nepoužívá. (Zdroj: DS „Psaní titulků a popisů" — „Uppercase overline nepoužíváme".)
Pravidlo. Každý titulek a podtitulek obrazovky se odvozuje z type tokenů — nikdy se nezapisuje natvrdo (font: 600 15px …). Změna měřítka v jednom místě (token) se promítne na všechny obrazovky.
Zdroj tokenů = kód:
packages/ui/src/tokens/tokens.cssnaorigin/main.legacy/colors_and_type.cssje export, ne kánon — čti ho jen jako historii.
| Role | Token | Použití |
|---|---|---|
| Page title / dashboard hero | --h1 (Geist 500 16/1.2) | největší, který shipuje — pozdrav na Domů, hlavní nadpis stránky |
| Primární titulek | --h2 (Geist 500 15/1.25) | titulek segmentu, jméno v draweru, titulek sekce, view bar |
| Podnadpis | --h3 (Geist 500 13/1.35) | menší nadpis uvnitř sekce |
| Eyebrow / overline | --section · --overline | drobný štítek nad titulkem — sentence case, NIKDY verzálky |
| Popisek pole | --label (Geist 500 12/22) | popisek nad/vedle vstupu |
| Nápověda pod polem | --hint (Geist 400 12/1.45) | vysvětlení, ne hodnota — proto 400 (AD 26. 8. 2026) |
| Podtitulek | --subtitle (Geist 400 13/1.5) | doplňková řádka pod titulkem, vždy --fg-secondary |
Rodina je jedna: Geist (--font-sans i --font-display), plus Geist Mono výhradně v roli níže. Manrope ani Inter už v systému nejsou — od 29. 8. 2026 (!2571). --tracking-tight je 0: Geist se záporný tracking nedopisuje.
Sdílené třídy (v colors_and_type.css): .ds-page-title, .ds-section-title, .ds-subtitle, .ds-eyebrow. Použij je (nebo tokeny) na každém novém titulku.
Pravidla obsahu (DS „CONTENT FUNDAMENTALS"):
- Sentence case — nikdy Title Case pro titulky/sekce/tlačítka/menu.
- Bez tečky na konci titulku (titulek je štítek, ne věta).
- Max 16px — hierarchii tvoří váha + barva, ne velikost. Žádné 21/26px display nadpisy uvnitř aplikace.
- Váhy = 400 / 500 / 600, nic víc (ruling 6. 7. 2026, karta
Type · Weights): 600 je strop, váhy 700+ se nepoužívají; native<b>/<strong>je přemapováno na 600. Headingy samotné jedou 500 (--h1/--h2/--h3) — 600 zbylo na--sectiona na zvýraznění uvnitř textu. Hierarchii dělá váha a barva, ne velikost. - Nadpis sekce BEZ ikony (AD 18. 9. 2026, ACRM-359) —
.sb-huvnitř detailu (schůzka, projekt, obchod, osoba…) nese jen text + počet + akce. Ikona před nadpisem sekce („✓ Rozhodnutí“, „⚠ Námitky“) je dekorace, která se sčítá přes celou obrazovku; ikony patří řádkům a akcím, hierarchii nadpisů dělá váha a barva. - Podtitulky ÚSPORNĚ — jen když nesou informaci navíc. Žádné dekorativní „výplňové" podtitulky pod každým titulkem.
- Eyebrow/overline = sentence case, NIKDY verzálky. ALL CAPS, kapitálky ani Title Case nepoužíváme nikde — ani na mikro-eyebrow, ani na názvech sekcí v navigaci. Hierarchii dělá váha a barva, ne velikost ani velikost písmen.
6.1 Monospace — jen finanční výkazy, kód a klávesy
Rozhodnutí Štěpána 31. 8. 2026 (ACRM-34), potvrzené 2. 9. 2026: „Jediné místo, kde monospace používáme, jsou finanční výkazy." — „souhlasím s AD, odstraň to mono, kde to jde."
| Mono ANO | účetní výkazy (kódy účtů, částky; v appce scoped .acc-page/.acc-inv), doslovný kód, klávesové zkratky (kbd), identifikátory ke zkopírování (ID workflow, kódy majetku, QR štítky) |
| Mono NE | datové tabulky, meta a termíny v railu, datumy a časy, počty a odznaky, popisky grafů, názvy |
Kritérium, když je to hraniční: mono má smysl tam, kde mřížka glyfů něco znamená — sloupec, který se má zarovnat, nebo doslovný kód. Jednociferné číslo v pilulce nemá s čím lícovat, takže je to dekorace. Sloupce čísel se zarovnávají přes font-variant-numeric: tabular-nums na sans, ne přes rodinu písma (a tabulkové číslice nikdy u dat a časů — datum je text, ne číslo; AD 22. 7. 2026).
Čas, který se nesmí posouvat, bez tabular-nums (zadavatel 26. 9. 2026, přehrávač přepisu schůzky — apps/web/src/components/meetings/TranscriptPlayer.tsx, apps/web/src/ds/meeting-record.css .player .tm): proporcionální text má u každé číslice jinou šířku, takže odpočet vedle sebe „poskakuje" a stopa přehrávače se s ním hýbe. Řešení NENÍ tabular-nums (ten je u času zakázaný výše) — buňka dostane pevnou šířku přes neviditelné vzory nejširších číslic: display: inline-grid, viditelná hodnota a dva aria-hidden vzory se stejným textem nahrazeným 0 a 8 (nejširší číslice písma) sdílejí grid-area: 1 / 1, takže šířku buňky určuje nejširší z nich a viditelný text zůstává kanonický proporcionální text, jen s pevnou kotvou.
Proč se to rozlezlo (a proč to hlídat): do 29. 8. 2026 mapoval --font-mono na Inter, takže monospace fakticky neexistovalo a psát ho kamkoli bylo bez následku — zažilo se to jako „zvýrazni číslo". !2571 (Geist) ho přemapoval na skutečný Geist Mono a tím se mono tiše obnovilo na ~100 místech naráz. Není to sto rozhodnutí, je to jedno rozhodnutí stokrát zopakované. Odklizeno v appce 9 MR (!2770–!2805), v zrcadle !2724.
Výjimka — plnoplošné brány mimo shell. Auth/onboarding (
_ds/auth.css,.au-title/.au-sub) mají vlastní vzdušnější měřítko — řídí se §4, ne 16px capem. Je to dokumentovaná výjimka, ne licence pro velké nadpisy v appce.
Referenční anti-pattern (vše už přepojeno na tokeny): lokální .home-greet 26px, .sgb-title 14px, .vtitle / .mtitle / .pipe-nm / .pdr-top-name 700 15px.
7. Navigace — IA žije v App Shell (jeden zdroj)
Pravidlo. Informační architektura levé navigace je jediná konstanta NAV v _ds/app-shell.js (+ ROUTES, PARENT). Žádná obrazovka nekreslí ani nedefinuje navigaci sama — vše jde přes DS.AppShell (viz §1). Změna IA v app-shell.js se promítne do všech obrazovek automaticky.
- Typy uzlů:
row(řádek nejvyšší úrovně) asection(rozbalovací sekce); v sekci jsouitem(záznam / segment / průvodce) aaction(„+ nová věc", přerušovaný okraj). Vzor 1:1 =templates/sidebar-nav/SidebarNav.dc.html. - Sekce jsou sentence case (Záznamy · Segmenty · Pohledy) — NIKDY verzálky. Hlavička je klikací (sbalí/rozbalí): chevron vlevo + jemná modrá count kapsle (
--accent-tint/--accent-ink) vpravo. - Badge: počet na hlavičce sekce = jemná modrá kapsle (
--accent-tint/--accent-ink, tabular-nums). Notifikační badge na řádku = plný--accent, bílé číslo. Záznamové řádky badge nemají. - Klíče
activejsou kontrakt.home · lide · firmy · sro · praha · kraje · brno · lide-pruvodce · firmy-pruvodce · pipeline · moje · potermin · riziko— při úpravě IA je zachovej, jinak se rozbije zvýraznění aktivní položky i routing.
8. Section top bar — uzavřený slovník prvků (jen povolené)
Pravidlo. Horní lišta sekce (content toolbar pod App Shellem, na každé obrazovce) smí obsahovat POUZE prvky definované v kartě Components · Section top bar. Žádné jiné. Slovník je uzavřený — co tam není, na lištu nepatří.
Povolené prvky (a nic víc):
- Identita vlevo — ikona + název sekce. Buď plochá ikona (
--fg-secondary) + název, přepínač (.pipe-btn: dlaždice/ikona + název + chevron, otevírá menu), nebo kruhový avatar (.nav-pav) u detailu záznamu. Jen jedna identita, vlevo. - Oddělovač
.tdiv— svislá linka 1 px / 20 px mezi skupinami ovládání. - Ovládací chip
.tchip— rounded-rect (radius-md), v něm: ikona + volitelně.k(tlumený štítek) +.v(hodnota, bold) +.chev(chevron, otevírá menu). Tohle je jediný prvek pro zobrazení / řazení / filtr / rozsah. Aktivní stav = modrý okraj (.tchip.on), ne výplň. - Výplň
.vspace— pružná mezera (flex:1), odtlačí akci doprava. - Tlačítko
.btn/.btn.primary— vpravo; maximálně jedna primární (plná modrá) akce na obrazovku.
Zakázáno (časté prohřešky):
- Pilulky (
.chip,border-radius: pill) jako filtry/taby v liště. Pill se v Section top baru nevyskytuje — filtr/přepínač je vždy.tchips chevronem a rozbalovacím menu (vzor = přepínač zobrazení v kartě). - Jiná značka identity, než jakou má táž položka v navigaci. Rozhodnutí zadavatele 27. 9. 2026: identita v liště = TATÁŽ značka jako položka v menu (
nav-catalogue.ts) — řádek s ikonou → plochá ikona (--fg-secondary); podpoložka s barevnou dlaždicí (sg) → barevná dlaždice se stejným glyfem a tónem. Detail záznamu dědí značku své sekce (projekt = dlaždice Projekty, úkol = ikona Úkoly, schůzka = ikona Kalendář). Výjimka — přepínač (pipeline): spouštěč ukazuje značku VYBRANÉ položky + chevron, jako každý výběr (zadavatel 27. 9. 2026, 7b). Implementace (acrm !4017, vlna H): značku NIKDY nepiš ručně — ber ji zapps/web/src/components/section-mark.ts:useSectionMark()(značka + název aktuální položky menu),sectionMarkFor(path, search, mode),sectionMarkForKey(key)(značka jiné sekce, např. drobečky detailu úkolu → Projekty), adaptérymarkProps(→ propsSectionTopBarTitle) asegmentMark(dynamické segmenty / procesy — značka z dat, shodná s menu). Výjimky, které helper záměrně neřeší: přepínač pipeline (značka vybrané položky), identita osoby/firmy/obchodu (kind, 32 px), detail úkolu jako drobečky (s projektem = Projekty, bez = Úkoly). - Dvě+ primární tlačítka, sekundární akce naházené do lišty, vlastní jednorázové „chipy" mimo
.tchip. - Verzálky v názvu i v chipech (sentence case, §6).
Escalation (když prvek opravdu chybí). Slovník nerozšiřuj potichu. Designer napíše krátké zdůvodnění Art Directorovi: (a) jakou potřebu prvek řeší, (b) proč to nejde stávajícími pěti prvky, (c) návrh tokenů/chování. Teprve po schválení se prvek přidá do karty Section top bar (zdroj pravdy) a až pak na obrazovky. Bez schválení v kartě = na lištu nepatří.
Self-review před publikací lišty: projdi prvky zleva doprava — je každý z povolené pětky? Je identita právě jedna? Je primární tlačítko nanejvýš jedno? Pokud něco neprojde → nahraď .tchipem nebo eskaluj.
Zdroj pravdy + anatomie + DO/DON'T: karta Components · Section top bar.
9. Allow-list — oprávněný keep označ ds-ok
Validátor (pnpm ds:validate, od 7.7.26 STRICT v pre-commitu i CI appky) shazuje každou natvrdo napsanou hodnotu: px ve spacing/gap/radius místo --sp-* / --radius-*, hex místo barevného tokenu / tone-třídy.
Oprávněný keep existuje — a MUSÍ nést marker s důvodem, jinak je to porušení:
background: #16b8c4; /* ds-ok: brand tile CRM workspace */height: '100vh', // ds-ok: viewport výška, ne spacing tokenOprávněné důvody (úplný výčet):
- brand barvy (workspace tile; kanálové glyfy ale preferuj přes
--channel-*), - gradient stops (mapový placeholder, color wheel),
- true-overlay scrim/stín definovaný overlay systémem (
--ov-scrim/--overlay-shadow), - layoutové rozměry (šířka sloupce/panelu, viewport výška — nejsou spacing škála),
- auth/onboarding vzdušné měřítko (dokumentovaná výjimka §4/§6),
- native control seed (barva nativního prvku, kterou token neřídí).
Marker patří na řádek nálezu (nebo na řádek nad něj). Pozor na prettier: dlouhé deklarace (gradienty) láme na víc řádků a marker odsune z řádku nálezu — takové řádky chraň /* prettier-ignore */. Marker potlačí TOKEN/COLOR nálezy, nikdy HARD (verzálky výjimku nemají).
10. Dialog system — jeden plášť pro všechny overlaye
Pravidlo. Každý dialog v aplikaci je instance JEDNOHO systému (karta Components · Dialog system, app: .acrm-dialog + <Popup> / useConfirm()). Žádné bespoke modaly, žádný window.confirm.
- Scrim = jednotný závoj
--ov-scrim; oddělení pláště dělá jen podpisový stín--overlay-shadow(jen skutečné overlaye — nikdy fokusní karty, §4). - Tvar =
--radius-xl, bílý povrch, obsah clipnutý; max 1 rám (§0). - Kotva: form dokuje ~11vh od horní hrany; confirm centruje.
- Šířky = TŘI TŘÍDY, ne řada čísel (ACRM-320/321,
<Dialog size>):s400 confirm a picker ·m750 formulář (default dialogů se vstupy) ·lflexi dokument, e-mail, náhled souboru a buildery — bez pevné míry, šířku bere z okna se stropem 1200, výšku z obsahu. Číslo vwidthje deprecated: nový dialog si vybírá příčku, ne pixely. Měřený vzor: Linear 750, Attio 800. Head+foot pinned, scrolluje jen tělo (.tall= 88vh). - Patička: vlevo kontextové ghost afordance (
.lead), vpravo sekundár a max jeden primár; destrukce =.btn.danger(--critical). - Klávesy / fokus / motion: Esc zavře; fokus po otevření na panel (autofocus input vyhraje) a po zavření zpět na trigger; scrim fade 120 ms, plášť rise+scale 160 ms, reduced-motion okamžitě.
- Confirm (nevratné/destruktivní rozhodnutí): titulek + jedna věta důsledku + Zrušit + destruktivní primár — v Reactu
useConfirm()(promise), nikdy nativníwindow.confirm.
11. Přechod mezi stavy prvku — jeden prvek, který se přetváří
Pravidlo (AD 17. 9. 2026). Když prvek mění stav (chip nahrávání, tlačítko s průběhem, lišta, dlaždice), nevyměňuje se za jiný prvek — zůstává týž a jen se přetvaruje. Nic nepřilétá ani neodlétá.
- Jeden trvalý prvek. Rámeček (u chipu kanonický
.tk-chip) je v DOM po celou dobu; stav nese atribut (data-phase), ne jiná komponenta. - Mění se jen rozměr — šířka (u svislých prvků výška) z předchozí na novou kanonickou PRUŽINOU (zadavatel 26. 9. 2026,
packages/ui/src/lib/spring.ts: tlumený oscilátor, tuhost 190, tlumení 17, ~750 ms, přestřelení ~6 %, WAAPI klíčové snímky). NAHRAZUJE dřívější0,29 s cubic-bezier(0.32, 0.72, 0, 1)(ACRM-152) — ten kánon skončil, nedoplňuje se.<Dialog morphKey>(okno) aMorphText(šířka textu,@acrm/ui) jedou na pružině; oba mají kanonický záznam v DS registru (spring,morph-text). Žádná vlastní délka ani křivka. - Obsah se prolne NA MÍSTĚ. Odcházející vrstva se vyjme z toku (
position: absolutena téže pozici, šířku určuje jen příchozí) a rozplyne se (opacity, ~0,14 s ease-out); příchozí najede opacity 0 → 1 za 0,2 s se zpožděním 0,06 s. Žádný posun ani zvětšení —transformzůstávánone. - Tvar se nemění: výška, rámeček, radius i písmo jsou ve všech stavech tytéž a obsah je dědí. Stav „probíhá přepis" nesmí být vyšší než stav klidový — skok rozměru rozbije řadu chipů.
- Glyf uvnitř (pauza ↔ přehrát) se mění prolnutím ikony (opacity + scale 0,6 → 1, 0,2 s), ne výměnou celého obsahu.
- Animuje se jen ZMĚNA STAVU, ne každý render (tikající časomíra, dotažená data) — jinak se přechod ruší uprostřed. Změna během běhu začíná z právě viditelného rozměru.
- Výchozí rozměr měř v okamžiku akce (klik), ne z pozorovatele velikosti: ten drží hodnotu z doby před načtením písma (změřeno 83,7 místo 85 px → poskok zpět).
prefers-reduced-motion= výměna bez animace (springAnimatevrátínull, odcházející vrstvadisplay: none). Pro celou appku to navíc drží globální pojistkaapps/web/src/ds/reduced-motion.css(acrm !4008, 27. 9. 2026): poslední vrstva CSS (ve všech třech seznamech —main.tsx,.ladle/components.tsx,ds-proto-build.mjs), která při omezeném pohybu zkrátí každýtransitionaanimationna0.01ms, vynuluje delay, pustí animaci jen jednou a vypne plynulé rolování. Proč0.01ms, ne0s: nulová délka nevyvolátransitionend/animationenda kód, který na ně čeká (zavření šuplíku, odmontování), by uvízl. Pojistka pokrývá i portované soubory, na které se nesahá. Lokální přepis (např. „ruka zůstane stát“) je přesnější a zůstává. Nový přechod proto nemusí psát vlastní blok, ale nesmí spoléhat na průběh animace (výsledný stav musí být správný i bez ní).- Ověřuje se po snímcích, ne okem: rozměr jede po křivce pružiny (viz
spring.ts), výška konstantní,transform: none, obě vrstvy během prolnutí na téže levé hraně.
Proč: výměna prvků čte jako dva různé objekty — oko sleduje „něco přiletělo" místo „tohle se změnilo". První kolo návrhu nahrávacího chipu takhle vypadalo a AD ho zamítl; přijaté chování je jeden objekt, který se roztahuje a zužuje.
Referenční implementace (vše na pružině, acrm !4016, 27. 9. 2026): <Dialog morphKey> (packages/ui/src/components/Dialog.tsx), MorphText (packages/ui/src/components/MorphText.tsx), ChipMorph (apps/web/src/components/notes/ChipMorph.tsx — šířka chipu; sdílí ho i NoteRecChip v NoteAudio.tsx), kurzorový pruh výpisu .il-cursor-bar (ItemList.tsx) a formless okno: use-avail-spring.ts (šířka okna + posun, posun drží, dokud šířka nedojede — SPRING_ARRIVE_MS) a use-formless-height-spring.ts (výška .fl-body, obsah se nehýbe) v apps/web/src/components/meetings/. Dřívější @keyframes flaSettle a CSS přechody šířky/výšky formless okna zanikly. Stará křivka cubic-bezier(0.32, 0.72, 0, 1) smí zůstat jen u prolnutí obsahu (bod 3), vstupních animací a barvy — nikdy u změny rozměru.
Past — vlastní proměnná čtená z JS: proměnnou s clamp() / 100vw (např. --fla-shift) Chromium v getComputedStyle(el).getPropertyValue() nevyhodnotí — vrátí nevyhodnocený výraz, ne pixely. Když JS potřebuje hodnotu v px (cíl pružiny), čte ji přes skrytou sondu (prvek s width: var(--x) a měří jeho getBoundingClientRect().width), ne ze stylu proměnné.
12. Žádné dvě úrovně záložek nad sebou
Pravidlo (zadavatel 27. 9. 2026 zamítl TabStrip pod taby v detailu uživatele). TabStrip / Tabs řádek se nikdy nekreslí pod jiným taby řádkem — jedna obrazovka nese nejvýš jednu vodorovnou řadu záložek. Když obsah potřebuje druhou úroveň volby:
- Je to nová stránka, ne záložka. Druhá úroveň navigace = vlastní položky menu + vlastní stránky (vzor
Settings page, kartaSection top bar · Settings page) — ne vnořený TabStrip pod existujícímrecord-tabs. Osobní nastavení a preference nejsou záložka detailu záznamu (uživatele, firmy, …); patří do Nastavení jako vlastní položka a vlastní stránka. - Nebo je to jeden
Segmented controluvnitř stránky (např. E-mailové šablony „Moje | Firemní"), ne druhý řádek tabů. Segmented je přepínač obsahu JEDNÉ stránky, ne navigace mezi stránkami — nesmí se řadit pod.tbar/record-tabsjako by to byl další tab strip.
Zakázáno: TabStrip/Tabs bezprostředně pod record-tabs (nebo pod jiným TabStrip), a to i když je vizuálně odlišený (menší, jinak podbarvený) — dvě úrovně tabů nad sebou zamítá i vizuálně upravená varianta. Řešení je vždy buď samostatná stránka (Settings pattern), nebo Segmented control v obsahu, nikdy druhý tab řádek.
Zdroj pravdy + anatomie: karty Components · Tab strip, Components · Record tabs a Components · Settings page (docs/section-top-bar/settings-page).
13. Rozměr = token podle VÝZNAMU
Pravidlo (zadavatel 27. 9. 2026, vlny F + F4). Rozměr v CSS se nepíše číslem, ale tokenem, který říká, co to je — ne jakou má hodnotu. Stejné číslo s jiným významem = jiný token (--pill-h a --tile-sm mají obě 22 px, ale můžou se rozejít). Zdroj: packages/ui/src/tokens/tokens.css.
| Co to je | Token | Hodnota |
|---|---|---|
| glyf / ikona | --ico-2xs · -xs · -sm · -md · -lg · -xl | 12 · 14 · 16 · 18 · 20 · 24 |
| mezera, odsazení | --sp-* | škála mezer |
| výška ovládání (tlačítko, přepínač) | --control-h | 30 |
| kompaktní ovládání (Button compact, IconButton sm, tlačítko v řádku) | --control-h-sm | 24 |
| vstupní pole, select, hledání + ovládání topbaru, které s nimi lícuje | --field-h | 32 |
| řádek výpisu / navigace | --row-h · --row-h-nav | 37 · 28 |
| avatar v textu · výchozí · velký | --avatar-xs · -sm · -lg | 16 · 24 · 32 |
| tečka indikátoru · tečka stavu | --dot-sm · --dot | 6 · 8 |
| pilulka malá · pilulka | --pill-h-sm · --pill-h | 20 · 22 |
dlaždice přepínače (.pipe-tile) | --tile-sm | 22 |
| silná čára (indikátor záložky, spoje) | --line-thick | 2 |
- Nový token jen s významem, ne pro jedno číslo. Když hodnota nemá význam na škále (komponentní rozměr, kresba 1:1 z předlohy), zůstává viditelným dluhem v ratchetu — ne
ds-okjen kvůli čistému výpisu.ds-okpatří tam, kde by byl nutný i v novém kódu (glyf = výška sousedního textu, iniciály avataru) a vždy s důvodem na řádku. - Baseline ratchetu (
dluh,suppressed) se nikdy ručně nezvyšuje — mr-bot to hlásí jako obcházení brány. Ratchet jen klesá. - Glyf v boxu má paritu s boxem: box − glyf = sudé číslo (18 → 12 / 14, 32 → 14 / 16); lichý rozdíl = kresba na půlpixelu, vypadá rozmazaně.
- Tokenizace nemění hodnotu. Změna hodnoty (např. pole 32 → 30) je vizuální změna → návrh.
14. Žádné popisné texty v základním UI — vysvětlení do (i)
Zadavatel 3. 10. 2026: „přesně takový přístup musíme mít, žádné dlouhé popisné texty v základním UI, vše schovávat do (i)“ (návrh v2 na Nastavení, :3777/preview/vysvetlivky-info-tooltip.html). Navazuje na AD 9. 8. 2026: nikdo je nečte.
- Nejdřív škrtat. Věta, která nemění rozhodnutí uživatele, zmizí. Význam nese struktura, hierarchie, glyf a chování.
- Co zbyde a mění rozhodnutí (důsledek, nevratnost, odkud se berou data) jde do InfoTip (i) za nadpisem sekce nebo popiskem pole: klik / tap otevře, tap mimo nebo Esc zavře, max 2 věty / 280 px, na dotyku terč
--tap-min. Tooltip zůstává jen pro název akce nebo důvod, ne pro vysvětlení. - Viditelné zůstávají: stav („Na účtu zatím není žádné číslo“), chyba, varování, které se musí přečíst DŘÍV (např. automatizace odešle reálné e-maily), data a jediný návod k akci.
- Příklad nebo formát hodnoty („např. věcně, zdvořile…“) patří do placeholderu pole, ne pod pole.
- Sekce, po které zbyde jen nadpis + (i), se přeskládá. Sekce bez obsahu nestojí sama.
- Doplňkový světlý text (
--fg-muted) zůstává světlý (zadavatel 3. 10. 2026); co má být čitelné, je--fg-secondary. - Hostitel (i) je nejbližší nadpis nebo popisek:
SectionBlock info,Field labelExtra(stojí VEDLE<label>v.acrm-field-head),.flabel,.dlg-label,SegCol.info(hlavička sloupce tabulky). (i) nikdy uvnitř<label>obalujícího ovládací prvek a nikdy v tlačítku; vysvětlení přepínače nebo zaškrtávátka jde do (i) jeho pole. Kde hostitel chybí (prázdný stav), zůstane jedna viditelná věta. - Krátké varování před nevratnou akcí stojí u tlačítka („Odejde přesně tento text.“), ne v (i).
Výsledek akce 3. 10. 2026 (10 MR: !4504, !4507, !4511, !4515, !4517, !4519, !4520, !4522, !4525, !4529): ~130 textů do (i), ~40 smazáno, 11 do placeholderu, ~85 zůstalo viditelných (stavy, chyby, varování, jediné návody). Po cestě opraveno: popisek pole otevíral (i) (labelExtra uvnitř <label>), Avatar bez fallbacku na iniciály, přetékání Průvodce na 390, potomkovský selektor .sgb-flabel .ti.
15. Upozornění = červená a původní ikona
Zadavatel 3. 10. 2026 (zamítl amber u duplicit: „fuj, hnědá, škaredej trojúhelník… pokud to někde takto používáme, změň to všude“):
- Upozornění (ikona + text u řádku, v dialogu, u duplicity, varování v okamžiku rozhodnutí) má glyf
alert-square-roundeda barvu--critical(glyf) /--critical-ink(text). alert-trianglea text v--warning-inkse u upozornění nepoužívají.- Datové barvy v grafech a ukazatelích (pásmo Koučinku
--ic-amber, reporty, stat tile) nejsou upozornění a zůstávají. - Hnědá se v aplikaci nepoužívá vůbec, nikdy (zadavatel 3. 10. 2026: „vůbec nepoužívej hnědou… nikdy“). Hnědé jsou tokeny
--warning-inka--pill-amber-inkve světlém režimu (#a35200) a--warning-subtle/--pill-amber-bgv tmavém (#331b00). Žádný text, glyf ani plocha v hnědém tónu. Jasná oranžová (--ic-amber#ff990a,--warning#ffb224) hnědá není. - Upozornění a chyba vypadají stejně (glyf
alert-square-rounded,--critical) — i u toastu (ToastProvider: warning a error). Rozliší je text, ne barva ani jiný glyf. Návrh „varování jinou barvou / jantarovou“ (i z review bota) se zamítá s odkazem na tento bod (AD 4. 10. 2026, acrm !4576). - Barva nese prioritu, ne kategorii (zadavatel 4. 10. 2026 k souhrnu importu: „vše červené, není vidět priorita… vrcholem je červená ikona na zeleném pozadí“). Červená jen u toho, co vyžaduje rozhodnutí hned (a jen glyf + titulek / počet); kontrola = neutrální nebo accent; hotovo / informace = tichý řádek bez rámečku. Glyf má vždy tón svého řádku / pruhu — nikdy červený glyf na zeleném nebo jiném tónu. Bloky na jedné stránce mají jednu šířku. Pořadí shora: rozhodni → zkontroluj → hotovo.
16. Názvy tříd bez segmentu „ad“ (blokátory reklam)
Incident 6. 10. 2026 (ATSL, FA256): blokátor reklam schoval popisek .cwk-adlabel v liště „celý den“ týdne kalendáře, grid poskočil o sloupec a celodenní schůzky visely o den dřív. Kosmetické filtry (EasyList, AdGuard, uBlock) skrývají prvky podle tříd a id s „ad“ segmentem.
- Žádný segment třídy ani id (část mezi
-/_) v kánonu, kartách, screens ani v appce nesmí býtad,ads,adv,advert…,sponsor…aniad+ slovo (adlabel,adcell,adev,adbox,adbanner,adslot…). Běžná slova (add,addr,admin,adresa) jsou v pořádku. - Zkratky piš celým slovem: celodenní =
allday(.cwk-allday-label/-cell/-ev/-more/-pop), nikdyad. - Appku hlídá kontraktní test
apps/web/src/ds/__tests__/tridy-bez-reklamy.contract.test.ts(acrm !4780); název ze starého kánonu by při portu neprošel.
17. Myš a dotyk mají přednost před klávesnicí; přetahování vždy s kopií pod kurzorem
Zadavatel 6. 10. 2026 (FA255, přes CTO: rozbité přetahování obchodů po refaktoru desky z 3. 10. — tažená karta „se nechytne myši", jen ztlumení a čára):
- Vzhled, chování a funkční prvky UI mají přednost před přístupností z klávesnice. Klávesové ovládání se přidává jen tam, kde nic nezhorší pro myš a dotyk; kvůli němu nesmí z toho, co uživatel vidí a používá, nic ubýt. Návrh, který kvůli klávesnici ubírá viditelné chování, se zamítá s odkazem na tento bod.
- Každé přetahování v aplikaci má kopii taženého prvku, která jede s kurzorem / prstem —
.acrm-drag-ghost(apps/web/src/ds/reorder.css: podklad--bg-canvas, stín--shadow-pop,--radius-md) přes sdílenéliftDragGhost/useReorderz@acrm/ui(acrm !4774, !4776). Místo dopadu ukazuje rozestup cíle a zvýrazněné místo.acrm-drop-slot(čárkovaný--accent, podklad--accent-tint, pod kopií) přesdropGapz@acrm/ui(zadavatel 6. 10. 2026, acrm !4796 — čára „sem“ nestačila a zanikla). Ztlumení zdroje a místo dopadu jsou doplněk, kopii nenahrazují. Z návrhů ji neodstraňuj.
18. Tlumený text --fg-muted se nemění
Zadavatel 7. 10. 2026 (R15, podnět FA257 z Datamart e2e): --fg-muted (--ink-400, světle #98999c, tmavě #717479) zůstává, i když jako běžný text nesplňuje WCAG AA (2,85 : 1 / 3,63 : 1). Je to vědomé rozhodnutí o vzhledu (RULES §17.1 — vzhled má přednost). Návrh ztmavit token nebo zavést druhý „textový" tlumený token se zamítá s odkazem na tento bod; kde text musí být čitelný naplno, patří do --fg-secondary / --fg podle významu.
19. Dotykový cíl na telefonu ≥ 44 px, vzhled se nemění
Zadavatel 8. 10. 2026 (bod 16, FA257, acrm !4882, prototyp proto/touch-targets-mobile@522540199):
- Pod 720 px má každé
.acrm-icobtn(ismaframed) a.acrm-btnneviditelnou plochu::afteraspoň 44 × 44 px (apps/web/src/ds/responsive.css, selektor v:where). Glyf, rozměr tlačítka ani hustota řádků se nemění; desktop beze změny. FAB je vyňatý. - Plocha nesmí krást klepnutí sousedovi: roste od levého horního rohu doprava a dolů, v liště sekce (
.tbar) svisle na střed; řádky výpisů (.il-li) a pole formulářů se kreslí nad ní;⋮sloupce tabulky má plochu jen do výšky. Ověřeno 18 tras × 430 klikatelných prvků, 0 % cizí plochy. - Nové tlačítko vlastní
::after,min-heightani „velkou" variantu pro telefon nedostává — cíl řeší toto pravidlo. Kde předek plochu ořízne (overflow), je to chyba k opravě, ne důvod ke zvětšení vzhledu.
20. Štítky výpisu vždy ve slotu tags
Zadavatel 8. 10. 2026 (zadání komunikace na kartě R13, acrm !4915, review AD FA258 / FA259 / FA264):
- Pilulky, které řádek výpisu štítkují (štítek pošty, tag úkolu, štítek projektu), patří do slotu
tagskomponentyItemList— nikdy docols,metaani do vlastního sloupce. Slot kreslí pilulky doprava těsně před datum, bez pevné šířky; nepřeroste polovinu řádku, název má přednost. Stavová pilulka ve sloupci tabulky štítek NENÍ a zůstává. - Výpis se štítky nastaví na obalu
--il-meta-w(jedna šířka data pro všechny řádky), aby pravá hrana štítků lícovala. - Na telefonu (hustota
lg) komponenta sama zalomí štítky na vlastní linku pod název i datum přes celou šířku; volající nic nevětví.lgmápadding-block: var(--sp-3). - Hlavička skupiny
.tl-grpnad vnořeným výpisem (width="embedded") nese.is-embeddeda jde přes celou šířku boxu; žádné lokální dorovnání v obrazovce. - Pilulka s vedoucí ikonou nemá tečku a ikona nese tón (
.acrm-pill > .ti { color: var(--pill-dot) }) — obecné pravidlo pilulky, ne výjimka jedné komponenty. Štítek projektu (Project label) je.acrm-pill sm+ ikona projektu, bez vlastního CSS. - Platí pro všechny výpisy (pošta, komunikace, úkoly,
TaskListv@acrm/ui); nový výpis se štítky bez slotutagsse nevydává.
21. Přiřazení k záznamu = rovnou našeptávač, nikdy dialog s tlačítkem „Vybrat…"
Zadavatel 13. 10. 2026 (dialog „Přiřadit ke kontaktu" s vnořeným „+ Vybrat kontakt"): „tenhle úplně debilní dialog, který místo toho, aby rovnou člověk vybral osobu, má v sobě vnořený další dialog, musíš předělat, nikdy nikde už ho nechci vidět, u prolinkování osob ani firem … musí to fungovat stejně jako když přidávám nový obchod — rovnou se otevře našeptávač institucí nebo lidí nebo obojího dle toho, co se přidává — musí to fungovat všude."
- Akce „Přiřadit / Propojit / Vybrat osobu · firmu · obojí" otevře rovnou velkou paletu hledání jako u Nového obchodu (
DealSubjectStep: šířkapaletteWidth= ⌘K,PaletteSkeleton, sekce, patička ↑↓), s kurzorem v hledání; na telefonu šuplík na plnou výšku. Ne malý našeptávač v Popoveru u spouštěče — zadavatel 14. 10. 2026: „vybírám si v pohodlném UI, s kým chci obchod otevřít; v malém inline dialogu se blbě hledá, když mám třeba časté jméno". Typ výsledků podle toho, co se přiřazuje: lidé, instituce, nebo obojí. - Zakázáno: dialog, jehož jediný obsah je spouštěč výběru („+ Vybrat kontakt" / „Vybrat firmu…") a tlačítko „Přiřadit". Výběr položky v našeptávači je potvrzení — žádný druhý krok.
- Dialog smí obalit výběr jen tehdy, když vedle něj sbírá další údaj (např. typ vztahu, role); i pak je našeptávač pole uvnitř dialogu otevřené hned, ne vnořený dialog.
- Vzor: výběr firmy/osoby u Nového obchodu — paleta je tam záměrně (zadavatel 14. 10. 2026). Malý
RecordSelectu spouštěče zůstává jen pro výběr hodnoty z krátkého seznamu (stav, typ), ne pro hledání záznamu.
22. Nic navíc proti prototypu a zadání
Zadavatel 13. 10. 2026 (bubliny chatu): „tam žádný zelený proužek v návrhu nebyl … vyhalucinoval jsi ho a ještě jsi domrvil tvar bubliny."
- Implementace i návrh obsahují jen prvky ze schváleného prototypu / zadání nebo z kánonu. Nový prvek (proužek, ikona, štítek, text, barva, tvar) se nepřidává „pro jistotu" — buď ho zadavatel viděl a schválil, nebo tam není.
- Změna tvaru nebo vzhledu existující komponenty, o které zadání nemluví, je chyba, ne vylepšení.
- Kontrola před odevzdáním: snímek DNES × PO × prototyp a seznam rozdílů; každý rozdíl buď vysvětlený zadáním, nebo odstraněný.
23. Dlouhý text se zkracuje „…", celý na hover / klik
Zadavatel 13. 10. 2026: „proč přestalo fungovat zkracování dlouhého textu na …? Teď to celé rozbíjí UI … musí to fungovat tak, jak to fungovalo, a dlouhý text zobrazit po hover nebo klik."
- Titulek, jméno, předmět a buňka ve výpisu, kartě, liště i pilulce mají jeden řádek s
text-overflow: ellipsis(min-width: 0na flex/grid potomkovi). Dlouhý text nikdy nerozšíří řádek, sloupec ani dialog. - Celé znění:
title/ Tooltip na hover, na dotyku klik (detail nebo popover). Víceřádkový clamp jen tam, kde to kánon komponenty říká (popis v railu, náhled zprávypreviewLines). - Regrese zkracování je chyba s nejvyšší prioritou — vizuální testy mají mít aspoň jeden řádek s extrémně dlouhým textem v každé rodině výpisů.
24. Méně textu v UI — rozšíření §14
Zadavatel 13. 10. 2026: „nebuď tak ukecaný v UI!!!! Zákaz si to vypisovat všude viditelně hromadu textu, NIKDO TO NECHCE ČÍST!!!!"
- Viditelný text v UI = popisky, hodnoty, akce. Vysvětlení, podklady, zdůvodnění, „co se stane", nápověda a AI odůvodnění patří do (i), do sbaleného „Podklady" nebo do detailu — nikdy jako odstavec v základním zobrazení.
- Měřítko: v řádku, kartě i dialogu nanejvýš jedna věta stavu; cokoli delšího je chyba podle §14/§24.
25. Jedna věc = jeden ovladač, jedna cesta
Zadavatel 13. 10. 2026 (podpis v psaní e-mailu: ikona Podpis vedle „Podpis: plný ▾"): „Nemůžou být 2 stejné věci vedle sebe 2 různými cestami." V acrm docs/UI-RULES.md §2.2 (!5017), oprava !5019.
- Vedle sebe nikdy dva ovladače téže věci. Novou schopnost (varianta, volba) přidej do nabídky existujícího prvku.
- Zdvojení se neřeší odlišením vzhledu (sebrat ikonu, přebarvit); jeden z ovladačů zmizí.
- Vzor: psaní e-mailu má pro podpis jen ikonu
signature→ Picker menu: osobní varianty (druhý řádek = náhled textu podpisu, je to hodnota, ne vysvětlení) — oddělovač — firemní podpisy — oddělovač — × Bez podpisu; ✓ u podpisu, který leží v těle. Na telefonu ⋯ → Podpis = spodní šuplík s „Hotovo". - Plovoucí ovladač (FAB „+", plovoucí přepínač rozložení) obsah překrývá záměrně — to není zdvojení ani chyba překryvu (zadavatel 14. 10. 2026).
- Dvě ikony s téměř stejnou nabídkou = jedna ikona. Vzor: „Později" (LaterMenu, AD 24. 10. 2026, a2a FA269) nahrazuje dvojici Odložit + Připomenout — jedna ikona v liště čtečky pošty, v nabídce přepínač „Připomenout" jako řádek Picker menu. Čip odloženého stavu je
Buttonghost s tónem, ne vlastní třída. - Ikona a ovladač před textem. Kde stačí ikona nebo ovládací prvek (šipka posunu, ⋮, chevron, čip), nepíše se text. Zadavatel 14. 10. 2026 (záložky detailu firmy, „+ 8 další"): „preferuj ikony a jine ovladaci prvky misto textu". Funkce se ale neztrácí: „+ N další" otevírá vypnuté záložky, takže ji nahradí ikona, ne nic (návrh 24g). Ikonový ovladač má vždy
aria-labela tooltip.
26. Viditelnost akce podle frekvence a kontextu
Zadavatel 14. 10. 2026 (prototyp jednotné hlavičky s modrým „Nový obchod" u osoby): „Vůbec takhle nechci … to tlačítko chci jenom někdy, když to má opravdu význam. U osoby nebo kontaktu nezakládám každý den obchod … Chci, aby ten systém byl pěkný a kontextový … obchod na tom místě, kde nad ním přemýšlím … komunikace je velmi častá, ale obchody jsou zřídkavé (u 200 000 kontaktů 20 obchodů)."
- Viditelná akce v hlavičce / liště (a zvlášť modrá primární) jen pro činnost, kterou uživatel v tom kontextu dělá opakovaně (Komunikace → Napsat; výpis úkolů → Nový úkol).
- Vzácná akce patří do kontextu, kde o ní uživatel přemýšlí — sekce nebo záložka té věci (Nový obchod v „Nejbližší aktivitě" vedle „… nemá otevřený obchod", v sekci / záložce Obchody osoby, v procesu), případně do ⋮. Nikdy trvale svítící v hlavičce. Zadavatel 14. 10. 2026: „zmizelo to CTA v Nejbližší aktivita!" — kontextové CTA se neodstraňuje.
- Akce, která už nemá smysl (obchod existuje), se nenabízí výrazně.
- „Jedna primární akce" (UX základy bod 4) je strop, ne povinnost: hlavička detailu záznamu primár mít nemusí.
22. Stav patří do řádku štítků jako pilulka
Zadavatel 15. 10. 2026 (prototyp čtení e-mailu proto/mail-cteni-kontext, ACRM-523 / ACRM-525): „udělej to jako štítek … nemělo by to být výjimka, zaveď to jako pravidlo". Nahrazuje dřívější výklad z review !4390 („pilulka = jen kategorie, stav tečkou s textem").
- Stav záznamu nebo vlákna (Čeká na vaši odpověď, Čeká na ně, Po termínu, Delegováno…) se kreslí jako pilulka
.acrm-pill sm <tón>ve stejném řádku jako štítky (obchod, štítek pošty, příloha) — všechny „štítky" jedné věci drží pohromadě, nikdy rozházené do hlavičky, meta řádku a těla. - Stavová pilulka nemá křížek (stav se mění akcí, ne odebráním) a nese významový tón (
amberčeká,rosepo termínu,greenvyřízeno,greyneutrální); štítek pošty má barvu štítku. Tím se stav a kategorie liší, aniž by stav musel být jiný prvek. - Ve výpisu jde stavová pilulka do slotu
tags(§20) před štítky; ve sloupci tabulky zůstává stavová pilulka sloupce. - Tečka + text (
.il-dot) zůstává jen tam, kde pilulky nejsou (hustý řádek bez slotutags, legenda grafu).
27. Prázdný stav stojí uprostřed plochy — i svisle
Zadavatel 21. 10. 2026 (nepropojené kanály Komunikace, proto/kanaly-nepropojene): „vertikálně vystřeď na stránce — zapiš to do DS — všechny prázdné stavy vystřeď".
- Prázdný stav se kreslí uprostřed plochy, kterou nahrazuje — vodorovně i svisle. Platí pro
EmptyState(.acrm-empty, tón prázdno i chyba), „nic nenalezeno" i nepropojený / nenastavený modul (např.ChannelConnectPane). Plocha = to, co by jinak zaplnil obsah: stránka pod lištou, výpis pod FilterBarem, panel, záložka. - Hostitel vyplní zbytek plochy (
flex: 1; min-height: 0ve sloupcovém flexu) a stav v něm stojí na středu (margin: autonebojustify-content: center). Lišta, záložky a FilterBar zůstávají nahoře — vystředí se jen obsah pod nimi. - Je-li obsah vyšší než plocha (telefon), začíná nahoře a plocha roluje;
margin: autose sám srazí na 0, nic se neořízne. Žádná výjimka „na mobilu nahoru". - Sekce, jejíž výška se řídí obsahem (sekce railu, karta, popover), nemá co středit svisle — tam jen vodorovně a varianta
.sm.