Review — AI (9 Sep 2026)
The last category without a family review. Two families, two sub-components: ai-assistant (canon, app-css) and discussion (candidate, mockup only).
Source of truth: origin/main acrm (mirror /root/acrm-main). Measured in a browser against the catalogue built from that mirror.
0. Summary
Six stories, zero console errors, and the panel itself is sound. Everything found here is about what the canon record says about it — and one defect that does not belong to this family at all, but is most visible here.
That last one is the important one: a global, unqualified .sub selector in ds/segment-screen.css leaks a navigation-row style onto every .sub in the product. It turns plain descriptive sentences into things that look and feel clickable. The assistant's empty state is where it shows most clearly, which is how this pass found it — but it is a system-wide defect with six live sites.
1. Findings in the design system
A1 — A global .sub selector styles descriptive text as a navigation row (significant)
apps/web/src/ds/segment-screen.css:154 declares a bare, unqualified .sub:
.sub {
display: flex;
height: var(--row-h-nav);
padding: 0 var(--sp-3) 0 var(--sp-4);
border-radius: var(--radius-md);
cursor: pointer;
}
.sub:hover { background: var(--hover-surface); }It is meant for the navigation sub-row of the segment screen. Nothing scopes it, so it hits every element in the product whose class list contains sub.
Measured on the assistant's empty state (.aichat-empty .sub — the sentence „Asistent vidí to, co ty — tvoje obchody, kontakty a poštu."), against a plain unclassed <span> inserted next to it:
| descriptive sentence today | what a plain line is | |
|---|---|---|
| display | flex | block |
| height | 28px (= --row-h-nav) | 19.5px |
| padding | 0 8px 0 12px | none |
| border-radius | 11px | none |
| cursor | pointer | auto |
…plus a :hover background. So a sentence that explains the panel is drawn as a 28px navigation row with a hand cursor and a hover highlight, inviting a click that does not exist.
Six live sites use the bare class and every one of them is descriptive text, not navigation:
| file | what it is |
|---|---|
settings/TemplateAttachmentsSection.tsx:81 | attachment size (formatBytes) |
mail/ComposeForm.tsx:3917 | „nahrává se…" |
mail/compose/TemplatePreviewPane.tsx:322 | file size |
assistant/AssistantPrompts.tsx:488 | prompt body |
assistant/AssistantChat.tsx:901 | empty-state subtitle |
contract/ContractDocument.tsx:142 | „Slouží jako zálohová faktura" |
This is the same class of defect already recorded twice in this system — the global .ti in app-shell.css (finding A10 of an earlier pass) and the ic/fl warning written into global-search.css's own header: generic names in a shared sheet escape their component. The difference is that this one is not harmless: it changes layout and it lies about affordance.
Remedy is a one-line scope (.sgb-nav .sub, or whatever the segment screen's own root is), plus a decision about the six sites — they want a plain descriptive style, which the canon already has.
⛔ Not fixed in this pass: it touches a shared sheet and six screens, so it needs the AD's ruling and a measured before/after per site. It is also exactly the kind of change that should not ride along with a catalogue fix.
2. Findings in the canon record
D1 — The registry records the wrong sheet, and misses half the component
ai-assistant records files and css as only apps/web/src/ds/ai-chat.css. The panel stands on two sheets:
| sheet | lines | .aichat-* selectors |
|---|---|---|
apps/web/src/ds/ai-chat.css | 835 | recorded |
apps/web/src/components/assistant/assistant.css | 352 | 27, none recorded |
The second sheet is not a detail: it carries the panel header (.aichat-head, .aichat-title), the confirmation dialog (.aichat-confirm*, 5 classes), the mail preview (.aichat-mail*, 8 classes), the typing indicator and the recovery notice. An agent in another repo that reads _index.json and pulls the one recorded sheet gets half a panel — which is precisely what the Identity + States review warned about on 5 September 2026. That warning was written down and never reached the registry; this pass makes the correction itself rather than repeating it.
D2 — The class list is both short and wrong
The registry lists 7 classes. Measured in the catalogue, the six stories render 21 .aichat-* classes, of which 17 are not recorded:
.aichat-act .aichat-acts .aichat-body .aichat-bodywrap .aichat-cfoot .aichat-composer
.aichat-hbtn .aichat-head .aichat-mark .aichat-md .aichat-msg .aichat-send .aichat-slash
.aichat-title .aichat-tools .aichat-tools-t .aichat-userAnd in the other direction, 3 of the 7 recorded classes (.aichat-prompt-row, .aichat-run, .aichat-tool) are never drawn by any story — they are real classes in the code, but the catalogue shows nothing of them, so the coverage tick overstates what a reader can actually see. The tool trace in particular only appears collapsed.
Across both sheets the component has 81 distinct .aichat-* selectors. A registry entry is not meant to transcribe all of them, but seven — three of which are invisible in the catalogue — is not a skeleton either.
3. discussion — correctly parked
discussion stays candidate / mockup: nothing in apps/web or packages/ui emits it, so there is nothing to write a story against. That is the honest state, and the registry says so plainly. No action.
4. What was measured
| check | result |
|---|---|
| stories | 6 |
| console / page errors | 0 |
.aichat-* classes rendered by stories | 21 (17 unrecorded) |
| recorded classes never rendered | 3 |
.aichat-* selectors across both sheets | 81 |
| lines of CSS in the unrecorded sheet | 352 |
| mouse-only roots | 1 — and it is A1, not a component defect |
The single mouse-only hit was the empty-state sentence. Chasing why it had a pointer — the CSSOM was asked which rule set it, since grep cannot see specificity — is what turned a one-line curiosity into finding A1.
5. Open for the AD
- A1 — scope the global
.subto the segment screen, and give the six descriptive sites the plain style they actually want. Needs a ruling because it touches a shared sheet and six screens.
D1 and D2 are canon-record corrections and were made in this pass — no ruling needed.
Source: docs/REVIEW-ai-family.md · GitLab