@felloinnovations/brand-kit 0.5.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/AGENTS.md +29 -9
  2. package/CHANGELOG.md +110 -0
  3. package/README.md +14 -6
  4. package/design-system/01-how-claude-decides.md +5 -3
  5. package/design-system/03-colour.md +22 -3
  6. package/design-system/05-space-and-layout.md +2 -1
  7. package/design-system/08-choosing-components.md +20 -4
  8. package/design-system/09-charts.md +7 -4
  9. package/design-system/10-patterns.md +1 -1
  10. package/design-system/11-page-recipes.md +40 -1
  11. package/design-system/13-motion.md +4 -4
  12. package/design-system/15-ai-experiences.md +11 -0
  13. package/design-system/17-decisions.md +51 -0
  14. package/design-system/components/AppShell/README.md +89 -21
  15. package/design-system/components/AppShell/preview.html +148 -3
  16. package/design-system/components/AppShell/style.css +47 -0
  17. package/design-system/components/Avatar/README.md +6 -3
  18. package/design-system/components/Avatar/preview.html +2 -1
  19. package/design-system/components/Avatar/style.css +3 -0
  20. package/design-system/components/Banner/README.md +9 -5
  21. package/design-system/components/Banner/preview.html +9 -0
  22. package/design-system/components/Banner/style.css +3 -0
  23. package/design-system/components/Button/README.md +29 -2
  24. package/design-system/components/Button/preview.html +33 -1
  25. package/design-system/components/Button/style.css +21 -0
  26. package/design-system/components/Calendar/README.md +148 -0
  27. package/design-system/components/Calendar/preview.html +449 -0
  28. package/design-system/components/Calendar/style.css +61 -0
  29. package/design-system/components/Card/README.md +13 -0
  30. package/design-system/components/Card/preview.html +23 -0
  31. package/design-system/components/Card/style.css +19 -0
  32. package/design-system/components/ChatCard/README.md +74 -3
  33. package/design-system/components/ChatCard/preview.html +126 -25
  34. package/design-system/components/ChatCard/style.css +6 -0
  35. package/design-system/components/CheckRow/README.md +1 -1
  36. package/design-system/components/CheckRow/preview.html +1 -1
  37. package/design-system/components/CheckRow/style.css +1 -1
  38. package/design-system/components/Chip/README.md +16 -7
  39. package/design-system/components/Chip/preview.html +25 -1
  40. package/design-system/components/Chip/style.css +5 -0
  41. package/design-system/components/Combobox/README.md +10 -4
  42. package/design-system/components/Combobox/preview.html +19 -4
  43. package/design-system/components/Combobox/style.css +7 -1
  44. package/design-system/components/CommentThread/README.md +138 -0
  45. package/design-system/components/CommentThread/preview.html +134 -0
  46. package/design-system/components/CommentThread/style.css +41 -0
  47. package/design-system/components/DateInput/README.md +38 -4
  48. package/design-system/components/DateInput/preview.html +50 -2
  49. package/design-system/components/DateInput/style.css +6 -0
  50. package/design-system/components/Dialog/README.md +26 -3
  51. package/design-system/components/Dialog/preview.html +80 -0
  52. package/design-system/components/Dialog/style.css +28 -3
  53. package/design-system/components/EmptyState/README.md +1 -1
  54. package/design-system/components/Fold/README.md +21 -0
  55. package/design-system/components/Fold/preview.html +44 -1
  56. package/design-system/components/Fold/style.css +30 -0
  57. package/design-system/components/InlineEdit/README.md +116 -0
  58. package/design-system/components/InlineEdit/preview.html +135 -0
  59. package/design-system/components/InlineEdit/style.css +34 -0
  60. package/design-system/components/Input/README.md +20 -1
  61. package/design-system/components/Input/preview.html +24 -0
  62. package/design-system/components/Input/style.css +13 -1
  63. package/design-system/components/KanbanBoard/README.md +69 -5
  64. package/design-system/components/KanbanBoard/preview.html +129 -0
  65. package/design-system/components/KanbanBoard/style.css +32 -1
  66. package/design-system/components/ListDetail/preview.html +1 -1
  67. package/design-system/components/Matrix/README.md +1 -1
  68. package/design-system/components/Matrix/preview.html +1 -1
  69. package/design-system/components/Motion/README.md +2 -2
  70. package/design-system/components/Motion/preview.html +8 -8
  71. package/design-system/components/PlanTimeline/README.md +144 -0
  72. package/design-system/components/PlanTimeline/preview.html +109 -0
  73. package/design-system/components/PlanTimeline/style.css +64 -0
  74. package/design-system/components/README.md +12 -7
  75. package/design-system/components/ScoreHero/README.md +2 -2
  76. package/design-system/components/ScoreHero/style.css +1 -1
  77. package/design-system/components/ShareBar/README.md +1 -1
  78. package/design-system/components/ShareBar/style.css +1 -1
  79. package/design-system/components/Skeleton/README.md +82 -17
  80. package/design-system/components/Skeleton/preview.html +84 -2
  81. package/design-system/components/Skeleton/style.css +9 -14
  82. package/design-system/components/Starter/README.md +1 -1
  83. package/design-system/components/Starter/preview.html +1 -1
  84. package/design-system/components/Stepper/README.md +81 -5
  85. package/design-system/components/Stepper/preview.html +64 -1
  86. package/design-system/components/Stepper/style.css +29 -0
  87. package/design-system/components/StreakCalendar/README.md +1 -0
  88. package/design-system/components/Table/README.md +8 -4
  89. package/design-system/components/Table/preview.html +16 -1
  90. package/design-system/components/Table/style.css +3 -1
  91. package/design-system/components/TextDiff/README.md +96 -0
  92. package/design-system/components/TextDiff/preview.html +42 -0
  93. package/design-system/components/TextDiff/style.css +21 -0
  94. package/design-system/components/TickStrip/README.md +1 -1
  95. package/design-system/components/TickStrip/preview.html +1 -1
  96. package/design-system/components/TickStrip/style.css +1 -1
  97. package/design-system/components/Timeline/README.md +4 -2
  98. package/design-system/components/TrendLine/README.md +38 -7
  99. package/design-system/components/TrendLine/preview.html +140 -3
  100. package/design-system/components/TrendLine/style.css +12 -2
  101. package/design-system/components/Well/README.md +1 -1
  102. package/design-system/components/Well/style.css +2 -2
  103. package/design-system/components/_house.css +1 -1
  104. package/design-system/components/bundle.css +501 -30
  105. package/design-system/tokens.json +17 -7
  106. package/dist/fello-core.css +2 -2
  107. package/dist/fello.css +2 -2
  108. package/dist/fello.scoped.css +2 -2
  109. package/dist/index.d.ts +1 -1
  110. package/dist/scoped.js +2 -2
  111. package/dist/tokens.d.ts +16 -8
  112. package/dist/tokens.js +16 -8
  113. package/package.json +7 -2
  114. package/scripts/check-drift.mjs +325 -0
  115. package/scripts/token-model.mjs +2 -1
  116. package/tokens/_dark.css +3 -2
  117. package/tokens/_product.css +13 -11
  118. package/tokens/palettes.ts +1 -1
  119. package/tokens/shadcn-compat.css +1 -1
  120. package/tokens/shadcn-compat.hsl.css +1 -1
  121. package/tokens/tokens.css +23 -15
  122. package/tokens/tokens.md +56 -50
  123. package/tokens/tokens.root.css +23 -15
  124. package/tokens/tokens.ts +17 -9
package/AGENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- # brand-kit for coding agents (0.5.0)
1
+ # brand-kit for coding agents (0.5.3)
2
2
 
3
3
  Read this before writing UI in any Fello project that uses `@felloinnovations/brand-kit`. It ships inside the
4
4
  package at `node_modules/@felloinnovations/brand-kit/AGENTS.md`. The HubSpot website (felix-theme) is out of scope:
@@ -22,9 +22,10 @@ All paths are under `node_modules/@felloinnovations/brand-kit/`.
22
22
  | `dist/fello.scoped.css` | The whole kit under a `.fello` root, for an app inside a host it does not own. |
23
23
  | `tokens/tokens.css` | Tokens only, as a Tailwind v4 `@theme`. |
24
24
  | `scripts/check-palette.mjs` | Checks an app's own palette file against the contract (Palettes, below). |
25
+ | `scripts/check-drift.mjs` | Lists every line of an app's source that drifted from the kit, by file and line; with a baseline, fails CI only on new drift (Checking it, below). Also `npx brand-kit-drift`. |
25
26
 
26
27
  The same guide is hosted, always current, at `https://brand-kit-site-production.up.railway.app/latest/llms.txt`
27
- (pinned copies under `/v/0.5.0/`).
28
+ (pinned copies under `/v/0.5.3/`).
28
29
 
29
30
  ---
30
31
 
@@ -170,10 +171,12 @@ public web page, email, deck, mockup). The face sets one of two layers, never mi
170
171
  already shipped a bug. Never `--radius-xl` or `--radius-2xl` for a product corner: those are Tailwind's.
171
172
  - **Semantic tokens over primitives**: `var(--color-text-heading)`, not `var(--color-brand-navy)`, for the same job.
172
173
  The semantic layer is what lets a colour be retuned, and what turns in dark.
173
- - **Check the catalog before building a component.** Never redraw one. If the kit has nothing for it, build it in
174
- the consuming app from tokens and say what was missing, as an issue
175
- (`https://github.com/FelloInnovations/brand-kit/issues/new?template=feedback.yml`). Do not add it to brand-kit and do not open a PR against it
176
- from a consuming app; the kit's owners take it from there.
174
+ - **Check the catalog before building a component. Never build a new one in an app** (Nikhil and Amit, 10 Nov
175
+ 2026: built once in the kit, everyone uses it and raises what is missing). If the kit has nothing for it, compose
176
+ the nearest catalog parts (a `Card` with its band, a `Menu`, a `Table`, a recipe), file the gap as an issue
177
+ (`brand-feedback`, or `https://github.com/FelloInnovations/brand-kit/issues/new?template=feedback.yml`) and say in
178
+ the PR which issue the screen waits on. When the kit ships it, `brand-catchup` swaps it in. Do not add it to
179
+ brand-kit and do not open a PR against it from a consuming app; the kit's owners take it from there.
177
180
  - **Close but not exact**: pass `className` to a React export (merged through `tailwind-merge`, so your utility wins).
178
181
  Do not fork it.
179
182
  - **Layout**: one content edge per surface; numbers in fixed right-aligned columns; rows in a list share one
@@ -238,8 +241,22 @@ fold, enter and exit is already there. The situations, with markup, are in `desi
238
241
 
239
242
  ## Checking it
240
243
 
241
- The kit's own checks run in the kit's repo, for anyone changing a catalog component (only `check-palette.mjs` ships in
242
- the package; the rest show what "done" means for your own screens too):
244
+ **In an app**, the drift check reads every file of its source and lists what drifted (raw colours, each marked
245
+ against the nearest token, kit tokens redefined, kit classes restyled, px type, raw radii and shadows, hand-rolled
246
+ motion, links underlined at rest, em dashes, local copies of kit components). Run it before calling UI done, and keep
247
+ it in CI with a baseline so nothing new gets in while old drift is fixed:
248
+
249
+ ```sh
250
+ node node_modules/@felloinnovations/brand-kit/scripts/check-drift.mjs src # the report; exit 1 on any drift
251
+ node node_modules/@felloinnovations/brand-kit/scripts/check-drift.mjs src --write-baseline .brand-drift.json
252
+ node node_modules/@felloinnovations/brand-kit/scripts/check-drift.mjs src --baseline .brand-drift.json # CI: fails only on new drift
253
+ ```
254
+
255
+ A line that is right as it is carries `brand-kit-ignore: <why>` on it or the line above. Updating to a newer kit is
256
+ the `brand-catchup` skill (only what the releases changed), never `brand-adopt` again.
257
+
258
+ The kit's own checks run in the kit's repo, for anyone changing a catalog component (only `check-palette.mjs` and
259
+ `check-drift.mjs` ship in the package; the rest show what "done" means for your own screens too):
243
260
 
244
261
  ```sh
245
262
  node scripts/check-geometry.mjs --only Name1,Name2 --widths 320,390,1440 # alignment, spacing, centring, clipping, targets
@@ -249,6 +266,7 @@ node scripts/check-geometry.mjs --only Name1,Name2 --hover # res
249
266
  node scripts/check-geometry.mjs --only Name1,Name2 --hover --motion # the same with motion on: a lift that only plays then
250
267
  node scripts/check-scope.mjs # the scoped build leaks nothing; fello.css resets miss the host
251
268
  node scripts/check-palette.mjs [file.css] # the built-ins, or a palette file, against the contract
269
+ node scripts/check-drift.mjs --selftest # the drift check catches every planted drift
252
270
  ```
253
271
 
254
272
  Open every screenshot the geometry check writes. In an app, run the same eye over the screen at 320, 390 and 1440,
@@ -282,5 +300,7 @@ size, radius, shadow or duration. Motion comes with the catalog's classes (`desi
282
300
  hand-roll a transition. Check the catalog (`design-system/components/`) before building a component. Write
283
301
  `text-[color:var(--x)]`, never `text-[var(--x)]`. Dark is opt-in (`data-theme`). This app's own colours are a palette
284
302
  (`data-palette`, `design-system/20-palettes.md`), checked with `scripts/check-palette.mjs` and shipped as its
285
- `--emit` writes it, never tokens retuned on `:root`. Run `design-system/18-checklist.md` before calling UI done.
303
+ `--emit` writes it, never tokens retuned on `:root`. Run `design-system/18-checklist.md` and
304
+ `node node_modules/@felloinnovations/brand-kit/scripts/check-drift.mjs src --baseline .brand-drift.json` before calling
305
+ UI done. To take a newer kit, use the `brand-catchup` skill, not `brand-adopt`.
286
306
  ```
package/CHANGELOG.md CHANGED
@@ -1,5 +1,115 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.3 (11 Nov 2026)
4
+
5
+ Madan's eighteen gaps from moving Marketing OS onto the kit (#15 to #32), and Hemanth's sidebar. Nikhil (10 Nov):
6
+ Marketing OS shows the new UI to Stephen before Thursday, and apps never build a missing component with Claude, so the
7
+ kit carries each of these. Everything adds; nothing that exists changes how it looks. Rulings in Decisions, 11 Nov 2026.
8
+
9
+ - **New components**: `Calendar` (things on dates in a month or a week, an agenda in a narrow column; #23),
10
+ `PlanTimeline` (a plan's phases and tasks as bars on one date scale, today one line through every row; #24),
11
+ `InlineEdit` (words that become a field in place, nothing jumps; #25), `CommentThread` (remarks anchored to content,
12
+ one level of replies, mentions, resolve; #26), `TextDiff` (what was removed and what was added, by line or inline,
13
+ never by colour alone; #28).
14
+ - **`AppShell`'s sidebar holds sections**: `__section` folds a page's own pages open in place, one level in, its
15
+ chevron turning; folded, a section is a button that opens its pages as a Menu panel beside the rail (`__fly`,
16
+ `__panel`); the person at the foot opens the account menu (`__me`). Enough for Customer Value to drop its own rail.
17
+ - **Fields**: `DateInput` jumps to a far month or year (`__jump`) and has Today and Clear in a foot (`__foot`; #20), and
18
+ takes a time and a date with a time on the browser's own picker (#27); `Combobox` ticks the chosen row and keeps the
19
+ sunk ground for the keyboard's (#19); `ws-colour-field`, a swatch beside its hex, in `Input` (#29).
20
+ - **Acts and tags**: `ws-btn-join` joins an act to a caret that opens a menu of its other forms (#22); `Chip --sm` (20
21
+ tall, 12 px words) for several tags together (#30); `Avatar --xs` (20) for dense pickers (#16).
22
+ - **Surfaces**: `ws-dialog--mounted` with `ws-dialog__scrim`, so a dialog Radix mounts enters and leaves like the
23
+ native one, out on `data-state="closed"` (#18); `Fold` gains acts beside the summary, an end status, words shown only
24
+ while folded (`ws-fold__peek`) and three tones (#31); `ws-card__media` rounds its own corners and `ws-card--ring`
25
+ with `ws-card__tick` marks a chosen tile in a grid (#32); `ws-table__prose` wraps a short prose cell with no 200 px
26
+ floor (#21). A button card no longer carries the browser's default button padding.
27
+ - **Status colours and two tokens**: error, warning, success and info map onto the kit's alert, needs, positive and
28
+ working tones (the "Status sets" table in Colour; #15). New `--ws-tint-alert` (the ground of an error status, with
29
+ `Banner --alert` and `Chip --alert`) and `--ws-shadow-rise` (a drawer rising from a pane; #17), both following every
30
+ palette, light, night and navy.
31
+ - **Pinned links keep working**: `/v/0.5.2/` is kept as a snapshot (`hosted/v/0.5.2`). Pinned links now point at
32
+ `/v/0.5.3/`.
33
+
34
+ **Upgrading from 0.5.2**: nothing to change; take it with `brand-catchup`. Then, on a yes, swap what the app hand-built:
35
+ a calendar, a Gantt, an editable title, a comment list, a diff, a split button, a nested sidebar or a dialog's own
36
+ animation for the kit's; a local warning or info colour for the status sets; a button card's padding reset can go.
37
+
38
+ ## 0.5.2 (10 Nov 2026)
39
+
40
+ What Hemanth was missing when he built the Customer Value app on the kit (10 Nov call with Amit). Everything here adds;
41
+ nothing that exists changes how it looks (the look stays locked at 0.5). Rulings in Decisions, 10 Nov 2026.
42
+
43
+ - **Update with `brand-catchup`, never a second adopt.** A new skill brings an app already on the kit up to the newest
44
+ release: it reads this changelog from the app's version to the latest, bumps the package (or re-fetches a guest app's
45
+ vendored scoped CSS), applies each release's "Upgrading from" notes and nothing else, lists where the app hand-built
46
+ something the kit now has (and swaps it only on a yes), and proves nothing new drifted.
47
+ - **`check-drift` lists every drifted line, so adopt stops stopping halfway.** `scripts/check-drift.mjs` ships in the
48
+ package (also `npx brand-kit-drift`): raw colours (each marked as matching a token, close to one, or no token),
49
+ Tailwind palette classes, kit tokens redefined, kit classes restyled, px type, raw radii and shadows, the
50
+ `text-[var(--x)]` trap, hand-rolled motion and hover lifts, links underlined at rest, em dashes in markup and local
51
+ copies of kit components, every one by file and line. `--baseline .brand-drift.json` makes it a CI check that fails
52
+ only on new drift; `brand-kit-ignore: <why>` keeps a line that is right; `--selftest` proves each rule. `brand-adopt`
53
+ is done only when it finds nothing left (or names every leftover), then leaves the baseline in CI; `brand-audit`'s
54
+ static half runs it first.
55
+ - **A whole page's loader.** `Skeleton` documents the page ghost it promised: the page's own `PageBar` with its name
56
+ shown at once and its data-bound words and act as ghosts, then a board of tile and card skeletons where the real
57
+ ones land, so nothing jumps. No new CSS. List and board pages use `Table`'s and `KanbanBoard`'s own ghosts.
58
+ - **`TrendLine` draws up to three series** in one unit on one axis: a `__series` box per extra line, navy, teal then
59
+ purple, a key (`__key--2`, `__key--3`), a column per series in the table, and a hover that reads every series for
60
+ the period. Several series are lines only. Different units, or one series more than four times another: two
61
+ TrendLines stacked in one card on the same periods, never two value axes.
62
+ - **`Stepper` reads across and holds milestones.** `--across` lays a thing's stages left to right in equal columns, the
63
+ in-hand stage opening in view on a track that scrolls on a phone; `--milestones` puts dated points on one row with
64
+ the measure on each ("First value 15 days") and one quiet act on one not yet reached; `__late` says a stall or a late
65
+ milestone in needs-you words ("Stalled 40 days").
66
+ - **One card for every board.** `KanbanBoard` documents the standard card (`ws-kanban-board__card`): the kind and its
67
+ figure with the time in stage (`__age`, `--stalled`), the title as the card's link covering it, meta, up to three
68
+ chips, a foot with people, a tally and one icon act, and one well act (`__card-act`) when the stage waits on the
69
+ person. Ticket and onboarding examples in the preview; a card-tall ghost for loading.
70
+ - **Calvin's desk.** `ChatCard` gains four kinds: Email, Call and Text (the time at the head's right, the sender's words
71
+ quoted on a sunk plate, three lines at most; Reply, or Listen for a call) and Account (its standing as a rating chip,
72
+ its numbers on the stats plate, one navy act). Page recipe 25, "An agent desk: one thread per account", composes the
73
+ threads by account, the open thread, the daily briefing on top and the layouts at 1440 and 390 from catalog parts.
74
+ - `check-geometry` counts a title whose cover spans its card as the card's target.
75
+ - **Next.js imports `fello.css` from the root layout** (`brand-adopt`, `brand-new`): under Turbopack an `@import` in
76
+ `globals.css` put its font `@import` after rules and `next dev` failed on every page (#14).
77
+ - **Apps never build a missing component** (Nikhil and Amit, 10 Nov): compose the nearest catalog parts, file the gap
78
+ with `brand-feedback`, name the issue in the PR; the kit builds it once and `brand-catchup` swaps it in. AGENTS.md,
79
+ How Claude decides and `brand-feedback` say so.
80
+ - **Pinned links keep working**: `/v/0.5.1/` is kept as a snapshot (`hosted/v/0.5.1`). Pinned links in the docs now
81
+ point at `/v/0.5.2/`.
82
+
83
+ **Upgrading from 0.5.1**: nothing to change; take it with `brand-catchup`. Then, in an app that hand-built any of these,
84
+ swap on a yes: a page loader made of divs for the page ghost (`Skeleton`); a second chart line drawn in its own SVG for
85
+ `TrendLine`'s `__series`; a horizontal stage track or milestone row for `Stepper --across` or `--milestones`; a board
86
+ card per board (column rails, stage hues, underlined titles) for `ws-kanban-board__card`; email, call or text bubbles
87
+ in a chat for the `ChatCard` message kinds. Add `check-drift` to CI with a baseline (`brand-adopt`, stage 8).
88
+
89
+ ## 0.5.1 (10 Nov 2026)
90
+
91
+ Loaders are calm: the shimmer is one quiet grey. Amit looked at the skeletons in an app built on the kit and did not
92
+ like the salmon, purple and green tints sweeping every grey ghost block (Decisions, 10 Nov 2026).
93
+
94
+ - **The shimmer is one neutral tone.** `--ws-shimmer` is the ghost grey with a lighter pass of the same grey, no chart
95
+ hues, in light, night, the navy ground and every palette. North's timing stays: 1.8 s on `--ws-loop-shimmer` and
96
+ `--ws-ease-shimmer`, the 300 % band at 100 deg; still under reduced motion. Every ghost that wears the shimmer
97
+ (Skeleton, a pending Stat, StatTiles, Table, Well, TickStrip, ShareBar, ScoreHero and the rest) changes with no
98
+ markup change.
99
+ - **One ghost grey at rest and in motion.** `--ws-shimmer-ground` is now `--ws-ghost` (#E3DFDB, the night's #273544),
100
+ so a ghost shows on the cream (1.29:1) and on the tray (1.13:1) alike, and the still ghost under reduced motion is the
101
+ same grey. Skeleton's own ground for a card's foot or band is gone.
102
+ - **The chart ghost's colour band is gone.** `ws-skeleton__chart`'s bars are ghosts under the same shimmer; the band
103
+ that crossed the drawing in blend mode colour is removed (a neutral band there would paint nothing).
104
+ - **The docs say so**: the Skeleton card and preview, the Motion card (the shimmer row is now Close, the chart band row
105
+ Not yet), Colour, Motion, Patterns, Charts, Choosing components and every loading line in the catalog.
106
+ - **Pinned links keep working**: `/v/0.5.0/` is kept as a snapshot (`hosted/v/0.5.0`), so a page pinned to it still
107
+ loads after the bump. Pinned links in the docs now point at `/v/0.5.1/`.
108
+
109
+ **Upgrading from 0.5.0**: nothing to change. A copy of the old gradient, or of #ECE8E4 as the shimmer's grey, should
110
+ become `var(--ws-shimmer)` or `var(--ws-shimmer-ground)`. `StatusLine`'s working words keep their colours for now (open
111
+ in Decisions).
112
+
3
113
  ## 0.5.0 (4 Nov 2026)
4
114
 
5
115
  The kit the whole team can trust: teams kept hitting alignment, spacing and placement bugs, and Seth (the designer) has
package/README.md CHANGED
@@ -59,11 +59,17 @@ The plugin carries the same `fello-brand-kit` skill as claude.ai, plus four comm
59
59
  | Command | What it does |
60
60
  | --- | --- |
61
61
  | `/brand-kit:brand-audit` | Read-only report: raw values, drift from tokens, pages that cannot scroll, fields with no white ground, small targets, contrast, console errors. |
62
- | `/brand-kit:brand-adopt` | Migrates an existing app onto the kit, in stages, building between each. |
62
+ | `/brand-kit:brand-adopt` | Migrates an existing app onto the kit, in stages, until the drift check finds nothing left, then guards it in CI. |
63
+ | `/brand-kit:brand-catchup` | Brings an app already on the kit up to the newest release: only what the releases changed, never a second adopt. |
63
64
  | `/brand-kit:brand-new` | Scaffolds a new app already on the kit. |
64
65
  | `/brand-kit:brand-feedback` | Sends what the kit was missing or got wrong as one issue per gap on this repo. The other skills offer it when they finish. |
65
66
 
66
- Audit before adopt, so someone who does not read code sees what is wrong before anything is rewritten.
67
+ Audit before adopt, so someone who does not read code sees what is wrong before anything is rewritten. Adopt once;
68
+ after that, catch up.
69
+
70
+ `npx brand-kit-drift src` (or `node node_modules/@felloinnovations/brand-kit/scripts/check-drift.mjs src`) lists every
71
+ line of an app that drifted from the kit; `--baseline .brand-drift.json` makes it a CI check that fails only on new
72
+ drift.
67
73
 
68
74
  ### In code
69
75
 
@@ -112,7 +118,7 @@ Then point the repo's agents at the guide: paste the block at the end of [AGENTS
112
118
  One line, pinned to a version:
113
119
 
114
120
  ```html
115
- <link rel="stylesheet" href="https://brand-kit-site-production.up.railway.app/v/0.5.0/fello.css">
121
+ <link rel="stylesheet" href="https://brand-kit-site-production.up.railway.app/v/0.5.3/fello.css">
116
122
  ```
117
123
 
118
124
  Then use the `ws-*` classes and `var(--token)`; the markup for each component is in the gallery. `/latest/` exists
@@ -183,11 +189,13 @@ is no longer maintained. Only the kit's owners (Amit and Arpan) change tokens.
183
189
 
184
190
  ## Releasing
185
191
 
186
- CI publishes. Bump `version` in `package.json` (and `plugin/.claude-plugin/plugin.json`, and the pinned `/v/` links
187
- in `skill/SKILL.md`), run `yarn build` and `yarn skill`, commit, then push a tag that matches:
192
+ CI publishes. Before the bump, keep the released hosted tree: `yarn hosted`, then copy `site-dist/v/<released
193
+ version>` to `hosted/v/` (the gallery serves every snapshot there, so pinned links keep working). Bump `version` in
194
+ `package.json` and the pinned `/v/` links (`AGENTS.md`, `skill/SKILL.md`, this README, `Starter`, guide 01; the plugin is
195
+ unversioned), run `yarn build` and `yarn skill`, commit, then push a tag that matches:
188
196
 
189
197
  ```sh
190
- git tag v0.5.0 && git push origin v0.5.0
198
+ git tag v0.5.3 && git push origin v0.5.3
191
199
  ```
192
200
 
193
201
  `.github/workflows/publish.yml` checks the tag matches `package.json`, builds, and publishes to npm through npm's
@@ -57,7 +57,7 @@ rest; a mockup about to ship takes all steps.
57
57
  | Where | Setup |
58
58
  | --- | --- |
59
59
  | A claude.ai artifact | inline `fello-core.css` plus the styles of only the components used, in one `<style>` (an artifact loads stylesheets only from Google Fonts; the whole `fello.css` is too big to paste) |
60
- | A plain HTML page or a static site | link the pinned file: `https://brand-kit-site-production.up.railway.app/v/0.5.0/fello.css` |
60
+ | A plain HTML page or a static site | link the pinned file: `https://brand-kit-site-production.up.railway.app/v/0.5.3/fello.css` |
61
61
  | A Next, Vite or Turbo app that owns its page | install `@felloinnovations/brand-kit`, import `fello.css` (it sits in Tailwind's layers, so utilities win) or `tokens.css` (Tailwind v4), with the Instrument Sans `@import` first (before `@import "tailwindcss"`) or a `<link>`; read its `AGENTS.md` |
62
62
  | An app inside a host it does not own (a shared bundle, a platform's guest app), or any Tailwind v3 app | the scoped build: `fello.scoped.css`, or the string from `@felloinnovations/brand-kit/scoped` injected in a `<style>`, under `class="fello"` on the app's root and on every portal's root; nothing outside it changes; it carries no font, so link Instrument Sans (the `brand-adopt` skill has the steps) |
63
63
  | Claude Design or Slides | this system is the organisation's default; nothing to load |
@@ -108,8 +108,10 @@ Choose the recipe first and adapt it (Page recipes); then the pattern (Patterns)
108
108
  and any chart (Charts). Do not invent a new surface; marketing and product pieces never cross faces.
109
109
 
110
110
  **When no product has a precedent**, decide it from the system (its principles, tokens, the nearest rule) rather than
111
- leave it out. A switch is navy when on because the tab thumb and a selected toggle are. A new component is built from tokens in the consuming project and listed in
112
- Decisions with the rules it derives from, so the kit's owners can take it.
111
+ leave it out. A switch is navy when on because the tab thumb and a selected toggle are. **A missing component is never
112
+ built in the app** (Nikhil and Amit, 10 Nov 2026): compose the nearest catalog parts in its place, file the gap
113
+ (`brand-feedback`) with the rules it would derive from, and name the issue in the PR. The kit's owners build it once,
114
+ in the kit, and `brand-catchup` swaps it in.
113
115
 
114
116
  ## 5. Apply the foundations
115
117
 
@@ -35,12 +35,12 @@ positive. Marks keep Seth's exact tones; a word in a tone takes its AA step on t
35
35
  | Under halfway marks, needs-you dots | `ws-chart-under-half`, `color-brand-salmon` | salmon #FF725C |
36
36
  | Needs work marks | `ws-chart-needs-work` | pink #F370A4 |
37
37
  | Alert marks | `ws-chart-alert` | #B1042F |
38
- | Chip tints: needs you, done, needs work | `ws-tint-needs`, `ws-tint-live`, `ws-tint-needs-work` | |
38
+ | Chip and banner tints: needs you, done, needs work, alert | `ws-tint-needs`, `ws-tint-live`, `ws-tint-needs-work`, `ws-tint-alert` | |
39
39
  | Hover washes (navy at .03, .05, .06) | `ws-hover-faint`, `ws-hover`, `ws-hover-strong` | |
40
40
  | The ink of a wash, a ring or a line of your own; the tint of a drop | `ws-ink`, `ws-shade` | navy (in dark, the heading's light ink and black) |
41
41
  | A floating navy message (a toast, the note tip) and the footer, and their words | `ws-inverse`, `ws-on-inverse` | the act and its words; in dark the brand navy and white |
42
42
  | An off control (a switch's track at rest) | `ws-control-off` | #7F7F7F |
43
- | The loading shimmer's ground | `ws-shimmer-ground` | #ECE8E4 |
43
+ | The loading shimmer's ground: the ghost grey, with a lighter pass of the same grey (never a chart hue) | `ws-shimmer-ground` | #E3DFDB (`ws-ghost`) |
44
44
  | A hero's glows, an assistant's working orb | `ws-glow-rose`, `ws-glow-pink`, `ws-glow-blue`, `ws-orb` | from the chart tones |
45
45
  | Focus | `ws-focus-color` | navy |
46
46
  | Behind a dialog | `ws-scrim` | navy 35% |
@@ -83,6 +83,24 @@ A strip of ticks or a bar takes the band's one tone; its words take the band's w
83
83
 
84
84
  Never a state by colour alone: a word or a mark goes with it.
85
85
 
86
+ ## Status sets: error, warning, success, info
87
+
88
+ An app whose statuses are named error, warning, success and info (a badge, a banner, an inline message) maps each onto
89
+ the kit's tones; there are no separate status colours (#15).
90
+
91
+ | Status | Means | Words | Ground (a chip, a banner) | Mark, icon or edge | Banner, Chip |
92
+ | --- | --- | --- | --- | --- | --- |
93
+ | Error | something is wrong now: failed, rejected, blocked | `ws-word-alert` | `ws-tint-alert` | `ws-chart-alert` | `--alert` |
94
+ | Warning | needs the person: something to fix, ending soon | `ws-word-needs` | `ws-tint-needs` | `ws-chart-under-half` (salmon) | `--needs` |
95
+ | Success | done, passed, gone well | `ws-word-positive` | `ws-tint-live` | `ws-chart-finished` (teal) | `--positive` / `--live` |
96
+ | Info | working, still running, a plain note | `color-text-interactive` | `ws-card-tint-blue` (a chip: the plate) | `color-text-interactive` | `--working` / `--accent` |
97
+
98
+ - **No solid status fills.** A status is its tint, its words and its mark; a solid fill with white words is navy's alone
99
+ (a count, the one act), and salmon and mid blue are never a fill.
100
+ - **A field's error stays "needs"**: a salmon edge and `ws-word-needs` words under the field (Input), since the person
101
+ fixes it. Error red is for a thing that went wrong, not a field to correct.
102
+ - A neutral status ("Draft", "Scheduled") is the plain chip or the `neutral` banner, never a tone.
103
+
86
104
  ## Rules
87
105
 
88
106
  - **Navy is for words, the one button and a few named fills**: the tab or segmented thumb, a selected toggle, a checked
@@ -99,7 +117,8 @@ Never a state by colour alone: a word or a mark goes with it.
99
117
  - **An assistant's mark** takes one of the four tones and keeps it; no other colour names it.
100
118
  - **The AI colours** (`color-ai-*`) exist only inside an assistant's orb mark, if the product has one, and as faint washes
101
119
  in `ws-cool-glow` and `ws-team-glow` behind a page hero. No conic rings, purple glows or gradient text, except the
102
- status line's word while an answer works (`StatusLine`, in the chart colours) and the loading shimmer.
120
+ status line's word while an answer works (`StatusLine`, in the chart colours). The loading shimmer is one neutral
121
+ tone, the ghost grey and a lighter pass of it, never the chart colours (0.5.1).
103
122
  - **People are neutral**: a disc of `ws-surface-sunk` with navy initials.
104
123
  - **Marketing pages** keep the kit's own marketing colours (its gradient button, `color-text-primary`); they never enter a
105
124
  product screen.
@@ -136,7 +136,8 @@ A public page's `KitCard` is 4.
136
136
 
137
137
  Everything is flat at rest. What floats lifts on one family of shadows, a single soft drop each: a popover
138
138
  (`ws-shadow-pop`), a menu (`ws-shadow-menu`), a tooltip or hover card (`ws-shadow-tip`), a floating chat or a tile opened
139
- out of its slot (`ws-shadow-float`). In dark each carries a 0.5 px light rim. Buttons never lift. Layers: `z-dropdown`
139
+ out of its slot (`ws-shadow-float`), and a drawer that rises from the bottom of a pane (`ws-shadow-rise`, the menu's
140
+ drop cast upward: the pane's content sits above it, so the shade falls on it). In dark each carries a 0.5 px light rim. Buttons never lift. Layers: `z-dropdown`
140
141
  for menus and tips, `z-modal` for a dialog or drawer, `z-toast` for a toast.
141
142
 
142
143
  ## The frame
@@ -14,6 +14,7 @@ Components new in 0.5.0 are marked (new).
14
14
  | A label that may be wider than its column (a long link act, a translation) | `Button` with `ws-btn--wrap` | a button is one line and never shrinks beside its row's words; only an opted-in label wraps, in balanced lines (a link, text or ghost reads from its start) |
15
15
  | Words that act inside a sentence | `Button` link (mid blue: goes somewhere or shows more) or text (navy: a quiet act) | never a boxed button in running words |
16
16
  | Go somewhere | `Button` as a link (`ButtonLink`), or `ws-link` | a link is a link in the markup, whatever it looks like |
17
+ | One act with a few other forms of itself (approve now, approve and schedule) | `Button` joined with its caret (`ws-btn-join`) opening a `Menu` | the plain act is the common one; other acts go in a three-dots `Menu` |
17
18
  | An act with no words (send, close, more, previous, next) | `IconButton` with a label | |
18
19
  | Turn something on or off, stays on | `Button selected` or `IconButton selected` (navy) | a toggle's state is `aria-pressed` |
19
20
  | Switch between a few views of one thing | `Segmented` (a switch) | inside the card it filters |
@@ -23,6 +24,7 @@ Components new in 0.5.0 are marked (new).
23
24
  | Know where you are in a deep hierarchy | `Breadcrumb` | the root crumb never shrinks; collapse the middle over four levels |
24
25
  | Move through a long collection | `Pagination` in the card's foot | |
25
26
  | A product of several pages that is not chat-first | `AppShell` (with its sidebar) and `TopBar` | the same rows, gutters and one navy button as the chat shell |
27
+ | A page with a few pages of its own, in the sidebar | `AppShell`'s section (`__section`) | folds in place, one level only; folded, a panel beside the rail; never a hand-built sidebar |
26
28
  | A single page: an artifact, a report, an internal page | `Page` with a `PageBar` | no shell; its board holds the cards; start from `Starter` |
27
29
  | A thread or app page in place of the chat | `PageBar`'s 56 px thread header | the page's name, the app's name, its acts, the way back |
28
30
  | Open the one thing's details | a link `Card`, a `Well` row, a `CheckRow`, a table row | it opens in the panel beside the chat, a drawer, or the page's side pane |
@@ -38,9 +40,11 @@ Components new in 0.5.0 are marked (new).
38
40
  | --- | --- | --- |
39
41
  | Type a short value | `Input` with a label above | the error under it with a warning mark |
40
42
  | Type several lines | `TextArea` | |
43
+ | Change one value where it is read (a title, a brief's fact) | `InlineEdit` | the same box and type at rest and editing; Enter or blur saves, Escape reverts; one value at a time |
41
44
  | Choose one of a few visible options | `Radio` group with a legend | up to about 5; make them easy to compare |
42
45
  | Choose one of many | `Select` | over 5 options, or a choice that changes the data rather than the view |
43
46
  | Choose one of many with search, or several as tags | `Combobox` | over about 20 options, or when the list is open-ended ("Create 'Pine Street'") |
47
+ | Choose a picture, a template or an asset from a grid | `Card` buttons with `ws-card__media`, `ws-card--ring` when chosen | a group of `aria-pressed` buttons (several) or a `radiogroup` (one); the tick and the ring, never a tab under a tile |
44
48
  | A number with a unit or steps | `NumberInput` | |
45
49
  | A value on a range (a team size, a share) | `Slider` (new) | the value said in words beside it |
46
50
  | A password | `PasswordInput` | |
@@ -48,8 +52,10 @@ Components new in 0.5.0 are marked (new).
48
52
  | Choose several | `Checkbox` | independent choices; the label is part of the target |
49
53
  | A setting that applies at once | `Switch`, with "Saved" shown for a moment | the whole row is the target |
50
54
  | Talk or type to an agent | `Composer` | the one chat box; a drawer's small ask field is its compact look |
51
- | Pick a date or a range | `DateInput` (native first, with its popover month grid) | |
55
+ | Pick a date or a range | `DateInput` (native first, with its popover month grid) | a far date: the month and year selects (`__jump`); an optional one: Clear in the foot |
56
+ | Pick a time, or a date with a time | `DateInput` on `type="time"` or `type="datetime-local"` (the platform's picker) | a zone other than the person's is named in the label |
52
57
  | Search a list | `Input` with the search icon, in the card it searches | (Patterns) |
58
+ | Set a colour (brand colours, a palette) | `Input`'s colour field: a swatch that opens the picker, the hex beside it | the hex validates as it is typed; an invalid one keeps the last good swatch |
53
59
 
54
60
  ## Showing things
55
61
 
@@ -69,17 +75,23 @@ Components new in 0.5.0 are marked (new).
69
75
  | What to do next, one row a person or thing ("who needs a nudge") | `ActionList` in a `Card` | the reason in words with its figures; one secondary act per row; a bulk act in the band |
70
76
  | What happened, in order | `Timeline` | |
71
77
  | Things moving through stages | `KanbanBoard` | a card glides between stages |
78
+ | Where one thing is in its stages | `Stepper --across` | the in-hand stage ringed, a stall in needs-you words under it |
79
+ | One thing's dated milestones (signed, first value) | `Stepper --milestones` | the measure on each milestone; a late one in needs-you words |
80
+ | Things on dates (posts, sends, tasks, touches by day) | `Calendar` (new) | a month or a week, Monday first; a narrow column reads it as an agenda |
81
+ | A plan's phases and tasks across their dates | `PlanTimeline` (new) | a bar from start to end on one scale, the phase in hand navy, today one line through every row |
72
82
  | A few facts about one thing | a `Plate` of label and value rows | inside the card |
73
83
  | A score that answers a report | `ScoreHero` (new) | the 96 px score, its strip, the rating word and one sentence; one per report |
74
84
  | A number that matters | `GoalTicks` (the 72 px number with its change chip) or `StatTiles` (several figures) | one hero figure per card; tiles only where the answer is numbers |
75
85
  | A key metric that opens across its row | `MetricTile` (new) | closed: label, figure, pace bar, foot; open: its chart and side column |
76
86
  | Progress against a pace or a target | `PaceBar` (new) | the fill, the pace mark, the figure in words beside |
77
87
  | A change since when | `ChangeChip` (in `Chip`) | an arrow and words, never colour alone |
78
- | A count, a kind, a state | `Chip` | a rating's tag takes the rating's tint and word |
79
- | A disclosure ("Why", "All details", a chapter) | `Fold` (card, quiet or row) | the one disclosure; never a custom accordion |
88
+ | A count, a kind, a state | `Chip` | a rating's tag takes the rating's tint and word; several on one card or in one cell: `--sm` (20) |
89
+ | A disclosure ("Why", "All details", a chapter) | `Fold` (card, quiet or row) | the one disclosure; never a custom accordion. An act in its head that must not toggle it, words shown only while folded, or a notice's tone: the card look's `ws-fold__act`, `ws-fold__peek`, `ws-fold--needs` |
80
90
  | A small group inside a card | `Section` | |
81
91
  | A tile in a bento, or the row of what an app can do | `Tile` | the tile row sits on the well, each tile a door or the step it waits on |
82
92
  | People | `Avatar` (and its stack) | |
93
+ | People commenting on a thing, with replies, mentions and resolve | `CommentThread` | anchored to the stretch it is on; one level of replies; a mention of you on the needs tint |
94
+ | What changed between two versions of a text | `TextDiff` (by line or inline) | never colour alone: a sign, a strike, an underline |
83
95
  | An agent | the assistant's own mark, drawn by the designer (no catalog piece) | still outside the chat (AI experiences) |
84
96
  | A short tip on hover or focus | `Tooltip` | never the only place a label lives; its navy note holds a cell's full words |
85
97
  | A reading of a chart's mark under the pointer | `HoverCard` (new) | a caret to its mark; the value is still written beside the mark |
@@ -94,10 +106,14 @@ Components new in 0.5.0 are marked (new).
94
106
  | Inspect one thing while keeping the list or chat | `Panel` (440 beside the chat, or a rimmed drawer beside a report) or a page's side pane | the same view component in each |
95
107
  | The chat as a bar, docked beside a page, floating or full screen | `ChatShell` (new) | one chat; it moves between its modes as itself |
96
108
  | One long conversation, marked by topic | `TopicRail` (new) with `ChatShell` | the topics as a rail; the conversation stays one thread |
109
+ | An email, a call or a text in the chat | `ChatCard`'s message kinds (Email, Call, Text) | only one to read or answer now; the rest named in the agent's words with the source |
110
+ | An account that needs a decision, in the chat | `ChatCard`'s Account kind | its standing as a rating `Chip`, its numbers on a stats plate, one navy act |
111
+ | A thread per account, with a daily briefing | Page recipes, 25 (`ListDetail` of threads, the thread, `Composer`) | one chat kept by the thing it is about; the briefing is the one time the agent speaks first |
97
112
  | A short blocking task (confirm, name, one field) | `Dialog` | sparingly; head, content, foot with the one primary last |
98
113
  | A list of acts | `Menu` | the three dots open it |
99
114
  | A quiet confirmation of a background act | `Toast` | essential information lives elsewhere |
100
115
  | A state of the whole page or card (offline, a trial ending, a job done) | `Banner` | never for a field's error |
116
+ | An error, warning, success or info status on a badge, a banner or a line | `Chip` or `Banner` in the status's tone | error `alert`, warning `needs`, success `positive` (a chip `live`), info `working` (a chip `accent`) (Colour, Status sets) |
101
117
  | Something that cannot be undone | `ConfirmDialog` | as Patterns' editing table says |
102
118
  | A page that is not there, offline, an error | `StatusScreen` | plain words, one act; never a status code |
103
119
  | Something that needs you later | a chat card in its app's chat and a row in Needs you | never a popup |
@@ -106,7 +122,7 @@ Components new in 0.5.0 are marked (new).
106
122
 
107
123
  | Need | Component | Rule |
108
124
  | --- | --- | --- |
109
- | Content on its way | `Skeleton` (the shimmer in the chart colours over ghost shapes) | never a spinner for content |
125
+ | Content on its way | `Skeleton` (the shimmer, one quiet grey, over ghost shapes) | never a spinner for content; a whole page keeps its own bar, its name shown at once, over a board of card skeletons (the page ghost) |
110
126
  | An answer at work | `StatusLine` (new) | the agent, what it is doing, the step |
111
127
  | A long load with no figure | `LoadBar` (new) | it never claims to finish before it has |
112
128
  | A press waiting on its answer | `Button pending` | keeps its width; a second press waits; the button stays focusable |
@@ -18,7 +18,7 @@ piece.
18
18
  | A key number that opens into its story | a tile: label, figure, pace bar or a mini chart (columns of the periods behind it, or a line with dots), foot; it grows across its row into a chart and a side column | `MetricTile` (new) |
19
19
  | Where a whole goes (a bill, a team's time) | one stacked bar, 1 px cuts between parts, a key under it | `ShareBar` (new) |
20
20
  | How a value changes over time, against a reference | a step line, the reference dotted, the gap between them hatched, events marked | `StepLine` (new) |
21
- | How a value moves over periods (a month's ARR, a week's calls), read on an axis | a line with its dots and the hatched area under it, or columns, switching between the two by a morph; a plan as a dotted salmon line | `TrendLine` (new) |
21
+ | How a value moves over periods (a month's ARR, a week's calls), read on an axis | a line with its dots and the hatched area under it, or columns, switching between the two by a morph; a plan as a dotted salmon line; two or three series in one unit as lines with a key | `TrendLine` (new) |
22
22
  | How several groups do on several measures | lanes by measures, each cell a tone and a figure | `Heatmap` (new) |
23
23
  | Compare a few categories (calls by kind) | horizontal bars with a fade, the number and label at the right | `GoalBars` |
24
24
  | Compare a few categories where height reads better (a hero) | vertical tubes with the number on a stalk | `GoalTubes` |
@@ -33,8 +33,8 @@ piece.
33
33
  | Yes or no across a few sources | a matrix of tone cells | `Matrix` (new) |
34
34
  | A sequence or a wait | steps on a line that fills | `Stepper` |
35
35
 
36
- Do not use: a pie with more than three parts (make it bars or a `ShareBar`), a free line chart (two series or more, or a
37
- line with no axis: make it thin bars, a `TrendLine` of one series over periods, or a `StepLine` where a designer draws
36
+ Do not use: a pie with more than three parts (make it bars or a `ShareBar`), a free line chart (more than three series,
37
+ or a line with no axis: make it thin bars, a `TrendLine` of up to three series in one unit over periods, or a `StepLine` where a designer draws
38
38
  a bill or a level over time; a `MetricTile`'s mini line with dots for a rate that holds near its target), an axis or a
39
39
  grid where thin bars suffice, stacked bars
40
40
  across categories (make two rows; one `ShareBar` for one whole is fine), a donut for a single number (make it the goal
@@ -74,6 +74,9 @@ Seth draws most shares as ticks. The rules every strip follows:
74
74
  labels, 12 before the plot; a `TrendLine` keeps 0.5 px value rules and right-aligned value labels, 12 before the plot,
75
75
  its columns starting at zero.
76
76
  - **A hover card may add detail, never be the only reading**: the value is written beside the mark.
77
+ - **One value axis, never two.** Series in different units, or one more than four times another, are two `TrendLine`s
78
+ stacked in one card on the same periods, each with its own axis and a key of one, the period names only under the
79
+ last. Up to three series that share a unit share one axis, a line each, with a key; a hover reads every series.
77
80
  - One chart per card; one hero figure per card; a change is a `ChangeChip` (in `Chip`).
78
81
 
79
82
  ## Data rules
@@ -89,7 +92,7 @@ Seth draws most shares as ticks. The rules every strip follows:
89
92
 
90
93
  ## States
91
94
 
92
- Loading and empty follow Patterns (a shimmer in the chart colours over the chart's ghost; the same card with its act).
95
+ Loading and empty follow Patterns (the shimmer, one quiet grey, over the chart's ghost; the same card with its act).
93
96
 
94
97
  | State | How |
95
98
  | --- | --- |
@@ -58,7 +58,7 @@ moves. A state never changes a thing's size, its type size or its place, so noth
58
58
  | Focus | a 2 px navy ring 2 px outside (`ws-focus-color`); inside a dense row, a well, a list or a clipped container the same ring drawn inside (`ws-focus-inset`) | `:focus-visible` only; never `outline: none` without the ring (Accessibility) |
59
59
  | Selected, open, current | the ground changes (the sunk cream, or the well for a pill in an inset list), the words go navy or 600; a list's selected fill slides from the row it left; the dividers beside an inset pill drop | the row keeps its height and type size; `aria-selected`, `aria-current` or `aria-expanded` says it |
60
60
  | Pending | the control keeps its width and its words; the working dot sits in its padding on the one beat; it stays focusable (`aria-disabled`, `aria-busy`) and refuses a second press | from 100 ms (Latency above); words that say what is happening ("Saving") |
61
- | Loading | the region's ghost in the chart colours' shimmer, the size of what it stands for; its head shows at once | never a spinner for content; still under reduced motion, with a word |
61
+ | Loading | the region's ghost under the shimmer (one quiet grey), the size of what it stands for; its head shows at once | never a spinner for content; still under reduced motion, with a word |
62
62
  | Disabled | dimmed (the component's own opacity), no pointer events, the reason said nearby | prefer leaving the act out, or keeping it focusable and saying why |
63
63
  | Others step back | while one row, part or tile is in focus, the rest dim (a matrix's other rows to 20%, a chart's other parts to `ws-dim`); the dimmed keep their grounds and dividers. A word that must stay readable steps to muted grey instead of fading (a heatmap's other squares fade their heat and status bar, their words stay AA) | the focused one never changes |
64
64
 
@@ -161,7 +161,8 @@ What a person sees the first time they open an app's thread (issue #12, Seth's v
161
161
  interactive). The row wraps; a tile is never narrower than 168.
162
162
  4. **The composer** at the foot, with a few starters (`SuggestionChip`).
163
163
 
164
- Nothing proactive arrives on a first open; the agent speaks when asked.
164
+ Nothing proactive arrives on a first open; the agent speaks when asked. (The daily briefing, recipe 25, starts once
165
+ there is data to brief on.)
165
166
 
166
167
  ## 23. A report with its drawer
167
168
 
@@ -209,6 +210,44 @@ Seth's Grow review inbox (Figma 313:2671).
209
210
  - **Keyboard**: arrow keys move through the list; Previous and Next move the item and the chosen row together.
210
211
  - **On a phone** the tiles stack, the list is the screen and the item is its own screen with Back.
211
212
 
213
+ ## 25. An agent desk: one thread per account
214
+
215
+ An agent that works a book of accounts with the person (Calvin in Customer Value): one chat, its threads kept by the
216
+ account they are about, the day's briefing on top. Every part is in the catalog.
217
+
218
+ - **The frame**: `AppShell`, the app's pages in its nav; the desk's row carries the count of what waits on the person.
219
+ The stage's wide body (`ws-app-shell__body ws-app-shell__body--wide`) holds one filled `ListDetail`
220
+ (`ws-list-detail ws-list-detail--fill`, joined), the list at North's 362 (`--ws-list-detail-list`): the threads,
221
+ then the open thread.
222
+ - **The threads** (the list): its head holds the filter (`Segmented --clear --stretch`: "Waits on you" and "All", each
223
+ with its count); its scroller holds `SideList`'s picks, one per thread, the latest activity first. "Today", the
224
+ briefing, is always the first. Then one pick per account the person has talked about: the dot in the account's
225
+ rating tone (teal healthy, mid blue watch, pink at risk: Colour's rating tones, never salmon), the account's name,
226
+ its last line as the sub (the person's last question or the agent's last act), when at the end, and what waits on
227
+ the person there in salmon's AA word. Questions about the whole book go to one "Your book" thread. There is no "New
228
+ chat": a thread starts from the account ("Ask about this" on its page) or from the composer naming it.
229
+ - **The open thread** (the detail): its head (`__top`) holds the account's name (`ws-section`) and its rating `Chip`,
230
+ "Open the account" at the right. Then the turns (`ChatTurn`): the person's in a bubble, the agent's as plain words,
231
+ each answer words plus at most one card (`ChatCard`): an email, a call or a text to read or answer now (the message
232
+ kinds), the Account card when a decision is due, a Suggestion holding a draft `Plate` for a reply it wrote. Every
233
+ other message is named in its words with its source ("From the 9 Nov call"); the full history is the account's
234
+ page. A long thread is marked by topic (`TopicRail`). The `Composer` sits at the detail's foot (where recipe 24's
235
+ acts sit), its starters for this account ("Catch me up", "Draft a reply to Jordan").
236
+ - **The briefing** ("Today"): written once a day at the hour the person set (6:00 by default, in their own time zone),
237
+ and the desk opens on it. One sentence on the day ("Morning, Halli. Three accounts need you and two replies are ready
238
+ to send."), then what needs the person as one `Well` (Home's Needs you, recipe 1): a row per account and its one
239
+ ask, the state word at the right, each row opening that account's thread at the card it means. Then at most one card,
240
+ the most pressing (a ready reply to send). Nothing else is copied in: each account's cards stay in its own thread. A
241
+ day with nothing due says so in one line. Before there is data, the desk's first open is recipe 22.
242
+ - **At 1440**: the nav open (232), the list 362, the thread the rest, about the chat's 760 reading column; cards at most
243
+ 556, their trays at 80.
244
+ - **At 390**: the nav is the bar's menu (AppShell's phone form); the list is the screen and the briefing its first
245
+ pick; a thread opens as its own screen with Back (recipe 24's phone form); the composer at the foot, clear of the
246
+ safe area; cards fill the column, their trays at 64.
247
+ - **Everywhere else in the app**: "Ask about this" on an account opens its own thread docked (`ChatShell`), the same
248
+ thread the desk shows. One chat, never a second assistant on the page.
249
+ - **Keyboard**: arrow keys move through the threads (recipe 24); `/` puts the focus in the composer.
250
+
212
251
  ## What every recipe shares
213
252
 
214
253
  One primary per page (navy in a product, the salmon gradient on a public page). The gutter is the stage's; one content
@@ -105,7 +105,7 @@ follows cause to effect on the way in; on the way out the person has already mov
105
105
  | Component | Enters | Leaves | How the exit gets to play |
106
106
  | --- | --- | --- | --- |
107
107
  | `Menu`, `Popover` | out of the corner it hangs from, 4 px toward its control, from `--ws-open-scale` (0.97), on `--ws-spring-settle` ("Messages and steps settle") | back into that corner over `--ws-duration-exit` (120 ms) on `--ws-ease-exit` | a native `popover`: `@starting-style` and `allow-discrete` keep its box while it leaves, and a close mid-entrance turns back. Mounted by the app: `data-leaving`, then remove it |
108
- | `Dialog` | the scrim fades; the window rises 14 px out of `--ws-open-scale-pane` (0.98) on `--ws-spring-settle`, its parts settling in after it | 8 px down over `--ws-duration-exit` | a native `<dialog>` (`showModal()`, `close()`), the same way. A drawer slides in from its edge over `--ws-duration-grow` on `--ws-ease-grow` and back over `--ws-duration-shrink` |
108
+ | `Dialog` | the scrim fades; the window rises 14 px out of `--ws-open-scale-pane` (0.98) on `--ws-spring-settle`, its parts settling in after it | 8 px down over `--ws-duration-exit` | a native `<dialog>` (`showModal()`, `close()`), the same way. A drawer slides in from its edge over `--ws-duration-grow` on `--ws-ease-grow` and back over `--ws-duration-shrink`. Mounted by a library (`ws-dialog--mounted` and `ws-dialog__scrim`): Radix's `data-state="closed"`, or `data-leaving`, then remove it |
109
109
  | `Toast` | up out of `--ws-open-scale-toast` (0.96) on `--ws-spring-settle` | 4 px down over `--ws-duration-exit` | `data-leaving`, then remove it |
110
110
  | `Tooltip` | pops from 0.9, 4 px toward its control, on `--ws-spring-pop` ("Tooltip pop-in"), after the 40 ms hover intent; at once on keyboard focus | fades off over 180 ms | CSS alone: hover, focus or `ws-tooltip--open` |
111
111
  | `HoverCard` | pops from 0.9 on `--ws-spring-pop`, its rows settling 45 ms apart; `--follow` glides after the pointer on `--ws-spring-follow`, which never bounces | to `--ws-pop-scale` over `--ws-duration-exit` | `data-leaving`, then remove it |
@@ -193,9 +193,9 @@ of cards wears `.ws-build`; each card in it wears `.ws-build__card` with `--ws-i
193
193
 
194
194
  ### Loading
195
195
 
196
- Content on its way is a ghost the size of what it stands for with the shimmer passing over it in the chart colours
197
- (`Skeleton`, or `.ws-shimmer` on a block of your own: every `--ws-loop-shimmer`, 1.8 s, on `--ws-ease-shimmer`), never
198
- a spinner. When the content lands, its details settle in top to bottom (`.ws-settle` with `--ws-i` on each, 22 ms
196
+ Content on its way is a ghost the size of what it stands for with the shimmer passing over it: one quiet tone, the
197
+ ghost grey and a lighter pass of the same grey, never a chart hue (`Skeleton`, or `.ws-shimmer` on a block of your own:
198
+ every `--ws-loop-shimmer`, 1.8 s, on `--ws-ease-shimmer`), never a spinner. When the content lands, its details settle in top to bottom (`.ws-settle` with `--ws-i` on each, 22 ms
199
199
  apart). An answer at work shows a `StatusLine`; a long load with no figure a `LoadBar`; a pressed button waiting keeps
200
200
  its width and shows its working dot on `--ws-loop`. Why: the layout is already in place, so nothing jumps when the real
201
201
  thing arrives. Under reduced motion the shimmer stops on its ghost and the words say what is loading.
@@ -19,6 +19,17 @@ sit in a bubble with navy text (`ChatTurn` has the sizes). Starters sit under th
19
19
  conversation is marked by topic (`TopicRail`), never split into threads the person did not ask for. A reply is words plus at most one card, never both saying the
20
20
  same thing. An act is a one-line receipt ("Drafted the opener for Nellie"), not a paragraph. A question is not echoed back.
21
21
 
22
+ ## Threads by account, and the daily briefing
23
+
24
+ An agent that works a book of things with the person (accounts, deals) keeps one thread per thing, because the person
25
+ works them one at a time: the thread belongs to the account, is opened from it or by naming it, and is never a split
26
+ the person did not ask for. Inside one thread, subjects are still marked by topic (Page recipes, 25).
27
+
28
+ The one time an agent speaks first is the daily briefing the person set up: once a day, at their hour, as the first
29
+ turn of "Today". One sentence on the day, what needs them as one list, at most one card. Plain words with no bubble,
30
+ nothing that says "AI", no popup or push of its own: the desk's count is the only notice. It never copies what each
31
+ thread already holds, and it stays quiet until there is data to brief on.
32
+
22
33
  ## Streaming, working and cancelling
23
34
 
24
35
  A reply arrives as it is written; while it works, a status line (`StatusLine`) says who is working, what it is doing and