@mthanh/vespercli 2.2.0 → 2.3.0

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 (157) hide show
  1. package/README.md +6 -3
  2. package/assets/CATALOG.md +9 -2
  3. package/assets/claude/.claude-plugin/marketplace.json +9 -9
  4. package/assets/claude/.claude-plugin/plugin.json +1 -1
  5. package/assets/claude/agents/code-planner.md +1 -1
  6. package/assets/claude/agents/code-reviewer.md +1 -1
  7. package/assets/claude/agents/code-tester.md +1 -1
  8. package/assets/claude/agents/copywriter.md +1 -1
  9. package/assets/claude/agents/feature-wrap-document.md +1 -1
  10. package/assets/claude/agents/janitor.md +1 -1
  11. package/assets/claude/agents/modernization.md +1 -1
  12. package/assets/claude/agents/principal-software-engineer.md +1 -1
  13. package/assets/claude/agents/refine-issue.md +1 -1
  14. package/assets/claude/agents/se-system-architecture-reviewer.md +1 -1
  15. package/assets/claude/agents/se-technical-writer.md +1 -1
  16. package/assets/claude/agents/skill-creator.md +1 -1
  17. package/assets/claude/agents/task-researcher.md +1 -1
  18. package/assets/claude/agents/technical-product-manager.md +1 -1
  19. package/assets/claude/agents/vision-analyst.md +1 -1
  20. package/assets/claude/agents/vitest.md +1 -1
  21. package/assets/claude/agents/workspace-learner.md +2 -2
  22. package/assets/claude/packs/backend/.claude-plugin/plugin.json +1 -1
  23. package/assets/claude/packs/backend/agents/firebase-developer.md +1 -1
  24. package/assets/claude/packs/backend/agents/nodejs-express-developer.md +1 -1
  25. package/assets/claude/packs/docs/.claude-plugin/plugin.json +1 -1
  26. package/assets/claude/packs/frontend/.claude-plugin/plugin.json +1 -1
  27. package/assets/claude/packs/frontend/agents/expert-nextjs-developer.md +1 -1
  28. package/assets/claude/packs/frontend/agents/expert-react-frontend-engineer.md +1 -1
  29. package/assets/claude/packs/frontend/agents/jest-react-component-analyzer.md +1 -1
  30. package/assets/claude/packs/frontend/agents/jest-react-scenario-scanner.md +1 -1
  31. package/assets/claude/packs/frontend/agents/jest-react-test-generator.md +1 -1
  32. package/assets/claude/packs/frontend/agents/jest-react-test-planner.md +1 -1
  33. package/assets/claude/packs/frontend/skills/design-taste-frontend/LICENSE +21 -0
  34. package/assets/claude/packs/frontend/skills/design-taste-frontend/SKILL.md +529 -0
  35. package/assets/claude/packs/frontend/skills/design-taste-frontend/UPSTREAM.json +7 -0
  36. package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/app.css +216 -0
  37. package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/base.css +105 -0
  38. package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/base.js +37 -0
  39. package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/charts.js +617 -0
  40. package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/scenes/stage.css +28 -0
  41. package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/scenes/stage.js +133 -0
  42. package/assets/claude/packs/frontend/skills/design-taste-frontend/evals/evals.json +76 -0
  43. package/assets/claude/packs/frontend/skills/design-taste-frontend/library/app.json +1327 -0
  44. package/assets/claude/packs/frontend/skills/design-taste-frontend/library/directions.json +1078 -0
  45. package/assets/claude/packs/frontend/skills/design-taste-frontend/library/heroes.json +1086 -0
  46. package/assets/claude/packs/frontend/skills/design-taste-frontend/library/motions.json +92 -0
  47. package/assets/claude/packs/frontend/skills/design-taste-frontend/library/palettes.json +1485 -0
  48. package/assets/claude/packs/frontend/skills/design-taste-frontend/library/photos.json +7240 -0
  49. package/assets/claude/packs/frontend/skills/design-taste-frontend/library/sections.json +4429 -0
  50. package/assets/claude/packs/frontend/skills/design-taste-frontend/library/sites.json +8350 -0
  51. package/assets/claude/packs/frontend/skills/design-taste-frontend/library/type.json +2024 -0
  52. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/app-screens.md +1199 -0
  53. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/colour.md +141 -0
  54. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/copy.md +177 -0
  55. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/critique.md +182 -0
  56. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/imagery.md +791 -0
  57. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/layout.md +292 -0
  58. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/motion.md +980 -0
  59. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/research.md +356 -0
  60. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/scenes.md +174 -0
  61. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/tells.md +115 -0
  62. package/assets/claude/packs/frontend/skills/design-taste-frontend/references/type.md +170 -0
  63. package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/assets.mjs +865 -0
  64. package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/draw.mjs +584 -0
  65. package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/inspect.mjs +303 -0
  66. package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/lib/app-draw.mjs +203 -0
  67. package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/lib/cdp.mjs +248 -0
  68. package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/lib/probe.mjs +909 -0
  69. package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/lib/rules.mjs +243 -0
  70. package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/lint.mjs +119 -0
  71. package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/scenes.mjs +124 -0
  72. package/assets/claude/packs/graphify/.claude-plugin/plugin.json +1 -1
  73. package/assets/claude/packs/integrations/.claude-plugin/plugin.json +1 -1
  74. package/assets/claude/packs/playwright/.claude-plugin/plugin.json +1 -1
  75. package/assets/claude/packs/playwright/agents/playwright-component-analyzer.md +1 -1
  76. package/assets/claude/packs/playwright/agents/playwright-scenario-scanner.md +1 -1
  77. package/assets/claude/packs/playwright/agents/playwright-test-generator.md +1 -1
  78. package/assets/claude/packs/playwright/agents/playwright-test-planner.md +1 -1
  79. package/assets/claude/packs/playwright/agents/playwright-tester.md +1 -1
  80. package/assets/claude/packs/polyglot/.claude-plugin/plugin.json +1 -1
  81. package/assets/claude/packs/styles/.claude-plugin/plugin.json +1 -1
  82. package/assets/copilot/agents/code-planner.agent.md +1 -1
  83. package/assets/copilot/agents/code-reviewer.agent.md +1 -1
  84. package/assets/copilot/agents/code-tester.agent.md +1 -1
  85. package/assets/copilot/agents/copywriter.agent.md +1 -1
  86. package/assets/copilot/agents/feature-wrap-document.agent.md +1 -1
  87. package/assets/copilot/agents/janitor.agent.md +1 -1
  88. package/assets/copilot/agents/modernization.agent.md +1 -1
  89. package/assets/copilot/agents/principal-software-engineer.agent.md +1 -1
  90. package/assets/copilot/agents/refine-issue.agent.md +1 -1
  91. package/assets/copilot/agents/se-system-architecture-reviewer.agent.md +1 -1
  92. package/assets/copilot/agents/se-technical-writer.agent.md +1 -1
  93. package/assets/copilot/agents/skill-creator.agent.md +1 -1
  94. package/assets/copilot/agents/task-researcher.agent.md +1 -1
  95. package/assets/copilot/agents/technical-product-manager.agent.md +1 -1
  96. package/assets/copilot/agents/vision-analyst.agent.md +1 -1
  97. package/assets/copilot/agents/vitest.agent.md +1 -1
  98. package/assets/copilot/agents/workspace-learner.agent.md +2 -2
  99. package/assets/copilot/packs/backend/agents/firebase-developer.agent.md +1 -1
  100. package/assets/copilot/packs/backend/agents/nodejs-express-developer.agent.md +1 -1
  101. package/assets/copilot/packs/frontend/agents/expert-nextjs-developer.agent.md +1 -1
  102. package/assets/copilot/packs/frontend/agents/expert-react-frontend-engineer.agent.md +1 -1
  103. package/assets/copilot/packs/frontend/agents/jest-react-component-analyzer.agent.md +1 -1
  104. package/assets/copilot/packs/frontend/agents/jest-react-scenario-scanner.agent.md +1 -1
  105. package/assets/copilot/packs/frontend/agents/jest-react-test-generator.agent.md +1 -1
  106. package/assets/copilot/packs/frontend/agents/jest-react-test-planner.agent.md +1 -1
  107. package/assets/copilot/packs/frontend/skills/design-taste-frontend/LICENSE +21 -0
  108. package/assets/copilot/packs/frontend/skills/design-taste-frontend/SKILL.md +529 -0
  109. package/assets/copilot/packs/frontend/skills/design-taste-frontend/UPSTREAM.json +7 -0
  110. package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/app.css +216 -0
  111. package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/base.css +105 -0
  112. package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/base.js +37 -0
  113. package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/charts.js +617 -0
  114. package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/scenes/stage.css +28 -0
  115. package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/scenes/stage.js +133 -0
  116. package/assets/copilot/packs/frontend/skills/design-taste-frontend/evals/evals.json +76 -0
  117. package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/app.json +1327 -0
  118. package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/directions.json +1078 -0
  119. package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/heroes.json +1086 -0
  120. package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/motions.json +92 -0
  121. package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/palettes.json +1485 -0
  122. package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/photos.json +7240 -0
  123. package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/sections.json +4429 -0
  124. package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/sites.json +8350 -0
  125. package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/type.json +2024 -0
  126. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/app-screens.md +1199 -0
  127. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/colour.md +141 -0
  128. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/copy.md +177 -0
  129. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/critique.md +182 -0
  130. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/imagery.md +791 -0
  131. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/layout.md +292 -0
  132. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/motion.md +980 -0
  133. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/research.md +356 -0
  134. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/scenes.md +174 -0
  135. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/tells.md +115 -0
  136. package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/type.md +170 -0
  137. package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/assets.mjs +865 -0
  138. package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/draw.mjs +584 -0
  139. package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/inspect.mjs +303 -0
  140. package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/lib/app-draw.mjs +203 -0
  141. package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/lib/cdp.mjs +248 -0
  142. package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/lib/probe.mjs +909 -0
  143. package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/lib/rules.mjs +243 -0
  144. package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/lint.mjs +119 -0
  145. package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/scenes.mjs +124 -0
  146. package/assets/copilot/packs/playwright/agents/playwright-component-analyzer.agent.md +1 -1
  147. package/assets/copilot/packs/playwright/agents/playwright-scenario-scanner.agent.md +1 -1
  148. package/assets/copilot/packs/playwright/agents/playwright-test-generator.agent.md +1 -1
  149. package/assets/copilot/packs/playwright/agents/playwright-test-planner.agent.md +1 -1
  150. package/assets/copilot/packs/playwright/agents/playwright-tester.agent.md +1 -1
  151. package/assets/manifest.json +2 -0
  152. package/dist/cli.min.js +102 -102
  153. package/package.json +1 -1
  154. package/scripts/__snapshots__/generate-claude-assets.test.js.snap +1 -1
  155. package/scripts/generate-claude-assets.strict.test.js +1 -1
  156. package/scripts/generate-claude-assets.test.js +6 -6
  157. package/scripts/packs-layout.test.js +2 -1
@@ -0,0 +1,1199 @@
1
+ # App screens
2
+
3
+ Dashboards, admin, analytics, settings, inboxes, wallets and builders: the screens people work in.
4
+ Read this file whole before you start one. The page run in `SKILL.md` does not apply to them.
5
+
6
+ A generated dashboard is the average of every dashboard template: a dark or tinted sidebar with a
7
+ coloured pill on the active item, "Welcome back" and a waving hand, four KPI cards each with an icon
8
+ in a tinted circle, a green "+12.5%" and a sparkline, a gradient area chart, a zebra table under
9
+ uppercase headers. Nothing in it is wrong and none of it was decided.
10
+
11
+ This chapter is distilled from a study of 23 real product screens chosen by the owner: 17 products,
12
+ 17 light screens and 6 dark, all at desktop width (1440 or 1512px). Each screen was measured from its
13
+ pixels and noted for what works and what fails; the numbers below are those measurements and their
14
+ medians. The products are not named. What separates these screens from the generated kind, in order
15
+ of how much it shows:
16
+
17
+ 1. **Colour goes on data, not chrome.** The median screen has about 3% coloured pixels; 17 of 23 stay
18
+ at 5% or less. 12 have no filled primary button at all.
19
+ 2. **KPIs are type, not tiles.** No screen puts an icon in a coloured circle on a KPI, and none draws a
20
+ sparkline on one.
21
+ 3. **Surfaces are flat.** 17 of 23 give their cards no shadow; separation is a 1px line or one tone
22
+ step.
23
+ 4. **There is no hero header.** 9 screens have no heading over 16px; where there is one, its median is
24
+ 24px.
25
+ 5. **Charts carry almost no chrome.** A single series has no legend; gridlines are 3-7 faint lines or
26
+ none.
27
+ 6. **Navigation recedes.** The active item is a neutral grey pill or a change of text colour; a
28
+ coloured left bar appears once.
29
+ 7. **Tables are rules and alignment.** No zebra striping, no header bands, numbers right-aligned.
30
+ 8. **Data states are honest.** Zeros print as zeros, missing values as a grey dash, and an empty
31
+ section keeps its frame.
32
+
33
+ Taking the template's devices away is half the job, as it is on a page. The other half is substance:
34
+ the product's real data, a screen that answers its one question first, and a grid whose arithmetic
35
+ closes.
36
+
37
+ **A warning learned in testing.** In the first blind round, screens built with this chapter were
38
+ clean, quiet and correct, and they lost to richer screens built without it. The judges' reasons were
39
+ the same every time, and each is now a rule below:
40
+
41
+ - **The first screen was thin.** One large chart of a flat line filled it, and half the blocks the
42
+ brief asked for started below the fold. On a 1440×900 screen, every block the brief names shows its
43
+ header and its first rows (§2.2).
44
+ - **The product was missing.** No name, no workspace, no mark: the screen could have belonged to
45
+ anyone. The shell names the product and the scope (§3.2).
46
+ - **Restraint hid meaning.** A latency rise and a request rise were the same grey. Colour on a change
47
+ says good or bad, not up or down (§5).
48
+ - **There was nothing to do.** No control for the job the screen exists for. The most frequent job is
49
+ one click from the first screen (§2.2).
50
+ - **Rows ended ragged** and **a style's move was over-applied** (a tray around every card, an icon
51
+ rail where people needed labels). Keep the move to where it carries meaning.
52
+
53
+ Quiet is the starting point, not the goal. A screen that a person would trust shows more of the
54
+ product than a template does: its people, its objects, its numbers and the one thing to do next.
55
+
56
+ **Give the product a face.** After four rounds the judges' top complaint was the same on most
57
+ screens: "a well-applied kit, not a product with its own identity" (stock Geist or Inter, a #f8f8f8
58
+ ground, white 12px cards, lime on black). The style's tokens make a screen correct; these make it
59
+ this product's, and choosing them is a step of the run, not a finish (§2.3):
60
+
61
+ - **One face from the sheet, chosen before you build.** Each style lists two or three ways it takes a
62
+ face from the brief: a ground tinted from the product's world, a figure face with character, the
63
+ brand's hue on the main data element. Choose one, write it in your notes next to the screen's
64
+ question, and check that it shows on the first screenshot.
65
+ - **The dealt typeface, really loaded.** A build that fell back to the default face landed on the
66
+ default look; the inspector now fails it.
67
+ - **The product's mark and name** at the top of the shell, drawn for this product (a simple
68
+ monogram or symbol in the accent, from its name or its object), never a black square with a letter.
69
+ - **One element only this product has**, built from its own things: an energy home's power flow, a
70
+ bakery's sell-out strip, a leave planner's cover against the minimum, the pace groups of a running
71
+ club as a unit chart, the couple as three lanes, a deploy's commit as the hero of the overview. The
72
+ sheet lists the library's signature elements whose words appear in the brief; otherwise invent one.
73
+ Name it in your notes next to the screen's question.
74
+ - **The one chart hue on the main data element**: today's line, the booked bars, the current period,
75
+ the margin that breaks. A screen whose only hue is a delta reads as a kit, and the inspector warns
76
+ when a screen with charts carries no hue on its data (`no-data-hue`).
77
+ - **Its people and objects as themselves**: each person gets a stable initial and a pale tint of their
78
+ own hue, with people listed next to each other at least 60 degrees apart. These tints are identity,
79
+ not data: they stay pale and out of the chart legends. Products show their thumbnails, cover art
80
+ shows the cover.
81
+ - **Words of the trade** in labels and empty states ("Waiting on the customer", "Off sick", "Due
82
+ on the 28th"), never the generic noun of a template ("Items", "Records", "Status").
83
+
84
+ **Calendars and timelines** (house rule, from testing; the study has none). People down the left on a
85
+ fixed 160-220px column, grouped under a team subheader rather than repeating the team on every row;
86
+ days across with faint 1px day lines, weekends one tone step darker, and today marked by a 1px line
87
+ in the one data hue with its date in ink. Bars are 20-24px tall at radius 4. One-line names sit on a
88
+ 32px pitch; a name with a subline (team, office) needs 40-44px, or the subline touches the next name.
89
+ **Every kind of booking has its own mark**, so sickness reads apart from a holiday at a glance:
90
+ holiday a pale fill, off sick a 1px diagonal hatch, long leave a darker grey step, working away an
91
+ outline, a pending request a dashed outline. A style with a hue budget may add a 3px left edge in the
92
+ hue for the kind the screen is about. Full colour is only for what needs a decision (a request that
93
+ breaks cover). A label sits inside its bar; a bar too short for it shows the kind's code inside and
94
+ the full label in its tooltip, or the label after the bar's end, never over the days before it.
95
+ Holiday markers name their office in a multi-office product. Every swatch in the legend is the mark
96
+ itself, scaled down, and lists only kinds on screen: `Charts.timeline(el, rows, kinds)` draws the bars
97
+ and returns that legend from the same kinds map.
98
+
99
+ ## Contents
100
+
101
+ 1. When this applies
102
+ 2. The run for an app screen
103
+ 3. The shell
104
+ 4. The canvas and the page title
105
+ 5. KPIs
106
+ 6. Charts
107
+ 7. Tables and lists
108
+ 8. Forms and settings
109
+ 9. Type and colour
110
+ 10. Density
111
+ 11. Empty, zero, loading and error states
112
+ 12. The phone
113
+ 13. House rules for app screens
114
+ 14. Tells of generated dashboards
115
+
116
+ ## 1. When this applies
117
+
118
+ An app screen is worked in rather than read. This chapter covers:
119
+
120
+ - dashboards and overviews: a seller's day, a project's health, a publication's growth;
121
+ - admin and back office: members, orders, events, a catalogue;
122
+ - analytics and reports, including a generated report with no app around it;
123
+ - settings and billing;
124
+ - list screens to work through: inboxes, queues, tables with filters;
125
+ - wallets and finance homes;
126
+ - builders and editors: flow, form and page builders, canvases;
127
+ - the detail page of one object: an event, a deployment, a customer.
128
+
129
+ A product site that shows its interface is a page; the interface fragments on it follow these rules
130
+ for their insides (mark each fragment's root with `data-ui`). When a request holds both, build each
131
+ with its own run and share one palette and one typeface.
132
+
133
+ The study is 23 desktop screens. It has no phone screens, no loading or error states, one settings
134
+ page, no inbox and no dense operations table (the densest screen shows about 120 data points). Where a
135
+ rule below goes past the study, it says **house rule**.
136
+
137
+ ## 2. The run for an app screen
138
+
139
+ Do these in order. The first three steps decide whether the screen is any good.
140
+
141
+ ### 2.1 Inventory the data and the jobs
142
+
143
+ The page run inventories the subject's world; an app screen inventories its data. Write in your notes,
144
+ in 8 to 12 lines:
145
+
146
+ - **the objects** the screen shows (deployments, invoices, members, events, conversations) and their
147
+ fields, with units;
148
+ - **realistic magnitudes**: how many objects, a typical amount, the range of a rate, how values move
149
+ over a day, a month, a year, and for a new account how small they really are;
150
+ - **the people**: who opens this screen, how often (a glance once a day, or an eight-hour session),
151
+ on what device;
152
+ - **the jobs**: what they do next from here (approve, reply, pay, ship, invite), and which job comes
153
+ up most;
154
+ - **the product's own things**: its name and mark, the workspace or account it is scoped to, the people
155
+ in it (two partners, a team of six, the club's members), and the objects people recognise by sight
156
+ (product photographs in a shop, cover art in a media tool, a map of the route). These are what make
157
+ a screen belong to this product instead of to a template; plan where each one appears.
158
+
159
+ Then write the data itself: a small dataset in a JSON or JS file that the screen renders from, with
160
+ believable names, amounts that add up to their totals, dates in order and a unit on every figure.
161
+ Totals are computed from the rows, never typed in separately. Small numbers stay small: the studied
162
+ screens show new accounts with 1, 6 or 9 of something, drawn honestly at their real size. Write the
163
+ figures that must agree as assertions in the data file (`console.assert(sold - cancelled === rsvps)`,
164
+ the bins sum to the total, the parts to the whole) and read the console: in testing, a ticket table
165
+ that did not reconcile with its own KPI cost a judge's trust in the whole screen. Checks that need
166
+ computed values (allowance after a request, cover per day) go in the script that computes them.
167
+
168
+ **Data that tells the truth** (house rules, from testing; judges checked every one of these):
169
+
170
+ - **A fact shown twice is one variable.** A time window, a total or a state that appears in two cards
171
+ (the battery full 13:30-16:30 in the KPI label, the shaded span and the battery card) is one value in
172
+ the data file, and the copy and the chart annotation are both built from it. Two cards that
173
+ disagree by half an hour cost more trust than a missing card.
174
+ - **Totals and deltas come from the parts as shown.** Sum the rounded pennies the screen displays,
175
+ never round the unrounded total separately: £21.68 + £8.34 − £3.81 is £26.21, and a screen that
176
+ says £26.22 is caught. A change is the difference of the two values on screen (£5.28 against
177
+ £5.22 is +£0.06, not +£0.07).
178
+ - **Every relative figure names its baseline** in the same phrase: "3 h 40 m before close", "45 m
179
+ earlier than last Sunday", "+5 on the usual Monday". "Early", "up" or a bare "+5" next to another
180
+ time or figure reads as measured against that one.
181
+ - **One name per time.** Shops close at 15:00 and the tills are cashed up at 15:12; the header and
182
+ the card use the same words for the same moment, and an error state rewrites the status line.
183
+ - **If a caption has to say which bars are which, encode it in the chart instead**: a marked period in
184
+ a second tone with its own legend entry, a signed axis, a label on the mark.
185
+
186
+ ### 2.2 Name the screen's one question
187
+
188
+ Every screen answers one question first: "Did today's sales come in?", "Which deploy broke?", "Who is
189
+ waiting for a reply?", "How much of this month's plan is left?". Write it in one line. It decides
190
+ three things:
191
+
192
+ - **what is biggest.** In the study the largest block is always the one that carries the screen's
193
+ question, whatever form it takes (a chart, a plan, a ring, a list). The same holds for figures:
194
+ the largest figure on the screen answers the question the title row's sentence answers. In testing,
195
+ an 88% sun ratio at 32px out-shouted the 24px charging window the title led with;
196
+ - **what comes first** in the reading order;
197
+ - **what is left out.** The studied settings page shows three usage numbers and links to the
198
+ analytics screen instead of drawing a chart; four screens draw no chart at all because a few
199
+ numbers say it.
200
+
201
+ Then name the screen's **one finding**: the fact in today's data that most needs attention ("9 no-shows
202
+ while 8 people waited for a place", "the 23:28 deploy doubled the error rate", "eating out is £36 over").
203
+ Put it where it is read first, as the line under the title or the subline of the headline figure,
204
+ next to the action it drives. In testing, the finding that mattered sat in a 14px caption at the
205
+ bottom of a card and the screen read as flat.
206
+
207
+ **Do not rebuild a studied screen.** When the product is of the same kind as a screen in the study (a
208
+ finance home, a deploy overview), its arrangement is the trap: judges recognised the copies at once.
209
+ Take the structure from the product's own things instead: for a couple's budget, Mia, Joint and Tom
210
+ as three columns running through accounts, plan and bills; for a running club, the pace groups.
211
+
212
+ Then list the screen's blocks as the answers to its next questions, one line each, the way the page
213
+ run lists claims. A block with no question is deleted. This is how you avoid the stock order of KPI
214
+ row, big chart, two small charts, table.
215
+
216
+ Three more lines, each tested:
217
+
218
+ - **Everything the brief names is on the first screen.** At 1440×900, every block the brief asks for
219
+ shows its header and its first rows or its figure. Size the headline block to the question (about
220
+ 200-360px tall), cap long lists at 4-6 rows with "View all", and put time-sensitive blocks (bills
221
+ due, SLAs running out, a failed deploy) before long tables. A chart whose line is flat for most of
222
+ the window does not get the full width: give it two-thirds and put the next answer beside it.
223
+ - **The most frequent job is one click away.** Name it ("pack the orders due today", "reply to the
224
+ oldest breach", "redeploy the failed build") and put its control where the answer shows: a primary
225
+ button in the title row, an action on the row that needs it, a "View logs" on the failed item. A
226
+ screen with no control for its main job reads as a report, not as a tool.
227
+ - **Show the evidence beside the answer.** A judge trusts "Error rate 0.28%" more with its spike
228
+ annotated ("peaked at 3.9% after the 23:28 deploy, reverted") than with the number alone. One line
229
+ of explanation on the event that matters is worth more than a second chart.
230
+
231
+ ### 2.3 Choose a style
232
+
233
+ ```bash
234
+ node <skill>/scripts/draw.mjs --app --kind <kind> --brief "<one line about the product>" \
235
+ --screens <screens> [--theme light|dark] [--keep palette,type] --options 3
236
+ ```
237
+
238
+ This deals up to three styles from `library/app.json` (fewer when only two suit the kind and the
239
+ theme). `draw.mjs --app --list kinds` (or `styles`, `screens` or `signatures`) prints the choices; the
240
+ screens are `overview`, `analytics`, `list`, `detail`, `settings`, `wallet`,
241
+ `builder`, `inbox`, `home` and `report`. The library holds seven styles, each distilled from the
242
+ studied screens that share its move:
243
+
244
+ | Style | Theme | For | The move |
245
+ | --- | --- | --- | --- |
246
+ | `achromatic-ledger` | light | money homes, reports, settings with usage | No colour in the chrome; charts in ink; one small signal where a figure changed |
247
+ | `framed-sheet` | light | B2B analytics, developer platforms, builders | One tinted L-frame; the page on a white sheet inset 8px, no shadow |
248
+ | `accent-ladder` | light | creator and small-business admin with plans | The full hue on small marks only; its pale tints on every area |
249
+ | `editorial-greeting` | light | team and personal homes | The greeting as the h1 in a centred 12-column column; every figure at regular weight |
250
+ | `pastel-consumer` | light | wallets, budgeting | Pale same-hue tiles under one large radius; quiet money polarity |
251
+ | `true-black-flat` | dark | community, events, media | Elevation by lightness alone; colour only on data |
252
+ | `data-terminal` | dark | markets, monitoring | Every selection is the same 1px accent line; signs, not colour, on numbers |
253
+
254
+ Choose by how the product is used (long sessions or a quick look, money or media, a team or one
255
+ person, day or night), not by what is most familiar, and write one line on why. Then deal the sheet:
256
+
257
+ ```bash
258
+ node <skill>/scripts/draw.mjs --app <the same arguments, without --options> --style <id>
259
+ ```
260
+
261
+ The sheet gives the style's tokens and type, its shell and one pattern for each screen you named.
262
+ Keep the style's one move intact and take every other value from the defaults in this file. Redraw
263
+ (`--redraw style | shell | screen:<name>`) only for a reason you can state: it contradicts the brand,
264
+ or the product is used in a way the style does not suit. With an existing brand, pass
265
+ `--keep palette,type`, map its colours onto the roles in §9 and keep the style's colour budget.
266
+
267
+ **Then choose its face, before any markup.** The sheet's "Its face" list gives two or three ways this
268
+ style takes a face from the brief, and "Signature elements" lists the library's elements whose words
269
+ appear in the brief (a power flow for an energy home, a sell-out strip for a bakery, a cover matrix
270
+ and a kind-encoded timeline for a leave planner). Write in your notes, next to the screen's question:
271
+ the face you chose, the signature element (from the sheet, or your own built from the product's
272
+ things), and where each appears on the first screen. A style dealt to two products must not give them
273
+ the same face: in four rounds, the screens that skipped this step were scored as the same kit.
274
+
275
+ ### 2.4 Build the shell
276
+
277
+ Build the frame first, empty: the sidebar or rail, the top bar if the shell has one, the canvas with
278
+ its gutters, the title row (§3 and §4). `<skill>/assets/app.css` is a neutral start for all of it:
279
+ copy it into the project and put the sheet's tokens in its `:root`. Look at it at 1440 and at 390 before any data goes in. Do the
280
+ grid arithmetic now and write it in a comment: the column count, the gutter, and the sum that proves
281
+ the cards land on the canvas edges.
282
+
283
+ ### 2.5 Put in the data
284
+
285
+ Render every block from the dataset; draw the charts from it too, with `<skill>/assets/charts.js`
286
+ (`Charts.line`, `Charts.bars`, `Charts.diverging`, `Charts.ring`, `Charts.barList`, `Charts.plan`,
287
+ `Charts.bullet`, `Charts.timeline`, `Charts.matrix`, `Charts.timeStrip`; the file's header lists their
288
+ options) or your own SVG to the rules of §6, never a chart library's defaults and never a picture of a
289
+ chart. The newer helpers return `{ svg, legend }`: put that legend in the card's header rather than
290
+ drawing your own, so each swatch is the mark it explains. Format every figure by §7.4: separators, fixed decimals per
291
+ metric, a sign on every change, units as smaller grey suffixes, tabular figures, right alignment in
292
+ columns. Use the product's own words for labels. No placeholder data: the inspector fails lorem ipsum,
293
+ Acme, John Doe and their kind. Proof is not invented here either: no vanity totals, no "+12%" on an
294
+ account that is a week old.
295
+
296
+ ### 2.6 Build the states
297
+
298
+ For every block, build its empty, zero, loading and error state (§11); for every row and control, its
299
+ hover, selected, focus and disabled state. Look at each one in the browser. A screen that only works
300
+ with full data is half built.
301
+
302
+ ### 2.7 The check
303
+
304
+ ```bash
305
+ node <skill>/scripts/lint.mjs --app <source files or folder>
306
+ node <skill>/scripts/inspect.mjs --app <url or path/to/index.html>
307
+ ```
308
+
309
+ A sheet dealt with `--app` switches both tools to the app rules by itself. The inspector opens the
310
+ screen at 1440, 768 and 390 and measures what this chapter asks for: an h1 (and reports it as the
311
+ screen's hero); a sidebar that folds on the phone; the canvas used to its right edge; panel shadows
312
+ and borders; the number of corner radii; cards in one row that end apart, where a column of cards
313
+ stacked with the gutter counts as one block (`ragged-row`); a blank band inside a card of over 40px,
314
+ or over 64px before a new section's heading (`panel-void`); icons in tinted squares; numeric alignment and tabular figures; chart hues; colour
315
+ share, and a screen with charts but no hue on its data (`no-data-hue`); placeholder data; text under
316
+ 11px; and the page rules that still hold (contrast, gradients, the banned palettes, emoji). Fix every
317
+ `FAIL`. Treat each `WARN` as wrong unless you can defend it to a designer in one sentence.
318
+
319
+ Then look at the screenshots, every width, and answer these in writing. This is the critique for an
320
+ app screen: the caps in `critique.md` for pictures, motion and the page's live element are page rules
321
+ and do not apply here.
322
+
323
+ 1. Is the screen's question answered by the biggest thing on it, and is that read first? Is the
324
+ largest figure the one that answers the title row's sentence?
325
+ 2. Does every block share the screen's edges? Is there a dead strip on one side, a card stopping
326
+ short, an orphan cell, a stretched card with a blank band (a legend pinned to its foot, four rows
327
+ in a card kept at its neighbour's height)?
328
+ 3. Is colour only on data, on status and on the one primary action, and does the main data element
329
+ carry the one hue? Does the face you chose show on the first screen?
330
+ 4. Do the numbers add up, and do they line up digit for digit? List every fact that appears twice
331
+ and check that the copies agree; recompute each total and change from the values as displayed;
332
+ check that every relative figure names what it is against.
333
+ 5. Does every zero look like a zero and every missing value like a dash? Does every count badge sit
334
+ on a queue that needs action, with its noun clear from the label?
335
+ 6. Does every legend swatch match the mark it explains, and does any caption have to say which bars
336
+ are which (then encode it in the chart)? Does any label collide with a line or another label?
337
+ 7. On the phone, is the navigation folded away, and does each block still answer its question?
338
+
339
+ Fix the worst three, inspect again, look again. Three rounds at most. Judge the pictures: if a problem
340
+ shows in a screenshot, it is real, whatever the code says.
341
+
342
+ ### 2.8 Report
343
+
344
+ Tell the user, briefly: the style dealt (name and seed) and any redraws with their reasons; the face
345
+ you chose and the signature element; each screen's one question; any check you allowed and why (for example `--allow icon-chips` for node-type
346
+ tiles in a builder); and the sample data that must be replaced with real data, listed so it can be
347
+ found.
348
+
349
+ App screens have no motion floor. Motion is feedback: press, hover, focus, a menu or a sheet opening,
350
+ a row arriving. Nothing on the screen performs an entrance (house rule).
351
+
352
+ ## 3. The shell
353
+
354
+ ### 3.1 Five archetypes
355
+
356
+ | Shell | In the study | What it is |
357
+ | --- | --- | --- |
358
+ | **Open plane** | 5 screens | A labelled sidebar on the page ground (or within 1-2% of it), separated by nothing or by one 1px hairline. No top bar: the header and the cards sit on the ground. The canvas is fluid with a 24-64px gutter, or a centred column. |
359
+ | **Tinted frame, white sheet** | 8 screens | Sidebar and top bar share one tinted ground (#f6f6f6-#f9fbfc) with no rule between them; the page sits on a white sheet inset 8px from the window's right and bottom edges, radius 10-16 (median 16), a 1px #eaeaea-#ededed edge and no shadow. Variants: a flush L-frame, the inset sheet, and floating panels inset 8-12px with a 12px gap. |
360
+ | **Ruled T-frame** | 4 screens | A 210-240px sidebar and a 64px top bar on one ground, divided only by 1px rules. The workspace switcher sits at the top bar's right end behind a full-height divider. Three of the four are dark. |
361
+ | **Icon rail** | 3 screens | An unlabelled rail 50-60px wide (median 55); 15-18px icons on a 34-49px pitch; the active item marked by colour or by a 2% tint band; groups split by 20px hairlines. It saves about 180px of width. |
362
+ | **No sidebar** | 3 screens | A 46-48px top bar over a centred 1088-1208px column with 152-212px gutters; the logo sits on the column's left edge. For reports, viewers and products with few destinations. |
363
+
364
+ All six dark screens use one ground everywhere, divided by 1px rules of #161616-#232323 or by nothing.
365
+ No screen in the study puts a dark or saturated sidebar against a light canvas (0 of 17).
366
+
367
+ ### 3.2 Sidebar
368
+
369
+ - **Width.** Labelled sidebars run 210-292px; the median is 230 and most sit at 224-240. One floating
370
+ sidebar card appears (280px wide, 40px in from the window edge).
371
+ - **Rows.** A 32px hit area on a 34px pitch is the mode (7 screens); the roomy versions run 40-52px on
372
+ a 42-60px pitch. Icons are 14-20px, median 16, outline at about 1.5px stroke on 14 of 16 screens.
373
+ Labels are 14px at 400 on 12 of 16, in ink or in a grey of #4b4d4f-#63666e, about 8-10px after the
374
+ icon, with the label column at x 36-48.
375
+ - **Active item.** A neutral grey pill with the label unchanged, on 8 screens: radius 4-16 (median 8),
376
+ inset 8-14px from the sidebar's edges, a fill of about #e9e9e9-#ededed. On dark, brightness alone:
377
+ the label goes from #bbb to #fff (3 screens). Colour alone on the icon or label (3, all of them
378
+ rails or a floating card). A tinted accent fill (3). A left accent bar once in 23. The weight
379
+ changes on 2. Default: the grey pill on light, brightness on dark.
380
+ - **Groups.** Sentence-case grey labels at 12-13px, never uppercase (9 screens), with 22-56px of air
381
+ above and 13-33px to the first item; or hairlines instead (4). Utilities such as settings and help
382
+ pushed to the bottom (5).
383
+ - **Top and bottom.** The workspace or account switcher at the top of the sidebar (7 screens), at its
384
+ bottom (2), or in the top bar. The bottom holds a user row (8) or one upsell (8); one of those
385
+ upsells is a filled accent button.
386
+ - **The product is named** (house rule, from testing). The product's mark and name sit at the top of
387
+ the sidebar or rail, and the scope (workspace, team, project, account) is shown as a switcher or a
388
+ breadcrumb. A screen whose product cannot be named from the screenshot reads as a template.
389
+ - **Counts on nav items** (house rule, from testing). A count appears only on a queue that needs
390
+ action, and its noun is clear from the label: "Requests 5", "Price changes 3". A bare "Range and
391
+ prices 9" left the judge asking nine of what.
392
+ - **Labels by default.** A labelled sidebar unless the product has five destinations or fewer and the
393
+ screen needs the width (a research or monitoring view); an icon rail always carries the product's
394
+ mark at the top, a tooltip and an accessible name on every icon. Nav items are other screens, never
395
+ anchors into the current page (a sidebar that scroll-spies one long page was marked down twice).
396
+
397
+ ### 3.3 Top bar
398
+
399
+ 14 of 23 screens have one; the default is none. Heights fall into two groups: 44-51px (median about
400
+ 48) on light chrome, and 64px, usually with a 1px rule. A top bar must hold something real: search,
401
+ the workspace switcher, or the page or object name. Search sits centred on the window at 548x32 with
402
+ a shortcut hint (2 screens), or at 457-537x36 in a no-sidebar bar. The right cluster is inset 24-46px
403
+ from the edge. Two screens leave about 1070px of their top bar blank; both are flagged for it.
404
+
405
+ ### 3.4 Right rail and pinned columns
406
+
407
+ One screen has a right rail: a fixed 384px column in a `1fr 384px` grid with a 24px gap, starting
408
+ level with the first card rather than with the title, its section headings outside the cards and 8px
409
+ above each. Use one only for a stable secondary stream: recent items, the details of the selected
410
+ object, share links. A pinned left column appears once: a 306px accounts card at the viewport height
411
+ minus 72px, so net worth stays in view while the rest of the screen scrolls.
412
+
413
+ Five screens float a button (24-56px), and one of those buttons covers the content it sits on and is
414
+ flagged. House rule: no floating button unless it is the screen's one primary action and covers
415
+ nothing at any width.
416
+
417
+ ## 4. The canvas and the page title
418
+
419
+ ### 4.1 Width and gutters
420
+
421
+ - **Fluid** (14 screens): side padding 17-64px, median 29, with 24 and 36-40 the common values;
422
+ content 1120-1312px wide, median about 1204.
423
+ - **Centred** (8 screens): 624, 864, 1088, 1100, 1152, about 1190 and 1208px; median about 1126.
424
+ Data pages land at 1100-1250 either way. Only two personal homes go narrow (624 and 864), and both
425
+ are flagged for wasting the width.
426
+ - **Top offset**, from the canvas top to the title: 20-88px, median about 36. Tools sit at 20-36;
427
+ greeting homes at 50-88.
428
+ - **One gutter.** Use one gap value horizontally and vertically. Mixed gutters (12 against 16, 20
429
+ against 24, 16 against 12) are flagged on 8 screens.
430
+
431
+ ### 4.2 One left edge, one right edge
432
+
433
+ The strongest screens run a single left edge from the header to the last row. One indents its page
434
+ header by the cards' 24px padding, so the title, the card titles, the numbers and the chart all start
435
+ on one line. Row rules may bleed 7-8px past the text column while the text stays on it.
436
+
437
+ The grid's arithmetic closes: 3 x 372 + 2 x 17 = 2 x 568 + 16 = 1152; 12 x 77 + 11 x 16 = 1100;
438
+ 4 x 144 + 3 x 16 = 624; a second-row card exactly as wide as the two cards above it
439
+ (251 + 24 + 515). Write your sum down.
440
+
441
+ Failures to avoid, all from the study: cards stopping 120px short of the sheet's right edge; a 0px
442
+ right gutter against a 40px left one; a column centred on the window instead of on the area beside
443
+ the sidebar (204px on its left, 444px on its right); a medallion 108px off the column's axis. The
444
+ inspector warns when the content stops well short of the right edge.
445
+
446
+ **Dead space from a grid that does not fit the data** is the commonest failure in the study (10
447
+ screens): four KPI tiles in a three-column grid, orphaning the fourth; one card alone in a
448
+ three-column row beside 810px of nothing; a card stretched to its neighbour's height with 250px of
449
+ blank under its legend. Choose the column count from the number of items, let a lone card span, and
450
+ do not stretch a card's frame over empty space.
451
+
452
+ **Cards that share a row share a bottom edge.** In testing, rows whose cards stopped 26-190px apart
453
+ were marked down every time, by judges and by the inspector (`ragged-row`). Balance the row by its
454
+ content first: move a list's rows so the two columns hold the same number, cap both lists at the same
455
+ count, or pair blocks of similar height. Two cards stacked in one column beside a tall card count as
456
+ one block: they balance when the column ends level. Only when the contents cannot balance, stack the
457
+ two blocks, or let the shorter card fill the row height with its content top-aligned and the footer
458
+ action (a "View all", a total) pinned to its bottom so the extra height is not a hole.
459
+
460
+ **A stretched card stretches only when it has content to fill.** Only an action or a total may be
461
+ pinned to a stretched card's foot; a legend or a note stays directly under its chart. In testing, a
462
+ cover card stretched to its neighbour with its legend pinned to the bottom left 60px of blank under
463
+ the last row, and a sell-out card left 45px above its links. When the content is short, let the card
464
+ keep its own height (`align-items: start` on the row), move its footer link into its header, or give
465
+ the row a block of similar height. A filtered block shrinks to its rows, or keeps a fixed number of
466
+ rows with one sentence in the empty ones; four rows over 270px of empty card is a hole. The inspector
467
+ warns on a blank band of over 40px inside a card (`panel-void`).
468
+
469
+ **Narrow blocks do not span the canvas.** A table of five columns or fewer, or a list of six rows or
470
+ fewer, runs to about 760px at 1440 and pairs with the next block; stretched to 1300px it leaves
471
+ 400-600px voids between a name and its first figure.
472
+
473
+ ### 4.3 The title
474
+
475
+ - **Every screen has one h1**; the inspector fails a screen without one. 14 screens set it in the
476
+ canvas at 18-48px, median and mode 24, at 600-700 (700 on 8). The rest have nothing over 16px: a
477
+ breadcrumb or the top bar names the page. Then the breadcrumb's last item is the h1, at 16px, and
478
+ the screen's name is still the first thing read.
479
+ - **A noun, not a greeting**: "Analytics", "Overview", the project's or the object's name. 3 of 23
480
+ greet, and one adds an emoji, which goes. A greeting suits a personal or team home only.
481
+ - **An optional second line**: one 14-16px grey sentence about the data or the object (the finding,
482
+ the period, the scope), never about the interface ("the filters narrow every block…", "this page
483
+ shows…" read as instructions, not a product), or a 12px line
484
+ naming the data's source.
485
+ - **Right of the title**: actions only when they are real (10 screens); otherwise nothing. A freshness
486
+ stamp ("Updated Jul 27, 4:09 PM", with a refresh button) on 6.
487
+ - **The primary action.** 12 of 23 have no filled primary button; 5 make it near-black (#1d1f20,
488
+ #1f2937) or inverted white on dark; 4 fill it with the brand hue. One primary per screen.
489
+
490
+ ### 4.4 Tabs, filters and the date range
491
+
492
+ - **The date range** at page level (7 screens) or on each card (7), never both. A card that states its
493
+ own period puts it in its header, right-aligned, in grey.
494
+ - **Underline tabs** (8 screens) always sit on a full-width 1px rule; the indicator is 1-4px (median
495
+ 2), as wide as the label or running 8-11px past it.
496
+ - **A segmented track** once: 48px, #f3f4f6, a white 36px active pill, and the date select inside its
497
+ right end, so tabs and range read as one row. A segmented control is as wide as its options, and full
498
+ width only below about 480px: three options spread across a 680px tablet card read as a progress bar.
499
+ - **Control height** in title and filter rows: 28-40px, median 34, clustering at 32 and 36.
500
+ - **Order**: scope on the left (the date first, then the filters), utility and refresh on the right.
501
+ - **Compound filters** that read as a sentence ("Date | Jun 14 - Jul 13 | Daily"), 28px tall and 8px
502
+ apart, once.
503
+ - **To the first card**: 13-64px, median 24.
504
+
505
+ ## 5. KPIs
506
+
507
+ - **No tile of its own.** 11 of the 20 screens with headline numbers give a KPI no tile: bare text on
508
+ the page or on a card (5), or one container split by 1px hairlines (6). 9 use one card per KPI,
509
+ 61-147px tall (median about 108). The default is one container split by 1px dividers into equal
510
+ columns. 7 screens have no KPI row at all and put each headline number in the card that explains
511
+ it, which is often better.
512
+ - **Count.** 1-6 per row, median 3-4. The count matches the grid: four KPIs get four columns.
513
+ - **Size.** Values 16-40px, median 26, mode 24. Values in their own tile run larger (median 30) than
514
+ in a shared strip (median 24). Nothing at 48px or over. Labels 12-16px, median 14; the value is
515
+ about 1.7 times the label.
516
+ - **Weight.** An even split: 400 on 8 screens, 600 on 6, 700-800 on 6. A large number at regular
517
+ weight under a semibold label is the common pattern. Bold for money only.
518
+ - **Order.** Label above the value on 14 screens; labels grey (#6b6b6b-#aaa) on 13; sentence case.
519
+ - **Nothing else.** No icon in a coloured circle (0 of 23), no sparkline (0 of 23), no tinted tile.
520
+ An info icon beside the label is fine (5 screens). Units are a smaller grey suffix: "5 mins" at 24
521
+ over 14, "2 m 24 s", "5 /10".
522
+ - **The answer figure leads.** When one figure is the screen's answer (a balance, net worth, the
523
+ portfolio's value), it is 30-36px and at least 1.3 times its sibling figures (those at 18-24px). In
524
+ testing, a 24px portfolio value beside two 24px figures left the screen without a lead. No other
525
+ figure on the screen is larger: the biggest number answers the title row's sentence, so a
526
+ secondary ratio in another card stays at the siblings' size.
527
+ - **One figure, one place.** A figure shown in the strip is not repeated in a legend beside it, and a
528
+ KPI strip whose every cell names a panel below (RSVPs, then an RSVPs panel) is dropped: lead each
529
+ panel with its own number instead.
530
+ - **A second job.** KPIs may be the chart's series tabs or the list's type filter (the selected card
531
+ takes a 1.5px border). As tabs, the selected one carries a 2px rule or the active fill and an ink
532
+ label; the others keep a grey label and their value in ink, at 400 against the selected one's 500.
533
+ A grey value reads as disabled: in testing, three shops' takings set in grey because they were tabs
534
+ read as secondary, though they were the brief's first ask. When the tabs are the per-entity
535
+ breakdown the brief asks for, grey nothing and let the rule alone mark the selection. On a phone the
536
+ tabs become a 2-up grid with the selected cell filled, or a row that scrolls sideways; never an
537
+ underline floating inside the grid (`app.css` does both).
538
+
539
+ ### Deltas
540
+
541
+ - Optional: 9 of the 20 KPI screens show one; 11 do not.
542
+ - 10-15px (median 14), never larger than the label. Text or a small glyph on 6 screens; a pale pill
543
+ on 3.
544
+ - **The window in words**: "vs prior 30 days", "in the last 90 days", "from 0 (last 4 weeks)" (7 of
545
+ the 9).
546
+ - **Colour only the number**, or set the whole delta in grey.
547
+ - **Colour says good or bad, not up or down** (house rule, from testing). Every metric has a good
548
+ direction: latency, error rate, cost, churn and time-to-reply are better when they fall. A change
549
+ in the bad direction puts `--negative` on the number (or a small down-pointing glyph in that
550
+ colour); a change in the good direction is `--positive` or grey. A judge read a 2.5× rise in errors
551
+ set in the same grey as a rise in visits as hiding the screen's only bad news.
552
+ - **Zero or undefined change is grey.** The study's commonest KPI failure is a zero or undefined change
553
+ shown as a signal: three identical green "up 100%" pills grown from zero, a ">999%", a bold red
554
+ "0.00%", a green "+0". When the prior period was zero, write "+4 (new)"; when there is nothing to
555
+ compare, a short grey dash where the delta would be.
556
+
557
+ ## 6. Charts
558
+
559
+ ### 6.1 Which chart for which question
560
+
561
+ | Question | Form | In the study |
562
+ | --- | --- | --- |
563
+ | Is it moving over time? | One line; an area only with a fill of 15% or less | 9 screens |
564
+ | How much per period? | Columns with square corners | 3 |
565
+ | How is it distributed? | A histogram with equal bins | 1 (its unequal bins are flagged) |
566
+ | Who ranks? | A sorted horizontal bar list, or the row's fill as the bar in a one-figure list | 3 |
567
+ | What share? | A thin ring, or a 100% stacked bar with 2px seams; five parts at most | 5 |
568
+ | How far to the target? | A progress bar, both ends labelled, the fill the true ratio | 4 |
569
+ | How much of the plan is used? | A track as long as the plan, the spent part filled, what is already committed as a lighter segment, an overrun past the track's end in the negative colour (`Charts.plan`) | house rule |
570
+ | Has it drifted from its target? | One row per part: the current share as a bar with a 1px tick at the target (`Charts.bullet`); never two stacked bars to compare | house rule |
571
+ | Where? | A map with a list beside it; the list carries the magnitudes | 1 |
572
+ | Per period, and the running total? | The two side by side at equal width, with the same dates | 1 |
573
+ | Which way did it flow, and how much? | Columns above and below one zero line on one scale, the axis signed and captioned on each side ("Sold" above, "Bought" below), a marked period in a second tone with its own legend entry (`Charts.diverging`) | house rule |
574
+ | Who is away when? | A timeline of people by day, each kind of booking its own mark (`Charts.timeline`) | house rule |
575
+ | Is there enough cover? | A team-by-day matrix of slack against the minimum (+2, +1, 0, −1), one hue ramping toward the negative colour, the headcount on hover (`Charts.matrix`) | house rule |
576
+ | When in the day, against last time? | One row per item on a shared opening-to-closing axis: a 2px grey track, an ink dot for today, a hollow tick for the comparison day (`Charts.timeStrip`) | house rule |
577
+
578
+ Three more, from testing:
579
+
580
+ - **The pair of per-period bars and the running total is used once per screen**, and only when the
581
+ total crosses a line that matters (capacity, a target). Three such pairs in six charts read as one
582
+ pattern stamped out.
583
+ - **A series that is flat except for one event** gets at most two-thirds of the width and about 140px of
584
+ height, or a range capped at about twice its reference line with the off-scale peak labelled
585
+ (`Charts.line({ max })`). A full-width plot that is 85% empty was the biggest block on a first
586
+ screen and was marked down.
587
+ - **A forecast is not a fact**: after today the line is dashed and the end value is labelled
588
+ (`Charts.line({ today, endLabel })`), with the gap to the target bracketed when there is one.
589
+ - **What the brief asks to see over time is drawn on the first screen.** KPI cells may switch the chart
590
+ only between metrics the brief did not name.
591
+
592
+ When there are only a few numbers, draw no chart: four screens skip it, and the settings page links
593
+ to the analytics screen with "View more".
594
+
595
+ ### 6.2 One question, one series
596
+
597
+ One series per chart is the norm; three is the most any screen draws. To show another metric, switch
598
+ it with a control (a segmented control, a dropdown, the KPIs as tabs) instead of overlaying lines.
599
+ Plots run 112-264px tall (median about 195) and 316-1136px wide (median about 570), an aspect of 1.8
600
+ to 5.2.
601
+
602
+ ### 6.3 Axes and gridlines
603
+
604
+ - **Gridlines** run horizontally only on 7 of the 12 cartesian charts, both ways on 3, and not at all
605
+ on 2. Use 3-5 (the study runs 3-7, median 4-5): 1px, solid, about #e5e5e5 on light (range
606
+ #cfcfd2-#f2f2f2), #2b2b2b on #111. Dashed lines are allowed in chart grids (4 screens: 3/3, 4/4,
607
+ 3/2.5) and nowhere else on the screen.
608
+ - **No y-axis line.** The baseline is the one heavier line (2px on two screens, 1px on one); full axes
609
+ on one.
610
+ - **Y ticks**: 4-7, median 5, at 11-16px (median 12) in grey (#5f5f5f-#6c6c6c), on the left (8
611
+ screens) or the right (2). Round, even steps (0/5/10/15%; 0-600 by 150), the top tick above the
612
+ maximum, integers for counts, and zero as the baseline for bars and counts.
613
+ - **Never without a scale.** Two screens draw no y-scale and show magnitude only on hover; both are
614
+ flagged. So are uneven ticks (0/3/6/10), a 0.8 tick on a count, a top tick equal to the maximum so
615
+ the line hits the plot's edge, and a cumulative axis that starts at 1.
616
+ - **Axis text no larger than the data.** 15-16px ticks beside 14px values are flagged as louder than
617
+ the numbers.
618
+ - **X labels**: 4-8 per chart, flat, never rotated (40 degrees is flagged), the first and last pulled
619
+ inside the plot, on one step all the way: a forced closing label after 14:00 on a 90-minute step
620
+ left a short last gap that a judge measured. Choose a step that lands on the end (hourly from 08:00
621
+ to 15:00) or leave the end unlabelled. Labelling only the two ends hides when things happened. Irregular dates on a
622
+ categorical axis are flagged: time goes on a time scale.
623
+
624
+ ### 6.4 Marks
625
+
626
+ - **Lines** 1-3px, median 2, in straight segments. Four screens smooth their lines, and one smoothed
627
+ curve invents values between daily totals (flagged), so draw straight segments. No point markers,
628
+ except a hover dot (8px on one screen).
629
+ - **Fill**: none on 7 of 10 time charts. At most a flat tint of about 14%, or a fade from the line to
630
+ transparent over 150-200px.
631
+ - **Bars** have square corners (4 screens), or at most a 4px top radius with a square bottom on the
632
+ baseline. Stacked segments are split by a 1-2px seam.
633
+ - **Colour.** One hue per chart. The accent touches only data on 8 screens, and data ink is under 3%
634
+ of the pixels on most. Neutral series are fine and often better: a near-black line that turns pale
635
+ grey after the cursor; a white line against a red one; signs instead of colour ("+$24,000,000").
636
+ But the one hue, when the style has one, goes on the screen's main data element (today's series,
637
+ the booked bars, the current period, the margin that breaks), not on a secondary chart or a delta:
638
+ in testing, an all-ink screen with no hue on any of its data read as a kit.
639
+ One subject keeps one hue across the screen: the same subscribers drawn pink in one chart and indigo
640
+ in the next is flagged. Unrelated hues on one screen (three, five) are flagged every time. Status
641
+ colours are for status. The inspector warns over four hues and fails over six.
642
+ - **Legends.** None for a single series (9 charts): the title or the dropdown names it. Otherwise five
643
+ items at most, as a 5-8px dot with a 12-14px grey label in the card's header, or as a small table
644
+ (dot, name, value, change) that makes the legend carry data. Never list a series that has no data
645
+ (flagged). Every swatch is the mark it explains, scaled down: the legend dot is the line's colour,
646
+ a hatched bar's swatch is hatched. A swatch drawn separately from the mark drifted from it in testing
647
+ (a black outline with a red edge explaining a red outline); the helpers return the legend built from
648
+ the same style object as the marks.
649
+ - **Rings** only for three to five parts of a whole that are not already listed beside them (a ring
650
+ redrawing the spent, due and left figures of the tile next to it was marked redundant). Never
651
+ labelled on the slices; the total sits in the centre or beside the ring. The
652
+ screens noted for their rings use thin strokes: 3-5px on a 90-154px ring, 8px on 182px. Two others
653
+ use 28 and 37px.
654
+ - **Progress bars** are 4-24px tall (median 8), fully rounded, with both ends labelled ("Skilled 200"
655
+ and "Expert 2,000"); the fill is the true ratio, so 303 on that scale fills 22px of 392. A zero has
656
+ no stub (a 6px stub at zero is flagged).
657
+ - **Tooltips** are bare text or a plain box without an arrow: label and value on one line.
658
+ - **Annotate the event that matters.** A step or a spike more than about three times the usual change
659
+ gets a 1px marker and a 12px label naming its cause ("Deploy a3f09c1", "Newsletter featured");
660
+ reference lines (a budget, an SLO, a start time) are 1px dashed with their label at the end. In
661
+ testing, an unexplained jump was the first thing a judge asked about. `Charts.line`,
662
+ `Charts.bars` and `Charts.diverging` take `annotations` and `reference`.
663
+ - **Labels never collide.** Annotation labels sit in rows above the plot, each beside the top of its
664
+ own leader line, and no leader line runs through another label; the rows are reserved only when a
665
+ label exists, so a chart without one has no dead band above it. The "Now" label of a forecast goes
666
+ on whichever side of its line the series does not cross. Lay labels out after the fonts load, or
667
+ the label set changes between loads (it did in testing). The helpers do all of this; give a label
668
+ that may not fit a `short` form.
669
+ - **Use the helper, then extend it.** Draw charts with `assets/charts.js` and add what a chart needs to
670
+ it, rather than writing new axis code: in testing, every chart written from scratch on a phone put
671
+ its y labels on top of its line.
672
+ - **Short and empty histories are drawn honestly**: a flat zero line with one spike, missing bars for
673
+ empty periods, no padded y-range, no "No data" picture. Do not give one point the screen's largest
674
+ plot, though: a lone dot in a full-size grid reads as barren (flagged once).
675
+
676
+ ## 7. Tables and lists
677
+
678
+ ### 7.1 Rows
679
+
680
+ - Single-line data rows: 36-53px, median 45.
681
+ - Two-line rows with media: 56-92px, median 72. The pitch is the media's height plus 24-32px
682
+ (48 + 24, 48 + 32, 50 + 30).
683
+ - Key-value and legend rows inside cards: 21-32px.
684
+ - In a two-line cell, line 2 sits about 21px below line 1 (19-23), one size smaller (12-14px) and
685
+ grey. Two-line labels need a 40-44px pitch at least: on a 32px pitch a subline nearly touched the
686
+ next row's name and the list ran together (house rule, from testing).
687
+ - Overview lists show 2-5 rows.
688
+
689
+ ### 7.2 Header
690
+
691
+ - 11-14px, median 12, mostly regular weight, grey, sentence case (9 of the 11 headed tables). The one
692
+ uppercase header in the study is flagged as louder than the data.
693
+ - **No fill band** (0 of 11) and **no rule under it** on 8 of 11. Where there is a rule, it is the
694
+ strongest line in the table (#e5e7eb over #f3f4f6 row rules).
695
+ - Header row 36-40px.
696
+ - Numeric headers are right-aligned and flush with their values; a header that stops 15px short of
697
+ its column is flagged. A header over a control aligns with the control it labels (centred over a
698
+ column of steppers), and a delta beside a stepper gets its own narrow unlabelled column; three
699
+ alignments in one header row were flagged.
700
+ - A sort glyph on the active column only.
701
+
702
+ ### 7.3 Dividers
703
+
704
+ - **No zebra striping** (0 of 23).
705
+ - No row dividers on about half the lists; they rely on a 61-92px pitch or on 2-8px gaps between
706
+ filled rows.
707
+ - When present: 1px, 3-7% darker than the surface (#ededed-#f4f4f4 on white; #161616 on #000,
708
+ #1b1a1f on #131217).
709
+ - Extent: bleeding 8-9px past the text edge; starting at the text column and skipping the media; or
710
+ the full inner width. Pick one per screen.
711
+
712
+ ### 7.4 Figures and alignment
713
+
714
+ - **Numbers right-aligned**, in tabular figures or a monospace. Every left-aligned numeric column and
715
+ every column of proportional digits in the study is flagged (durations "00:00:12" and "00:00:04"
716
+ that jitter, cents that drift).
717
+ - **Fixed decimals per metric**: money 2, percentages 1 or 2, counts none. Thousands separators
718
+ everywhere ("$16,531.54"); abbreviate only in a capacity line ("12.7k of 20.0k"). A sign on every
719
+ change ("-$0.09", "+10,100 (+0.20%)"). No space after the currency sign (one screen's "$ 89.00"
720
+ beside "$15.00" is flagged).
721
+ - **The identity column gets the most width**, about a third to a half of the table, and it is never
722
+ the one cut off at desktop width: shorten names editorially first (drop the issuer every row
723
+ shares, the share class, "Ltd") and use the same short name at every width.
724
+ - **One right edge per row or card**: every right-aligned figure inside a card or row ends on the same
725
+ padding line (a days-in-stage figure 18px short of the value above it reads as a second edge).
726
+ - **Two measures stack in one cell** rather than taking two columns: a count over its 12px grey
727
+ percentage, a date over its time, a money value over the amount in units, both lines on one right
728
+ edge.
729
+ - **Dates** in ISO form and right-aligned where rows are compared ("2024-02-15"); in words for
730
+ recency ("Today", "Yesterday", "6 days").
731
+ - **IDs** in a monospace at body size, truncated to about 8 characters with an ellipsis and a copy
732
+ icon 12px after.
733
+ - Truncate to one line with an ellipsis; never break inside a word.
734
+ - **A breakdown in a narrow card** ("Headingley 6 · Chapel Allerton 5 · Meanwood 3") goes in fixed
735
+ mini-columns, or each item is `nowrap` with its separator attached to the next item, so no line ends
736
+ on a dangling "·".
737
+ - **An edited cell shows that it changed** (house rule, from testing). In an editable grid a changed
738
+ value carries a mark (a dot, a tinted border), and the column header or a caption names the
739
+ baseline ("vs the usual Monday"); a bare grey "+5" beside a stepper was read as noise.
740
+
741
+ ### 7.5 Ink inside rows
742
+
743
+ - Only the identity and the key number get the primary ink; everything else is grey ("5" in ink,
744
+ " /10" in grey).
745
+ - A missing value is a grey dash; a real zero is printed ("$0", "0.00%", "0% (0)").
746
+ - The sign lives in the text, not in the colour: income green with a "+", expenses in ink, no red on
747
+ every negative.
748
+ - Link colour on the name cell only, with no underline.
749
+
750
+ ### 7.6 Status pills
751
+
752
+ - 15-28px tall (median 20), text 9-14px in the study (median 12) at 500; nothing under 11px here. A
753
+ full pill or a 3-5px tag.
754
+ - A pale tint with dark text of the same hue, optionally a 1px border one step darker: #dcfae5 with
755
+ #04250e, #ffedea with #831c1e.
756
+ - Neutral states are monochrome chips with a glyph ("Public" with a globe).
757
+ - A state machine uses one hue at three intensities: grey for off, the full hue for the call to
758
+ action, a dark tint for running. A saturated fill with white text only for that one call to action,
759
+ and only while it is rare: when more than about a fifth of the visible rows carry it, it becomes a
760
+ stripe of black blobs louder than the data (marked down in testing); use the pale pair or a 6px dot
761
+ with an ink label instead.
762
+ - **One status mark per row.** A tag and a badge that say the same thing are flagged.
763
+ - **A chip is never squeezed.** Tags and pills are `flex: none; white-space: nowrap`: in testing a
764
+ table column collapsed an environment chip to a 12px box with its word spilling out.
765
+
766
+ ### 7.7 Media
767
+
768
+ 16px logos in dense rows; 24-32px avatars; 48-50px in two-line rows. Circles for people, tokens and
769
+ companies; a 2-3px radius for artwork and flags; 8px for photographs. One fixed media slot down the
770
+ list so the text starts on one edge (a 50px slot with the text 16px after it). Media-to-text gap
771
+ 10-16px, median 12.
772
+
773
+ ### 7.8 Actions and paging
774
+
775
+ - **No pagination on an overview** (0 of 23). Cap the rows and link out: "View all" in the section
776
+ header, a 30px outlined button under the list, a full-width 32px bar. State the total ("3 tracks").
777
+ - Row actions: none on 9 screens; otherwise one kebab at the far right. Reserve a trailing action
778
+ column only when most rows carry the action; otherwise the action is an ink text action on the
779
+ row's second line and the figures stay flush to the card edge. When a row needs doing
780
+ (a bill to pay, an order to pack, a failed deploy), its action is a visible ghost button or an ink
781
+ text action in one fixed trailing column, at the same pitch for every row; never muted grey text,
782
+ and never stacked under the amount so the rows change height.
783
+ - Checkboxes only where bulk actions exist (one screen: 18px, 2px stroke, 3px radius).
784
+ - Hover and selected: a 1px outline at 6px radius overhanging the panel by 1px, or a darker border
785
+ with a 1px ring. No hover that changes the fill was seen. In a list that drives a detail pane (an
786
+ inbox, a queue), the selected row takes the `--active` fill of the nav pill instead, so it cannot be
787
+ mistaken for a focus ring or a hover (house rule, from testing).
788
+ - Toolbar: one search, 30-36px tall (256x30, 252x36, 316x32).
789
+ - **A full list screen** (house rule; the study has none): state the total above the table, keep the
790
+ header row in view while scrolling, and page or load more at the end with the range shown
791
+ ("1-50 of 1,284").
792
+
793
+ ### 7.9 Lists that carry data
794
+
795
+ - **The row fill is the bar**: the row's rounded background (radius 8) as wide as its share of the
796
+ largest share; 44px rows, 2px gaps. Only in a one-figure ranking list (a label and one value): in a
797
+ row with several columns or two lines, the fill's edge cuts through the words (failed in testing).
798
+ Planned against spent is a separate 6-8px track under the label (`Charts.plan`).
799
+ - **Bar list**: a 64px pitch, a label line, then a 10px pill bar with the value 5px after its end; the
800
+ longest bar about 88% of the width; one colour, no track.
801
+ - **Inline bars in a list are thin and grey** unless they are the screen's main series: 2-3px at
802
+ most. A ranked list of money in a narrow card carries a 2px proportional bar under each label, grey
803
+ with the top item in ink (`Charts.barList(el, rows, { thin: true })`), so "most costly first" is
804
+ seen and not only read. In testing, six 4px black bars were the loudest marks on the screen.
805
+ - **A timeline draws its comparison.** When the brief asks "against last Sunday", the comparison is a
806
+ mark on the same axis (`Charts.timeStrip`: an ink dot for today, a hollow tick for the comparison
807
+ day), not only a line of text.
808
+ - **Legend as table**: dot, name, pill, value and change on a 57px pitch.
809
+ - **Key-value well**: a tinted well, radius 8, 32px rows, label left, figure right.
810
+ - **Feed as row cards**: 63px tall, 8px gaps, radius 14, a fill one step lighter and a border one step
811
+ darker than the panel, a relative date on the right.
812
+ - **Tree**: no dividers, 8px of indent per level, ink against grey by level, a pitch of about 30px,
813
+ about 45px between groups.
814
+
815
+ ## 8. Forms and settings
816
+
817
+ The study holds forms on three screens and one settings page, so this section rests on little. It is
818
+ enough for the defaults.
819
+
820
+ ### 8.1 Fields
821
+
822
+ - **Label above the field**, 14px at 500, 8-10px gap. No floating labels and no placeholder standing
823
+ in for a label.
824
+ - **Inputs** 38-40px in forms (radius 8-10); toolbar and filter controls 28-40px, median 32. One
825
+ control height per context.
826
+ - Inputs stay white with a 1px #e5e7eb-#e8e8e8 border even on a grey panel; filter and select
827
+ controls take a border one step darker (#cdcfcf-#d1d5db).
828
+ - A leading icon at 14px, 13px in from the edge, with the text starting at 38px.
829
+ - **Spacing**: 24px from a description to the first label, 16px between fields, 16px to the Save
830
+ button.
831
+ - **A joined input and action** (a read-only link and its Copy button) share a border and square
832
+ their inner corners.
833
+ - **Toggles** 28x16 to 33x20. The on colour is a semantic green or near-black, not the brand accent.
834
+ - **Disabled** controls stay legible and say why they are disabled: the study's disabled Save
835
+ (#cecece on #f4f4f4, about 1.4:1) and its plan-locked panel at 30% opacity are flagged as
836
+ unreadable.
837
+
838
+ ### 8.2 Settings layout
839
+
840
+ - Each section is a row: a label column (about 450px: a 16/500 title and a 14px grey description)
841
+ beside a panel (about 700px, #fafafa, radius 16, padding 16, no border, no shadow). The title's cap
842
+ top aligns with the panel's first line, 6-8px below the panel's top.
843
+ - Sections are split by a full-width 1px rule with 32px above and below.
844
+ - A switch row: a 14/500 title, a status badge 8px after it, a 14px grey description, and the toggle
845
+ on the right, 16px from the edge and centred on the title line.
846
+ - A plan-gated feature: a 48px tinted strip with a 32px button directly above the locked panel; the
847
+ panel stays readable.
848
+ - Narrow containers stack: label, 10px, field, then 26px to the next pair.
849
+ - Do not leave the label column empty beside a tall panel (a 250px void is flagged): put the section's
850
+ help or a summary of its current values there, or narrow the column.
851
+ - **Destructive actions** (house rule; none in the study) go last, in a section of their own, as a
852
+ text or outlined button in the negative colour, with the consequence in words and a confirmation
853
+ that names the object.
854
+ - **One view per area** (house rule, from testing). When settings span several areas (general,
855
+ members, billing, notifications), each sidebar item opens its own view (a hash route is enough in
856
+ a static build), with the area's name as the h1. One long page of every area, with the sidebar
857
+ scrolling to anchors, put the first area the brief named four screens down and was marked down.
858
+ - **One save model per view**: every control saves itself and shows a quiet "Saved" stamp, or one
859
+ Save per panel at the panel's bottom right. Never a mix of both on one view.
860
+ - **Show what the setting produces.** Beside the control that changes it, a small preview of the
861
+ result (the invite email, the notification as it will arrive, the plan's next invoice) is the
862
+ product-specific substance a settings screen otherwise lacks.
863
+ - A settings view opens with a usage strip only when usage is its question (a plan or quota view),
864
+ and its figures stay smaller than its h1.
865
+
866
+ ### 8.3 Buttons
867
+
868
+ Controls run 27-40px tall (median 34; 32 is the commonest), with a 6-8px radius in the tight styles
869
+ and full pills in the soft ones. One filled primary per screen, usually near-black; a secondary is
870
+ white with a 1px border; a tertiary is text. The controls in one row share one height.
871
+
872
+ ## 9. Type and colour
873
+
874
+ ### 9.1 Type
875
+
876
+ - **One grotesk.** All 23 screens use a neo-grotesk, and 14 use that one family alone. A second face
877
+ always has one job: a monospace for every number or for IDs only, a serif for one greeting, a brand
878
+ face kept to the wordmark or the switcher. Never three. Axis ticks, chart notes and labels stay in
879
+ the text face even when IDs are in a monospace.
880
+ - **App type is not display type.** The h1 stays at 18-32px and no figure reaches 48px: in testing, a
881
+ 50px serif title and a 76px balance made a budgeting screen read as a landing page (the inspector
882
+ warns at 34px and 48px).
883
+ - **Sizes**:
884
+
885
+ | Role | Range in the study | Median |
886
+ | --- | --- | --- |
887
+ | Page title | 14-48 | 24 |
888
+ | KPI value | 16-40 | 24 |
889
+ | Card title (500-600) | 14-24 | 16 |
890
+ | Body, nav, cells | 13-16 | 14 |
891
+ | Labels, meta | 11-14 | 12 |
892
+ | Axis ticks | 11-16 | 12 |
893
+ | Pills, badges | 9-14 | 11-12 (house floor 11) |
894
+
895
+ A screen uses 4-9 sizes, median 6. The cleanest scales in the study are 12/14/18/24, 12/14/16/30
896
+ and 12/14/16/24.
897
+ - **Weights**: a median of 3 per screen; 10 of 23 never go above 600; 700 does one job per screen
898
+ (money, the greeting or the title).
899
+ - **Figures**: tabular on every number in a table, in a KPI, or anywhere it updates. Check that the
900
+ face really has tabular figures: `font-variant-numeric: tabular-nums` must change its digit widths;
901
+ if it does not, take another face.
902
+ - **Case**: sentence case on about 19 of 23; uppercase content labels on 4 only. Tracking 0, and
903
+ negative only on large type (-0.02em at 32px). Line height 20px for 14px text, 24px for 16px.
904
+ - **Dark** screens set body at 13px on three, and titles at 18-20/600 or 26-28/700.
905
+
906
+ ### 9.2 Colour on light screens
907
+
908
+ - **Ground models**: white cards on an off-white ground (10 screens; #f3f5f7 to #fdfdfd, median
909
+ #f9f9f9-#f9fafb); grey panels on white (6); a framed sheet (7).
910
+ - **The sidebar is never dark or saturated** (0 of 17): it matches the page, sits 1-3 levels off it,
911
+ or is white on a grey page.
912
+ - **Lines in three steps.** Card edges median #eaeaea, the working band #e5e7eb-#ededed (about 1.2:1 on
913
+ white). Row rules one step lighter, #efefef-#f4f4f4. Control borders one step darker, median
914
+ #d1d5db. #cbcecd on cards reads heavy; #f5f5f5 disappears.
915
+ - **Text in three tiers.** Primary about #111 (range #000 to a tinted #272446). Secondary about #606060
916
+ (#3a3b3b-#8e8e8e). Tertiary in the study runs #969696-#9f9d9b and placeholders #9ca3af-#b0b2b6,
917
+ which is 2.5-3:1 on white and under the house floor. House rule: every tier that carries words
918
+ reaches 4.5:1 on the surface it sits on, placeholders included; #6b6b6b is about the lightest grey
919
+ that holds on white and on #f9fafb.
920
+ - **Accent placement**: on data only with greyscale chrome (4 screens), on actions only (2), or no
921
+ accent at all (2). The primary button is usually near-black. Every screen with more than one accent
922
+ family is flagged.
923
+ - **Status**: positive greens in the study run #16a34a-#40a670, which is under 4.5:1 as text; use a
924
+ darker green such as #247b50 (5.2:1) for text, and the pale pairs for pills: positive #dcfae5 with
925
+ #04250e, negative #ffedea with #831c1e, a notice #fffbeb with a #fde68a border and #92400e text, a
926
+ count badge #c4242a-#dc3532.
927
+
928
+ ### 9.3 Colour on dark screens
929
+
930
+ - **Ground**: #000 (3 screens), #111 (2), #171719 (1). No navy and no slate.
931
+ - **Surfaces**, three ways: a lighter step with no border (#111 on #000, nested panels at
932
+ #222-#2a2a2a); the ground's own fill with a 1px line (#2e2e2e on #111); darker than the ground with
933
+ a soft shadow (once: #131217 on #171719 with 0 12px 28px rgba(0,0,0,.2)).
934
+ - **Lines**: structural lines 22-31 levels above the ground (#1a1a1a on #000, #2e2e2e on #111,
935
+ #222224 on #171719); interactive outlines brighter, #373737-#4c4c4c, so an outlined button reads as
936
+ clickable without a fill.
937
+ - **Text**: #fff; secondary about #aaa (#82848a-#bbb); tertiary about #888. #4c4c4f (about 2:1) is
938
+ flagged. The house floor of 4.5:1 holds here too. Two greys at most, and far enough apart to read
939
+ as two: about #b4b4b4 for secondary text and #949494 for meta (in testing, #aaaaaa, #969696 and
940
+ #bbbbbb on one screen read as one grey used three ways).
941
+ - **Accent** on data only, or on one selected state. Active nav by brightness. Emphasis without
942
+ colour: an inverted white pill, a grey-filled button (#212121), an outline.
943
+ - **Status** as a hue on a dark tint of itself: #3fc07a on #172a1d; #44a282 on #1b2828. **When the
944
+ accent is green or yellow-green, `--positive` is the accent** (a lime accent: lime on a dark lime
945
+ tint), or the sign carries the meaning in neutral ink; a mint "+£3.81" beside a lime "Sold" read as
946
+ two greens. The same holds on light screens.
947
+ - **Colour share** at or under 3% on all six.
948
+
949
+ ### 9.4 Surfaces, radius, icons, spacing
950
+
951
+ - **Edges.** A 1px border separates surfaces on 12 of the 17 light screens; three use a fill step
952
+ alone and one a shadow alone. A border or a shadow, never both. The shadows that exist are faint
953
+ (alpha .06 or less at 0 2px 8px; once 0 1px 4px at .12). Real shadows are for what floats: a menu,
954
+ a popover, a tooltip, a composer.
955
+ - **Radius is bimodal**: tight, 4-8px (9 screens, plus square cards on one), or soft, 16-24px (10);
956
+ 11-12px on only 3. Controls follow the cards: 6px with tight cards, full pills with soft ones.
957
+ Nested radii step down (20, 10, 8, 5, 4). The inspector warns over three panel radii.
958
+ - **Group, don't box.** A set of KPIs is one card split by 1px dividers, or a bare strip with 48-52px
959
+ vertical dividers.
960
+ - **Icons**: outline on 22 of 23; nav icons 14-20px (median 16) at about 1.5px; inline icons 12-14px;
961
+ about 10px to the label; grey (#454545-#73737f in a light nav, white or #81858a-#999 on dark). Never
962
+ in a saturated circle (0 of 23). A container, if any, is neutral (a #f0f0f0 disc) or codes a node
963
+ type in a builder.
964
+ - **Spacing** on a 4px base: card gap 6-24px (median 16); card padding 12-34px (median 20); section
965
+ gap 24-64px; control height 27-40px (median 34).
966
+
967
+ ### 9.5 Default tokens
968
+
969
+ Each style in `library/app.json` carries its own tokens. These are the study's medians for anything a
970
+ style does not set, with the greys moved to pass 4.5:1.
971
+
972
+ The names match the sheet `draw.mjs --app` prints and `assets/app.css`, a neutral start set to these
973
+ defaults (shell, title row, panels, the divided KPI strip, tables, pills, controls, tabs, empty states
974
+ and the phone fold). `assets/charts.js` draws the charts of §6 in SVG from your data (line, bars,
975
+ diverging columns, ring, bar list, plan, bullet, timeline, cover matrix and time strip), with these
976
+ rules built in and its colours read from these tokens.
977
+
978
+ ```css
979
+ :root {
980
+ /* light */
981
+ --ground: #f9fafb; --surface: #ffffff; --raised: #f9f9f9; --active: #eeeeee;
982
+ --border: #e8e8e8; --rule: #f2f2f2; --control: #d1d5db;
983
+ --text: #111111; --muted: #5f6368; --faint: #6b6b6b; /* placeholders use --faint */
984
+ --primary: #1d1f20; /* near-black fill, white label */
985
+ --accent: /* one hue, about 3% of pixels: the data, plus at most one control */;
986
+ --positive: #247b50; --pill-positive-bg: #dcfae5; --pill-positive-ink: #04250e;
987
+ --negative: #c4242a; --pill-negative-bg: #ffedea; --pill-negative-ink: #831c1e;
988
+ --pill-warning-bg: #fffbeb; --pill-warning-ink: #92400e; /* notice border #fde68a */
989
+ --grid: #e5e5e5; --chart-span: 0.06; /* the opacity of a shaded span in a chart */
990
+
991
+ --radius-card: 8px; --radius-control: 6px; --radius-chip: 4px; /* soft styles: 20 / 14 / 999 */
992
+ --gap: 16px; --card-pad: 20px; --pad: 24px;
993
+ --nav-row: 34px; --control-height: 32px; --row-height: 48px;
994
+ --font: "Inter", system-ui, sans-serif; /* one grotesk */
995
+ --fs-title: 24px; --fs-section: 16px; --fs-kpi: 24px; --fs-body: 14px; --fs-small: 12px;
996
+ }
997
+ :root[data-theme="dark"] {
998
+ --ground: #000000; --surface: #111111; --raised: #222222; --active: #222222;
999
+ --border: #1a1a1a; --rule: #161616; --control: #444444; /* on a #111 ground the border is #2e2e2e */
1000
+ --text: #ffffff; --muted: #b4b4b4; --faint: #949494; /* two greys that read apart */
1001
+ --primary: #ffffff; /* inverted: white fill, black label */
1002
+ --positive: #3fc07a; --pill-positive-bg: #172a1d; --pill-positive-ink: #3fc07a; /* a green accent replaces these */
1003
+ --negative: #e5566f; --pill-negative-bg: #2c1a20; --pill-negative-ink: #e5566f; /* the study's #d4405d, lifted for 4.5:1 */
1004
+ --grid: #2b2b2b; --chart-span: 0.12;
1005
+ }
1006
+ .num { font-variant-numeric: tabular-nums; }
1007
+ td.num, th.num { text-align: right; }
1008
+ ```
1009
+
1010
+ ## 10. Density
1011
+
1012
+ - The studied screens hold 6 to about 120 data points, median about 25.
1013
+ - **Sparse** (6-25): homes, settings, a single object. Card padding 20-24px, rows 56-92px, body
1014
+ 14-16px.
1015
+ - **Medium** (25-50): analytics overviews, finance homes, list screens. Rows 44-56px, padding
1016
+ 16-24px.
1017
+ - **Dense** (about 120, one screen): research and monitoring, read in long sessions. A 13px body,
1018
+ 28px list rows and 42px table rows, framed with generous air: 100px gutters, 64px between bands,
1019
+ 32px of card padding.
1020
+ - Density is three settings moved together: row pitch, padding and type size. Do not shrink the type
1021
+ and keep the padding.
1022
+ - **Placed space reads as calm; leftover space reads as unfinished.** In the study, emptiness looks
1023
+ deliberate when it comes from a fixed grid and repeated gaps, and accidental when it comes from a
1024
+ grid that does not fit the data, a column that is empty in every row (a 300px dead band), a mostly
1025
+ empty top bar, or a card stretched to its neighbour's height.
1026
+ - **Design for the data the account has as well as the data it will have.** Several studied screens
1027
+ were built for a busy account and show a new one: a 673x240 plot for a line that sits on zero for
1028
+ two thirds of its length. Keep the honest drawing, but size the block to the question, not to the
1029
+ data the product hopes for.
1030
+
1031
+ ## 11. Empty, zero, loading and error states
1032
+
1033
+ - **A real zero** is printed in the normal style: "$0", "0", "0%", "0.00%", "0% (0)" (10 screens). A
1034
+ zero may be dimmed to grey when the caption beside it becomes the next step ("$0.00", then
1035
+ "Automate your savings with up to 3.50% APY").
1036
+ - **Missing or not applicable** is a grey dash: an em dash, a "-", a 6x2px mark. Never a dash at full
1037
+ value size: "--" at 24px reads as loading (flagged).
1038
+ - **Counts follow the view, and so does the frame.** Counts shown in scope (tabs, KPI tiles, "12
1039
+ open") are computed from the rows in the current view or filter and recomputed on every switch. A
1040
+ filtered block shrinks to its rows and its row-mate aligns to the top, or the block keeps a fixed
1041
+ number of rows with one empty-state sentence; each view's subline is computed for that view.
1042
+ - **An empty side card fills with the reference data**, not one dashed box in 400px of white: before
1043
+ anything has sold out, last Sunday's sell-out times as a quiet list under "Nothing has sold out yet
1044
+ today".
1045
+ - **Red is a signal, not a texture**: one red mark per object at most, on the overdue or failing fact;
1046
+ thirteen red strings on one board read as noise, and a list of deals needing attention does not
1047
+ repeat the same flags on the board beside it.
1048
+ - **An empty section keeps its frame and its header** and adds one sentence spanning the block (in a
1049
+ row grid, `grid-column: 1 / -1`; a message squeezed into one 34px column broke word by word in
1050
+ testing): a 1px dashed box, radius
1051
+ 8, about 38px tall ("No channel usage in this range."), or a bordered box with an add link
1052
+ ("+ Liability account"). In a builder, an empty slot is a dashed 1px box on the canvas colour.
1053
+ - **An empty chart is drawn**: the zero line, missing bars for empty periods, no padded range, no
1054
+ picture.
1055
+ - **First run** (the whole screen empty): keep the frame and the title, and put the first action where
1056
+ the data will appear, with a setup progress at its true percentage if there are steps (one screen
1057
+ shows "Complete your setup" at 67%; another a four-cell getting-started strip above its tables).
1058
+ - **Loading** (house rule; not in the study): the final layout with each value replaced by a flat grey
1059
+ bar at its real size (a 24px value gets a 24px-tall bar; rows keep their pitch), labels and headers
1060
+ shown at once, no shimmer gradient, and no shift of the layout when the data lands. A refresh of
1061
+ data already on screen keeps the old values and updates the freshness stamp.
1062
+ - **Error** (house rule; not in the study): inside the block that failed, never as a full-screen
1063
+ banner. One sentence saying what failed and when the data was last good ("Couldn't load
1064
+ deployments. Last updated 09:14."), and a Retry text button. The negative colour only on a small
1065
+ icon or in the pill pair.
1066
+ - **Stale or static data**: a freshness stamp with a refresh button (6 screens). A snapshot that
1067
+ cannot refresh says so in one quiet notice (once: #fffbeb, a 1px #fde68a border, 12px #92400e
1068
+ text). A notice tint is never a ground; the inspector reads a pale amber ground as cream.
1069
+ - **Limits and usage**: a bar at the true ratio with both ends labelled ("12.7k of 20.0k").
1070
+
1071
+ ## 12. The phone
1072
+
1073
+ The study has no phone screens. This section is house rule, built from the skill's phone rules
1074
+ (`layout.md` §9) and from what the desktop screens imply. The inspector fails a sidebar that still
1075
+ takes more than 30% of a phone's width.
1076
+
1077
+ - **Navigation folds.** The sidebar becomes a 48px top bar with the screen's name, a menu button that
1078
+ opens a full-screen sheet (nav, workspace switcher, account) and at most one action; or a bottom
1079
+ bar of four or five destinations with short labels. An icon rail becomes that bottom bar.
1080
+ - **Margins** 16-20px; touch targets at least 44px tall; data and labels at 14px, sublines no smaller
1081
+ than 12px.
1082
+ - **The title stays**, at 20-24px. Header actions move into a kebab, except the one primary.
1083
+ - **Filters** collapse into one row of chips or a Filters sheet; tabs scroll sideways inside their own
1084
+ row, never the page. The first list row starts in the top 60% of the phone screen: three rows of
1085
+ filter controls above it pushed the list off the first screen in testing.
1086
+ - **KPIs**: a divided container becomes a 2-column grid, or a list with the label on the left and the
1087
+ value on the right. Never four squeezed columns. In a 2-column grid the count after any full-width
1088
+ lead is even; otherwise use three narrow columns or a divided list, or let the last cell take the
1089
+ full width (`app.css` does that for an odd count). A lone "Sold 3.18 kWh" beside an empty half-row
1090
+ was flagged.
1091
+ - **At most one row of controls above a chart**: an office select and a week switch share one row.
1092
+ Two stacked full-width segmented controls pushed the data down in testing.
1093
+ - **Charts** go full width, 160-200px tall, with 3-4 x labels and a legend of dots above, set in a
1094
+ 2-column grid (or behind a "Key" disclosure) when it would wrap to three lines. The y ticks keep
1095
+ their own lane at the left (or move to the right edge); a tick label never sits on the line.
1096
+ - **Row actions on a phone** are text actions or one compact trailing button, with one filled bulk
1097
+ action for the list ("Approve 3 that fit"); five 44px grey Approve blocks turned a list into a stack
1098
+ of buttons.
1099
+ - **When a strip collapses, drop the item least relevant to the screen's main action**, not the last
1100
+ in source order: the live price stays on an energy screen whose plan depends on it.
1101
+ - **Tables become lists of two-line rows below about 640px**: the identity and the key number on line
1102
+ 1, the other fields the brief names in 13px grey on line 2 ("fra1 · 1m 38s"), the one action at the
1103
+ right. Fields move to line 2; they are never dropped. A table that must stay a table scrolls inside
1104
+ its own frame with its first column fixed; the page never scrolls sideways.
1105
+ - **The tablet (641-1100px) is its own band**: the sidebar folds to the top bar, but tables keep four
1106
+ or five columns with secondary fields as sublines, two narrow panels stack once either would be
1107
+ under about 340px, and the identity column is never the one truncated while another has room.
1108
+ - **Blocks that carry an action move up, not down**: a right rail with an action (low stock and its
1109
+ Reorder, bills due and Pay) becomes a one-line summary row above the list ("5 items low · Review"),
1110
+ never a block under twenty orders.
1111
+ - **Several panes** (a list and its detail, an inbox): one region at a time. Choosing a row pushes the
1112
+ detail; back returns to the list at its scroll position.
1113
+ - **Settings**: the label column stacks above its panel.
1114
+ - **A right rail** moves under the main column or into a tab.
1115
+ - **Builders** show the work read-only, with the palette as a bottom sheet if editing stays.
1116
+ - Check 390px in the inspector's screenshots every round.
1117
+
1118
+ ## 13. House rules for app screens
1119
+
1120
+ The house rules in `SKILL.md` were written for pages that are read once. An app screen is read every
1121
+ day, and part of what those rules ban is the structure of a working screen. These relax, with limits:
1122
+
1123
+ | Allowed on app screens | Limit |
1124
+ | --- | --- |
1125
+ | **1px borders** on cards, panels, tables and controls | About 1.1-1.3:1 against the ground on light (#e5e7eb-#ededed on white); #1a1a1a on #000, #2e2e2e on #111. Controls one step stronger. A border or a shadow, never both. |
1126
+ | **Row rules** in tables and lists | 1px, 3-7% darker than the surface. No zebra, no header band. |
1127
+ | **Dashed lines** | In chart grids and empty slots only. |
1128
+ | **Small labels** above values | 12-14px, sentence case, grey at 4.5:1. Meta and axis text 11-12px. Nothing under 11px. At most one tracked uppercase label on a screen (a switcher's context label). |
1129
+ | **Rows of identical cards** | Peer metrics or peer objects only: 3-6 across, equal widths, one gap, no orphan, edges aligned across rows, no icon on top. Prefer one divided card; mixed spans beat a uniform grid. |
1130
+ | **Monospace** | IDs, keys and code; or every figure, as one style's decision. Otherwise tabular figures in the text face. |
1131
+ | **Pills** | Inside rows and beside a value only: 16-24px tall, a pale tint with dark text of the same hue. Never above a heading. |
1132
+ | **Index numbers** | Only as data: a rank ("1."), a node number. |
1133
+ | **Icons** | 14-20px outline, one set, grey: in the nav, before a label, or as a single affordance (kebab, chevron, info). A container only if it is neutral, or node-type tiles in a builder (pass `--allow icon-chips` and give the reason in the report). |
1134
+ | **Shadows** | On what floats: a menu, a popover, a tooltip, a composer, a dialog. A resting card gets at most a small blur under 8% black. |
1135
+ | **A second typeface** | With one job: a mono for IDs or figures, a serif for one greeting. |
1136
+ | **A gradient** | Only as an area fade under one line chart; a flat tint of about 14% is safer. |
1137
+
1138
+ Still banned, as on pages, and checked:
1139
+
1140
+ | Banned | Instead |
1141
+ | --- | --- |
1142
+ | Gradients on grounds, buttons, cards, text and KPI tiles (the study's two gradient buttons are flagged) | Flat fills |
1143
+ | Glows, glass, backdrop blur | Opaque surfaces one tone step from the ground |
1144
+ | An icon in a coloured circle or tinted square on every KPI or card (0 of 23) | A label and a number |
1145
+ | Rainbow charts: more than four hues, a hue per bar, one subject in two hues | One hue per chart, neutrals for the rest |
1146
+ | Sparklines on KPIs (0 of 23) | The trend in its own chart, or nowhere |
1147
+ | Emoji in greetings, labels, nav or empty states | Words |
1148
+ | Lorem ipsum, Acme, John Doe, "User 1"; vanity figures ("10,000+ teams"); totals that do not add up | Believable sample data computed from rows, listed in the report |
1149
+ | Status colour on a zero or undefined change | Grey, or the change in words ("+4 (new)") |
1150
+ | A dark or saturated sidebar on a light screen; a navy or slate dark theme | The page ground for the sidebar; true neutral darks |
1151
+ | The accent on chrome: a tinted nav row with a left bar, coloured tab pills, a brand fill on every button | The accent on data and at most one control; a near-black primary |
1152
+ | Uppercase tracked table headers, zebra rows, header bands | 12px grey sentence-case headers; rules or space |
1153
+ | Left-aligned numbers, proportional figures in columns | Right-aligned tabular figures |
1154
+ | A hero header, a greeting with an emoji, an illustrated welcome banner | A noun title at 24px |
1155
+ | Pagination under a five-row overview list | Capped rows, "View all", the total |
1156
+ | Violet and indigo accents; cream with terracotta | The dealt style's palette |
1157
+ | A landing-page title (over 32px) or a figure at 48px or more | An 18-32px title; figures at 16-40px |
1158
+ | Icons in boxes repeated down a list or on top of every peer card, tinted or neutral | One plain 16px icon where it helps, or none |
1159
+ | Every row a different hue, a "left" amount in green on every budget row | Grey for what is fine; colour only on the rows at risk or over |
1160
+ | A screen that names no product and offers no action | The product's mark and scope in the shell; its main job one click away |
1161
+
1162
+ **On violet and indigo.** 10 of the 23 studied screens use violet or indigo, always as a data hue or a
1163
+ single control. The ban is the owner's taste, not a finding of the study: the library deals other
1164
+ hues for the styles that came from those screens, and the inspector's palette check stays on.
1165
+
1166
+ ## 14. Tells of generated dashboards
1167
+
1168
+ Each line sets a habit of generated dashboards against what the 23 screens do instead.
1169
+
1170
+ | Tell | What replaces it |
1171
+ | --- | --- |
1172
+ | A dark navy or tinted sidebar with a coloured active pill and a left bar | The sidebar on the page ground; a neutral grey pill, or the label brightening on dark. A left bar appears once in 23. |
1173
+ | "Welcome back, Alex" with a waving hand and a subtitle | A noun title at 24/600. Three screens greet; the one emoji goes. |
1174
+ | Four KPI cards, each with an icon in a tinted circle | One container split by hairlines, label over value. No icons on any of the 23. |
1175
+ | A green "+12.5%" pill on every KPI | A delta on 9 of 20 screens, in words with its window; grey for zero; "+4 (new)" from zero. |
1176
+ | A sparkline on every KPI | None on any of the 23. The trend has its own chart. |
1177
+ | KPI values at 36-48px, bold, in the brand colour | 24-30px at 400-600 in ink; nothing at 48. |
1178
+ | A gradient area chart with a smoothed spline and a dot on every point | A 2px straight line, no fill on 7 of 10, no markers. |
1179
+ | A rainbow palette, a hue per bar or per chart | One hue per chart; the accent on data only; four hues at most on a screen. |
1180
+ | Gridlines every 20px, axis lines on both sides, a legend for one series | 3-5 faint lines, no y-axis line, no legend for a single series; round ticks above the maximum. |
1181
+ | A fat donut with labels on the slices and a big total in the hole | A thin ring, no slice labels, the legend as a table with the values. |
1182
+ | Cards with a 16-24px radius, a 1px border and a large soft shadow | A border or a tone step, no shadow; a tight or a soft radius, chosen once. |
1183
+ | A zebra table under uppercase tracked headers, with a checkbox, an avatar, a status chip and a kebab on every row | Rules and alignment: 12px grey headers, one status mark, one action where it is needed. |
1184
+ | Left-aligned numbers in proportional digits | Right-aligned tabular figures, fixed decimals, units in grey. |
1185
+ | Saturated status chips with white text | Pale tints with dark text of the same hue. |
1186
+ | The accent on every button, tab and link | No filled primary on 12 of 23; near-black where there is one. |
1187
+ | A top bar with search, a bell and an avatar on every screen, or one left mostly empty | No top bar on 9 of 23; when there is one, it carries search, the switcher or the object's name. |
1188
+ | Export, Share and a date picker clustered by the title | Actions only when they are real; a freshness stamp instead. |
1189
+ | Placeholder people and companies, round vanity totals, growth on a week-old account | The product's own data, small numbers at their real size, totals summed from the rows. |
1190
+ | Pagination under a short list | Capped rows and "View all". |
1191
+ | An equal four-up grid whatever the data, with orphan cells and stretched cards | A column count chosen by the item count; spans that change by row and land on the same lines. |
1192
+ | Neon on dark, glowing borders, glass | True neutral darks, lightness steps, colour on the data. |
1193
+ | The kit's own face: Geist or Inter on #f8f8f8 with white 12px cards and no hue on the data, or lime on black | One face taken from the brief (a ground from the product's world, a figure face with character, the brand's hue on the main data element) and one element only this product has. |
1194
+ | A coloured icon per category in a list | One grey icon set; colour, if any, on the numbers. |
1195
+ | An illustration and "No data yet" in an empty chart | The zero line drawn, and one sentence in the frame. |
1196
+
1197
+ A screen with every tell removed and nothing put in their place is a tidy template. What fills the
1198
+ space is the product: its own data at its real size, the screen's one question answered by its
1199
+ biggest block, and a grid whose sums close.