The kit currently declares 6 button sizes, 6 button chromes, 3 modal sizes, 1 loading-spinner size, 1 avatar size, and 5 input chromes. Of 38 enumerated entries, 0 are unreachable from feature code — every public type entry has either live traffic or is documented as a kit-internal primitive. 15 entries were retired on 2026-10-12; the kill / open-question sections below record what was here. UI-063 enforces the new contracted vocabulary.
Done 2026-10-12
14
retired entries — UI-063 enforces the contracted vocabulary
Open questions
3
still pending owner decision
Keep
43
live in feature code or internal primitives
The original kill list as authored 2026-10-12, kept here as a
"what was here" record. The plain row was renamed to
quiet in the same pass (see the Done section below);
the remaining 11 entries are now in the Done section. UI-063 enforces
the contracted vocabulary.
| Kind | Primitive | Name | Used | Sites | Rationale | |
|---|---|---|---|---|---|---|
| ✗ | button size | ButtonSize | icon | no | 0 | Zero call sites; IconButton hardcodes icon-sm; no consumer ever asked for square-only-32px. |
| ✗ | button size | ButtonSize | surface | no | 0 | Original kill entry — retracted. The user's working tree re-added both the type entry and the CSS rule on 2026-10-12 after the kill had been applied. selectable-surface.svelte:29 is the live consumer; surface now lives in ButtonSize alongside the new fit entry. UI-063 enforces the retired values list (icon / resize-row / resize-column / xl / full / xs / sm / md / lg / plain / link / dashed), so surface stays out of the gate's forbidden set. See the Keep table below. |
| ✗ | button size | ButtonSize | resize-row | no | 0 | Zero call sites; reserved for resize-handle CSS that lives elsewhere. |
| ✗ | button size | ButtonSize | resize-column | no | 0 | Zero call sites; same as resize-row. |
| ✗ | modal size | Modal / ModalFrame / WorkspaceModal | full | no | 0 | Zero call sites; declared across Modal, ModalFrame, WorkspaceModal. Drop. |
| ✗ | avatar size | AvatarBubble | md | no | 0 | Declared but never used. Drop. |
| ✗ | avatar size | AvatarBubble | lg | no | 0 | Declared but never used. Drop. |
| ✗ | loading size | LoadingSpinner | xs | no | 0 | Declared but never passed. Drop. |
| ✗ | loading size | LoadingSpinner | sm | no | 0 | Declared but never passed. Drop. |
| ✗ | loading size | LoadingSpinner | md | no | 0 | Declared but never passed. Drop. |
| ✗ | loading size | LoadingSpinner | xl | no | 0 | Declared but never passed. Drop. |
The 14 entries below were retired on 2026-10-12; plain was
renamed to quiet in the same pass to make its no-wash
semantics visible in the type. UI-063
(dead-primitive-variants) enforces the contracted
vocabulary: any size= or chrome= literal on a
kit primitive whose value is in this table is a finding. Two consumer
migrations are noted in the rationale column.
| Kind | Primitive | Name | Was | Now | Migration | |
|---|---|---|---|---|---|---|
| ✓ | button size | ButtonSize | icon | icon |
icon-sm | icon-xs only |
Zero call sites; IconButton hardcodes icon-sm. |
| ✓ | button size | ButtonSize | surface | surface |
sm + padding classes |
disclosure-row.svelte:30 and selectable-surface.svelte:29 rewrote to size="sm" with h-auto p-4 (height-follows-content preserved). |
| ✓ | button size | ButtonSize | resize-row | resize-row |
— | Zero call sites; CSS rule lives in shell.css via ui-resize-handle-row, not via BUTTON_SIZE. |
| ✓ | button size | ButtonSize | resize-column | resize-column |
— | Same as resize-row. |
| ✓ | button chrome | ButtonChrome | plain → quiet | plain |
quiet |
Renamed 2026-10-12 — not killed. The two real ButtonChrome consumers (disclosure-row.svelte:25, selectable-surface.svelte:29) need the no-hover-wash, no-pressed-accent behaviour that plain provided (a hover wash would compete with sibling rows on disclosure rows and override the surrounding card surface on selectable surfaces). Renamed to quiet to make the no-wash semantics explicit in the type. The two chrome="plain" callers on InputBase / TextareaBase (inline-field, composer-field) belong to InputChrome, which stayed live. |
| ✓ | button chrome | ButtonChrome | link | link |
ghost + className |
inline-action.svelte:21 rewrote to chrome="ghost" with h-auto p-0 font-medium hover:underline carried via className. |
| ✓ | button chrome | ButtonChrome | dashed | dashed |
outline |
empty-state-action.svelte:21 rewrote to chrome="outline" (the next-dashed affordance). |
| ✓ | modal size | Modal / ModalFrame / WorkspaceModal | xl | xl |
lg |
path-browser.svelte:702 rewrote to size="lg"; table-designer.svelte:148 (the conditional isDocumentDb ? 'sm' : 'xl') also to 'lg'. Q2 closed: lg, not full. |
| ✓ | modal size | Modal / ModalFrame / WorkspaceModal | full | full |
md |
Zero call sites; workspace-modal.svelte:23 default flipped from 'full' to 'md'. |
| ✓ | avatar size | AvatarBubble | md | md |
sm |
Declared but never used. |
| ✓ | avatar size | AvatarBubble | lg | lg |
sm |
Declared but never used. |
| ✓ | loading size | LoadingSpinner | xs | xs |
lg |
Declared but never passed. |
| ✓ | loading size | LoadingSpinner | sm | sm |
lg |
Declared but never passed. |
| ✓ | loading size | LoadingSpinner | md | md |
lg |
The default. Flipped to lg (the only size passed in practice, 7 sites). |
| ✓ | loading size | LoadingSpinner | xl | xl |
lg |
Declared but never passed. |
Enforced by UI-063 dead-primitive-variants —
scope <ui>/**/*.svelte, severity M. Add a value
to the gate's UI063_SIZE_DEAD / UI063_CHROME_DEAD
sets in providers/svelte_tailwind/analyzer.ts to retire more.
Each question below blocks the disposition of one or more rows in the kill / keep tables above. The answer collapses the row either way — ? means the question is live, not a verdict.
| # | Question | What it affects | Where to look | |
|---|---|---|---|---|
| ? | 1 |
Should DIALOG_INTENT_TO_CHROME.cancel map
to ghost instead of outline?
The current outline mapping is the source of the
Cancel / Install visual mismatch measured earlier — the cancel
and confirm buttons share the same border-box but read as
differently weighted because outline paints a visible border
while primary does not. Mapping cancel → ghost would make the
cancel recede and the primary CTA stand alone.
|
|
apps/web/src/components/common/display/button-chrome.ts:88 ·
DIALOG_INTENT_TO_CHROME table.
|
| ? | 2 |
Does InputChrome.muted survive, fold into
plain, or get killed?
muted paints a transparent-border input with
bg-muted/60. The intended use was filter rows where
the parent card already paints a surface. No direct call sites
found in feature code; could be dead, or could be used by an
internal primitive I missed.
|
|
apps/web/src/components/common/form/input-chrome.ts:7 ·
grep chrome="muted" across apps/web/src.
|
| ? | 3 |
Are plain, link, dashed
chromes kept as @internal escape hatches, or fully
removed?
Resolved 2026-10-12: kill taken. All three dropped
from ButtonChrome. disclosure-row.svelte
rewrote to chrome="ghost";
inline-action.svelte rewrote to chrome="ghost"
+ link-classes via className;
empty-state-action.svelte rewrote to chrome="outline".
The two chrome="plain" callers on input primitives
(inline-field, composer-field) are
InputChrome and stayed live.
|
|
apps/web/src/components/common/form/inline-field.svelte:17 ·
composer-field.svelte:18 ·
display/inline-action.svelte:21 ·
display/empty-state-action.svelte:21.
|
| Kind | Primitive | Name | Used | Sites | Rationale | |
|---|---|---|---|---|---|---|
| ✓ | button size | ButtonSize | sm | yes | 21 | Default for compact buttons; primary traffic in nav / inline actions. |
| ✓ | button size | ButtonSize | md | yes | 26 | Default for modal CTA / settings dialogs. |
| ✓ | button size | ButtonSize | lg | yes | 26 | Default for onboarding / empty states / marketing. |
| ✓ | button size | ButtonSize (internal) | icon-sm | yes (internal) | 2 | IconButton's only size; hardcoded inside the primitive. Keep type entry as internal-only. |
| ✓ | button size | ButtonSize (internal) | icon-xs | yes (internal) | 0 | BannerAction.iconOnly hardcodes icon-xs (12 BannerAction sites, ~half iconOnly). Live and load-bearing; just unreachable from outside. |
| ✓ | button size | ButtonSize (internal) | surface | yes (internal) | 1 | SelectableSurface's card-density size (p-4 rounded-lg, height-follows-content). Retracted from the 2026-10-12 kill — the type entry and CSS rule were re-added in the same pass as the new fit size. UI-063 leaves surface off its forbidden list because it is live. |
| ✓ | button size | ButtonSize (internal) | fit | yes (internal) | 1 | DisclosureRow's height-follows-content size (px-3.5 py-3, never h-*). Added 2026-10-12 alongside the surface retention. ui-action-size-fit CSS rule lives in shared.css; UI-063 enforces fit lives behind DisclosureRow. |
| ✓ | button chrome | ButtonChrome | primary | yes | 83 | Primary CTA chrome; carries the affirmative action tone. |
| ✓ | button chrome | ButtonChrome | danger | yes | 29 | Destructive intent; solid destructive fill. |
| ✓ | button chrome | ButtonChrome (internal) | danger-outline | yes (internal) | 0 | ICON_INTENT_TO_CHROME.danger → danger-outline; used by IconButton intent=danger. Keep as internal chrome. |
| ✓ | button chrome | ButtonChrome | outline | yes | 274 | Secondary intent chrome; outline with hover fill. The modal-back / cancel / secondary traffic. |
| ✓ | button chrome | ButtonChrome (internal) | ghost | yes (internal) | 5 | Used by MenuItem / ToolbarAction / BannerAction internally. Never directly addressed from feature code; keep as internal chrome. |
| ✓ | button chrome | ButtonChrome (internal) | quiet | yes (internal) | 2 | DisclosureRow + SelectableSurface. No chrome, no hover wash, no pressed accent — caller paints the visual contract (p-4, gap, border, surface role) via className. Renamed from plain 2026-10-12. |
| ✓ | button chrome | ButtonChrome | overlay | yes (internal) | 1 | Transparent / pointer-events only. One site — modal scrim. Keep as escape hatch. |
| ✓ | button intent | INTENT_TO_CHROME | primary | yes | 83 | Primary intent; maps to primary chrome. |
| ✓ | button intent | INTENT_TO_CHROME | secondary | yes | 274 | Secondary intent; maps to outline chrome. |
| ✓ | button intent | INTENT_TO_CHROME | danger | yes | 29 | Danger intent; maps to danger chrome. |
| ✓ | button intent | ICON_INTENT_TO_CHROME | primary | yes | ? | IconButton primary intent. |
| ✓ | button intent | ICON_INTENT_TO_CHROME | secondary | yes | ? | IconButton secondary → ghost. |
| ✓ | button intent | ICON_INTENT_TO_CHROME | danger | yes | ? | IconButton danger → danger-outline. |
| ✓ | button intent | DIALOG_INTENT_TO_CHROME | confirm | yes | ? | DialogAction confirm → primary. |
| ✓ | button intent | DIALOG_INTENT_TO_CHROME | cancel | yes | ? | DialogAction cancel → outline. See open question §1. |
| ✓ | button intent | DIALOG_INTENT_TO_CHROME | danger | yes | ? | DialogAction danger → danger. |
| ✓ | modal size | Modal / ModalFrame / WorkspaceModal | sm | yes | 7 | Delete / disable confirms; tight confirm dialogs. |
| ✓ | modal size | Modal / ModalFrame / WorkspaceModal | md | yes | 14 | Default size; most settings dialogs. |
| ✓ | modal size | Modal / ModalFrame / WorkspaceModal | lg | yes | 13 | Complex settings dialogs; default for skills / profiles / MCP. |
| ✓ | avatar size | AvatarBubble | sm | yes | 5 | Default in 5 sites (history, settings). |
| ✓ | loading size | LoadingSpinner | lg | yes | 7 | Only size passed in practice. |
| ✓ | brand mark size | BrandMark | sm | yes | 2 | Small inline use (history row). |
| ✓ | brand mark size | BrandMark | md | yes | 2 | Medium list-row. |
| ✓ | brand mark size | BrandMark | lg | yes | 3 | Settings panel header. |
| ✓ | brand mark size | BrandMark | xl | yes | 3 | Large hero (login). |
| ✓ | input chrome | InputChrome | default | yes | ? | Input / InlineField / Textarea default. |
| ✓ | input chrome | InputChrome | plain | yes | ? | InlineField / SearchField chrome. |
| ✓ | input chrome | InputChrome | search | yes | ? | SearchField chrome. |
| ✓ | input chrome | InputChrome | danger | yes | ? | Error state chrome; auto-applied by <Input invalid={true}>. |
| ✓ | input size | InputSize | sm | yes | ? | Compact field row (InlineField / SearchField / ComposerField default). |
| ✓ | input size | InputSize | md | yes | ? | Standard form row (Input / Select / Textarea default). |
| ✓ | checkbox | Checkbox / CheckboxBase | — | yes | — | Single visual; no size or chrome variants. |
| ✓ | switch | Switch / SwitchBase | — | yes | — | Single visual; no size or chrome variants. |
| ✓ | radio | RadioChoice / RadioChoiceBase | — | yes | — | Single visual; no size or chrome variants. |
| ✓ | slider | Slider / SliderBase | — | yes | — | Single visual; no size or chrome variants. |
| ✓ | color field | ColorField / ColorFieldBase | — | yes | — | Single visual; no size or chrome variants. |
| ✓ | anchored overlay | AnchoredOverlay | — | yes | 52 | Placement / align / layer only; no size dimension. |
| ✓ | toast / alert | NotificationToast / AlertBar | — | yes | ? | No size variation; intent-driven fill. |
| ✓ | banner | BannerAction | — | yes | 12 | Chrome = ghost + currentColor hover; size = sm or icon-xs. |
| ✓ | card primitive | ChoiceControl | — | yes | ? | Inline content row; size defaults to sm/md based on layout. |
| ✓ | card primitive | SelectableSurface | — | yes | ? | Toggleable selection row; no size prop. |