@sableui/react 0.9.1 → 0.10.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 (212) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +95 -0
  3. package/CONTRIBUTING.md +2 -2
  4. package/DESIGN.md +55 -16
  5. package/README.md +12 -0
  6. package/dist/{_contract-C2M1SjBf.d.ts → _contract-CkqXDVww.d.ts} +25 -2
  7. package/dist/blocks/danger-zone-block.js +3 -3
  8. package/dist/blocks/danger-zone-block.meta.js +1 -1
  9. package/dist/blocks/faq-block.js +3 -3
  10. package/dist/blocks/goal-progress-block.js +1 -1
  11. package/dist/blocks/notification-list-block.js +1 -1
  12. package/dist/blocks/pricing-table-block.js +12 -12
  13. package/dist/blocks/product-card-block.js +3 -3
  14. package/dist/blocks/product-card-block.meta.js +3 -3
  15. package/dist/blocks/profile-card-block.js +1 -1
  16. package/dist/blocks/profile-form-block.js +3 -3
  17. package/dist/blocks/revenue-breakdown-block.js +5 -5
  18. package/dist/blocks/stat-row-block.js +3 -3
  19. package/dist/blocks/task-list-block.js +2 -2
  20. package/dist/blocks/team-members-block.js +1 -1
  21. package/dist/blocks/wallet-block.js +4 -4
  22. package/dist/blocks/wallet-block.meta.js +3 -3
  23. package/dist/components/accordion/accordion.meta.js +2 -2
  24. package/dist/components/app-header/app-header.meta.js +1 -1
  25. package/dist/components/app-shell/app-shell.meta.js +2 -2
  26. package/dist/components/area-chart/area-chart.meta.js +3 -3
  27. package/dist/components/badge/badge.js +13 -4
  28. package/dist/components/badge/badge.meta.js +24 -13
  29. package/dist/components/badge/badge.variants.js +37 -23
  30. package/dist/components/banner/banner.meta.js +8 -8
  31. package/dist/components/banner/banner.variants.js +3 -3
  32. package/dist/components/bar-chart/bar-chart.meta.js +4 -4
  33. package/dist/components/breadcrumbs/breadcrumbs.meta.js +1 -1
  34. package/dist/components/button/button.meta.js +3 -3
  35. package/dist/components/card/card.js +16 -7
  36. package/dist/components/card/card.meta.js +4 -4
  37. package/dist/components/checkbox-card/checkbox-card.meta.js +10 -10
  38. package/dist/components/checkbox-card/checkbox-card.variants.js +15 -15
  39. package/dist/components/code-block/code-block.meta.js +1 -1
  40. package/dist/components/command-menu/command-menu.meta.js +1 -1
  41. package/dist/components/context-card/context-card.meta.js +2 -2
  42. package/dist/components/destructive-action-modal/destructive-action-modal.meta.js +1 -1
  43. package/dist/components/dialog/dialog.meta.js +2 -2
  44. package/dist/components/disclosure-picker/disclosure-picker.js +48 -2
  45. package/dist/components/disclosure-picker/disclosure-picker.meta.js +3 -2
  46. package/dist/components/empty-state/empty-state.meta.js +4 -4
  47. package/dist/components/gradient-art/gradient-art.meta.js +3 -3
  48. package/dist/components/label/label.meta.js +1 -1
  49. package/dist/components/line-chart/line-chart.meta.js +3 -3
  50. package/dist/components/meter/meter.js +1 -1
  51. package/dist/components/meter/meter.meta.js +2 -2
  52. package/dist/components/meter/meter.variants.js +1 -1
  53. package/dist/components/middle-truncate/middle-truncate.meta.js +4 -4
  54. package/dist/components/note/note.meta.js +3 -3
  55. package/dist/components/page-header/page-header.js +1 -1
  56. package/dist/components/pagination/pagination.meta.js +2 -2
  57. package/dist/components/phone/phone.meta.js +1 -1
  58. package/dist/components/pie-chart/pie-chart.meta.js +3 -3
  59. package/dist/components/pill/pill.js +4 -2
  60. package/dist/components/pill/pill.meta.js +19 -2
  61. package/dist/components/pill/pill.variants.js +23 -2
  62. package/dist/components/popover/popover.meta.js +2 -2
  63. package/dist/components/radar-chart/radar-chart.meta.js +3 -3
  64. package/dist/components/radial-chart/radial-chart.meta.js +3 -3
  65. package/dist/components/radio/radio.meta.js +2 -2
  66. package/dist/components/radio-card/radio-card.meta.js +6 -6
  67. package/dist/components/radio-card/radio-card.variants.js +15 -15
  68. package/dist/components/scroller/scroller.meta.js +1 -1
  69. package/dist/components/search-input/search-input.meta.js +1 -1
  70. package/dist/components/section-header/section-header.js +1 -1
  71. package/dist/components/segmented-bar/segmented-bar.js +1 -1
  72. package/dist/components/segmented-bar/segmented-bar.meta.js +6 -6
  73. package/dist/components/segmented-bar/segmented-bar.variants.js +4 -4
  74. package/dist/components/select/select.meta.js +2 -2
  75. package/dist/components/sheet/sheet.meta.js +1 -1
  76. package/dist/components/side-nav/side-nav.meta.js +1 -1
  77. package/dist/components/sidebar/sidebar.meta.js +1 -1
  78. package/dist/components/sparkline/sparkline.meta.js +4 -4
  79. package/dist/components/spinner/spinner.meta.js +1 -1
  80. package/dist/components/status-dot/status-dot.js +4 -1
  81. package/dist/components/status-dot/status-dot.meta.js +8 -16
  82. package/dist/components/status-dot/status-dot.variants.js +13 -4
  83. package/dist/components/table/table.meta.js +4 -4
  84. package/dist/components/tabs/tabs.meta.js +1 -1
  85. package/dist/components/textarea/textarea.meta.js +2 -2
  86. package/dist/components/toast/toast.meta.js +1 -1
  87. package/dist/components/tooltip/tooltip.meta.js +2 -2
  88. package/dist/file-hashes.json +120 -118
  89. package/dist/foundations/spacing.js +8 -8
  90. package/dist/index.d.ts +137 -72
  91. package/dist/index.js +12 -1
  92. package/dist/lib/chart/types.js +3 -3
  93. package/dist/lib/palette.js +103 -0
  94. package/dist/lib/selection-card.js +4 -4
  95. package/dist/palette.css +669 -0
  96. package/dist/patterns/auth-page.js +6 -6
  97. package/dist/patterns/auth-page.meta.js +3 -3
  98. package/dist/patterns/brand-landing-page.js +2 -2
  99. package/dist/patterns/chat-panel.js +2 -2
  100. package/dist/patterns/dashboard-page.js +71 -71
  101. package/dist/patterns/dashboard-page.meta.js +5 -5
  102. package/dist/patterns/feed-page.js +25 -25
  103. package/dist/patterns/feed-page.meta.js +3 -3
  104. package/dist/patterns/landing-page.js +1 -1
  105. package/dist/patterns/list-detail-page.js +17 -17
  106. package/dist/patterns/settings-page.js +17 -17
  107. package/dist/presets/index.d.ts +1 -1
  108. package/dist/presets/index.js +17 -2
  109. package/dist/styles.css +115 -50
  110. package/dist/{theme-provider-S0NVJs2Y.d.ts → theme-provider-CdSicAad.d.ts} +1 -1
  111. package/dist/themes/_contract.js +22 -8
  112. package/dist/themes/atelier/atelier.css +13 -13
  113. package/dist/themes/atelier/index.d.ts +1 -1
  114. package/dist/themes/ember/ember.css +13 -13
  115. package/dist/themes/ember/index.d.ts +1 -1
  116. package/dist/themes/index.d.ts +2 -2
  117. package/dist/themes/meridian/index.d.ts +1 -1
  118. package/dist/themes/meridian/meridian.css +13 -13
  119. package/dist/themes/poppy/index.d.ts +1 -1
  120. package/dist/themes/poppy/poppy.css +19 -16
  121. package/dist/themes/prism/index.d.ts +1 -1
  122. package/dist/themes/prism/prism.css +18 -15
  123. package/dist/themes/sable/index.d.ts +1 -1
  124. package/dist/themes/sable/sable.css +18 -22
  125. package/dist/themes/verdant/index.d.ts +1 -1
  126. package/dist/themes/verdant/verdant.css +15 -15
  127. package/llms/blocks/danger-zone-block.md +4 -4
  128. package/llms/blocks/faq-block.md +3 -3
  129. package/llms/blocks/goal-progress-block.md +1 -1
  130. package/llms/blocks/notification-list-block.md +1 -1
  131. package/llms/blocks/pricing-table-block.md +12 -12
  132. package/llms/blocks/product-card-block.md +6 -6
  133. package/llms/blocks/profile-card-block.md +1 -1
  134. package/llms/blocks/profile-form-block.md +3 -3
  135. package/llms/blocks/revenue-breakdown-block.md +5 -5
  136. package/llms/blocks/stat-row-block.md +3 -3
  137. package/llms/blocks/task-list-block.md +2 -2
  138. package/llms/blocks/team-members-block.md +1 -1
  139. package/llms/blocks/wallet-block.md +7 -7
  140. package/llms/components/accordion.md +2 -2
  141. package/llms/components/app-header.md +1 -1
  142. package/llms/components/app-shell.md +2 -2
  143. package/llms/components/area-chart.md +1 -1
  144. package/llms/components/badge.md +15 -7
  145. package/llms/components/banner.md +6 -6
  146. package/llms/components/bar-chart.md +2 -2
  147. package/llms/components/breadcrumbs.md +1 -1
  148. package/llms/components/button.md +3 -3
  149. package/llms/components/card.md +4 -4
  150. package/llms/components/checkbox-card.md +5 -5
  151. package/llms/components/code-block.md +1 -1
  152. package/llms/components/command-menu.md +1 -1
  153. package/llms/components/context-card.md +2 -2
  154. package/llms/components/destructive-action-modal.md +1 -1
  155. package/llms/components/dialog.md +2 -2
  156. package/llms/components/disclosure-picker.md +2 -1
  157. package/llms/components/empty-state.md +4 -4
  158. package/llms/components/gradient-art.md +3 -3
  159. package/llms/components/label.md +1 -1
  160. package/llms/components/line-chart.md +1 -1
  161. package/llms/components/meter.md +2 -2
  162. package/llms/components/middle-truncate.md +5 -5
  163. package/llms/components/note.md +3 -3
  164. package/llms/components/pagination.md +2 -2
  165. package/llms/components/phone.md +1 -1
  166. package/llms/components/pie-chart.md +1 -1
  167. package/llms/components/pill.md +12 -2
  168. package/llms/components/popover.md +2 -2
  169. package/llms/components/radar-chart.md +1 -1
  170. package/llms/components/radial-chart.md +1 -1
  171. package/llms/components/radio-card.md +4 -4
  172. package/llms/components/radio.md +2 -2
  173. package/llms/components/scroller.md +1 -1
  174. package/llms/components/search-input.md +1 -1
  175. package/llms/components/segmented-bar.md +7 -7
  176. package/llms/components/select.md +2 -2
  177. package/llms/components/sheet.md +1 -1
  178. package/llms/components/side-nav.md +1 -1
  179. package/llms/components/sidebar.md +1 -1
  180. package/llms/components/sparkline.md +2 -2
  181. package/llms/components/spinner.md +1 -1
  182. package/llms/components/status-dot.md +4 -4
  183. package/llms/components/table.md +8 -8
  184. package/llms/components/tabs.md +1 -1
  185. package/llms/components/textarea.md +2 -2
  186. package/llms/components/toast.md +1 -1
  187. package/llms/components/tooltip.md +2 -2
  188. package/llms/foundations/spacing.md +7 -7
  189. package/llms/layout/grid.md +1 -1
  190. package/llms/layout/page.md +1 -1
  191. package/llms/layout/region.md +1 -1
  192. package/llms/layout/split-pane.md +1 -1
  193. package/llms/patterns/auth-page.md +11 -11
  194. package/llms/patterns/brand-landing-page.md +2 -2
  195. package/llms/patterns/chat-panel.md +2 -2
  196. package/llms/patterns/dashboard-page.md +78 -78
  197. package/llms/patterns/feed-page.md +31 -31
  198. package/llms/patterns/landing-page.md +1 -1
  199. package/llms/patterns/list-detail-page.md +18 -18
  200. package/llms/patterns/settings-page.md +18 -18
  201. package/llms/reference/token-intent.md +25 -11
  202. package/llms/reference/utilities.md +1 -1
  203. package/llms/tasks/adding-a-component.md +4 -1
  204. package/llms/tasks/building-a-page.md +40 -0
  205. package/llms/tasks/converting-an-app.md +3 -1
  206. package/llms/tasks/using-presets.md +4 -0
  207. package/llms-full.txt +429 -347
  208. package/llms.txt +7 -7
  209. package/package.json +4 -4
  210. package/registry.json +369 -233
  211. package/scripts/lint-rules.mjs +26 -5
  212. package/skills/sable/SKILL.md +14 -3
@@ -45,9 +45,9 @@ const roleLabel: Record<Role, string> = {
45
45
 
46
46
  const roleSummary: Record<Role, string> = {
47
47
  owner: "Full access, including payouts and billing. Transfer ownership in studio settings.",
48
- admin: "Manages members, editions and payouts.",
49
- editor: "Drafts, prices and releases editions.",
50
- viewer: "Sees editions and sales, but can't change them.",
48
+ admin: "Manages members, projects and billing.",
49
+ editor: "Drafts, edits and publishes projects.",
50
+ viewer: "Sees projects and reports, but can't change them.",
51
51
  }
52
52
 
53
53
  type Activity = { id: string; icon: string; text: string; when: string }
@@ -62,7 +62,7 @@ type Member = {
62
62
  handle?: string
63
63
  joined?: string
64
64
  lastActive?: string
65
- editions?: number
65
+ projects?: number
66
66
  invitedBy?: string
67
67
  sent?: string
68
68
  expires?: string
@@ -75,40 +75,40 @@ const seats = 10
75
75
  const initialMembers: Member[] = [
76
76
  {
77
77
  id: "u_01", name: "Ada Lovelace", handle: "@ada", email: "ada@atelier.art", initials: "AL", role: "owner", pending: false,
78
- joined: "Mar 4, 2024", lastActive: "Online now", editions: 12,
78
+ joined: "Mar 4, 2024", lastActive: "Online now", projects: 12,
79
79
  activity: [
80
- { id: "a1", icon: "gem", text: "Released Analytical Engine No. 3 — edition of 50", when: "2 hours ago" },
80
+ { id: "a1", icon: "file", text: "Published the Analytical Engine No. 3 roadmap", when: "2 hours ago" },
81
81
  { id: "a2", icon: "mail", text: "Invited louise@bourgeois.studio as Editor", when: "2 days ago" },
82
82
  ],
83
83
  },
84
84
  {
85
85
  id: "u_02", name: "Grace Hopper", handle: "@grace", email: "grace@atelier.art", initials: "GH", role: "admin", pending: false,
86
- joined: "Mar 9, 2024", lastActive: "20 minutes ago", editions: 4,
86
+ joined: "Mar 9, 2024", lastActive: "20 minutes ago", projects: 4,
87
87
  activity: [
88
88
  { id: "a1", icon: "user", text: "Changed Frida Kahlo's role to Viewer", when: "Yesterday" },
89
- { id: "a2", icon: "edit", text: "Updated pricing on First Compiler — edition of 10", when: "3 days ago" },
90
- { id: "a3", icon: "gem", text: "Released First Compiler — edition of 10", when: "Sep 28" },
89
+ { id: "a2", icon: "edit", text: "Updated the budget on First Compiler", when: "3 days ago" },
90
+ { id: "a3", icon: "file", text: "Created the First Compiler project", when: "Sep 28" },
91
91
  ],
92
92
  },
93
93
  {
94
94
  id: "u_03", name: "Mary Shelley", handle: "@mary", email: "mary@atelier.art", initials: "MS", role: "editor", pending: false,
95
- joined: "Jun 18, 2024", lastActive: "3 hours ago", editions: 7,
95
+ joined: "Jun 18, 2024", lastActive: "3 hours ago", projects: 7,
96
96
  activity: [
97
97
  { id: "a1", icon: "calendar", text: "Scheduled Frankenstein Studies for Oct 14", when: "3 hours ago" },
98
- { id: "a2", icon: "gem", text: "Released The Last Man — edition of 25", when: "Sep 21" },
98
+ { id: "a2", icon: "file", text: "Published The Last Man report", when: "Sep 21" },
99
99
  ],
100
100
  },
101
101
  {
102
102
  id: "u_04", name: "Nina Simone", handle: "@nina", email: "nina@atelier.art", initials: "NS", role: "editor", pending: false,
103
- joined: "Jan 12, 2025", lastActive: "Yesterday", editions: 3,
103
+ joined: "Jan 12, 2025", lastActive: "Yesterday", projects: 3,
104
104
  activity: [
105
- { id: "a1", icon: "upload", text: "Uploaded artwork for Little Girl Blue", when: "Yesterday" },
106
- { id: "a2", icon: "gem", text: "Released Feeling Good — edition of 100", when: "Aug 30" },
105
+ { id: "a1", icon: "upload", text: "Uploaded files for Little Girl Blue", when: "Yesterday" },
106
+ { id: "a2", icon: "file", text: "Published the Feeling Good brief", when: "Aug 30" },
107
107
  ],
108
108
  },
109
109
  {
110
110
  id: "u_05", name: "Frida Kahlo", handle: "@frida", email: "frida@atelier.art", initials: "FK", role: "viewer", pending: false,
111
- joined: "Jul 2, 2025", lastActive: "4 days ago", editions: 0,
111
+ joined: "Jul 2, 2025", lastActive: "4 days ago", projects: 0,
112
112
  activity: [{ id: "a1", icon: "comment", text: "Commented on the Las Dos Fridas draft", when: "4 days ago" }],
113
113
  },
114
114
  {
@@ -341,8 +341,8 @@ export function ListDetailPage() {
341
341
  <dd className={selected.lastActive === "Online now" ? "text-success" : undefined}>
342
342
  {selected.lastActive}
343
343
  </dd>
344
- <dt>Editions released</dt>
345
- <dd>{selected.editions}</dd>
344
+ <dt>Projects owned</dt>
345
+ <dd>{selected.projects}</dd>
346
346
  </dl>
347
347
  )}
348
348
  </div>
@@ -395,7 +395,7 @@ export function ListDetailPage() {
395
395
  description={
396
396
  selected.pending
397
397
  ? `${selected.email} won't be able to join with the link they were sent.`
398
- : "They lose access to the studio right away. Editions they released stay on sale."
398
+ : "They lose access to the workspace right away. Projects they own stay with the team."
399
399
  }
400
400
  confirmLabel={selected.pending ? "Revoke invite" : "Remove member"}
401
401
  onConfirm={() => remove(selected.id)}
@@ -46,17 +46,17 @@ const timezones = [
46
46
  ]
47
47
 
48
48
  const notifications = [
49
- { name: "notifyCollects", title: "New collects", description: "When someone collects your work", on: true },
50
- { name: "notifySoldOut", title: "Sold out", description: "When an edition sells its last copy", on: true },
51
- { name: "notifyFollowers", title: "New followers", description: "When a collector follows you", on: false },
52
- { name: "notifyDigest", title: "Weekly digest", description: "Sales and collectors, every Monday", on: true },
49
+ { name: "notifyComments", title: "New comments", description: "When someone comments on your work", on: true },
50
+ { name: "notifyInvoicePaid", title: "Invoice paid", description: "When a customer pays an invoice", on: true },
51
+ { name: "notifyMembers", title: "New members", description: "When someone joins your workspace", on: false },
52
+ { name: "notifyDigest", title: "Weekly digest", description: "Activity and usage, every Monday", on: true },
53
53
  { name: "notifyProduct", title: "Product updates", description: "New Atelier features", on: false },
54
54
  ]
55
55
 
56
56
  const payouts = [
57
57
  { label: "Next payout", value: "$1,284.60", note: "Friday, Oct 16" },
58
58
  { label: "Pending", value: "$412.00", note: "Clears in 7 days" },
59
- { label: "Paid this year", value: "$18,920.00", note: "Across 214 collects" },
59
+ { label: "Paid this year", value: "$18,920.00", note: "Across 214 invoices" },
60
60
  ]
61
61
 
62
62
  export function SettingsPage() {
@@ -81,8 +81,8 @@ export function SettingsPage() {
81
81
  bottomNav={
82
82
  <BottomNav aria-label="Primary">
83
83
  <BottomNavItem icon={<Icon name="grid" />} label="Overview" showLabel render={<a href="/" />} />
84
- <BottomNavItem icon={<Icon name="image-stack" />} label="Editions" showLabel render={<a href="/editions" />} />
85
- <BottomNavItem icon={<Icon name="user" />} label="Collectors" showLabel render={<a href="/collectors" />} />
84
+ <BottomNavItem icon={<Icon name="folder" />} label="Accounts" showLabel render={<a href="/accounts" />} />
85
+ <BottomNavItem icon={<Icon name="user" />} label="Customers" showLabel render={<a href="/customers" />} />
86
86
  <BottomNavItem icon={<Icon name="bell" />} label="Activity" showLabel render={<a href="/activity" />} />
87
87
  <BottomNavItem icon={<Icon name="gear" />} label="Settings" showLabel active render={<a href="/settings" />} />
88
88
  </BottomNav>
@@ -94,8 +94,8 @@ export function SettingsPage() {
94
94
  </SidebarHeader>
95
95
  <SidebarNav>
96
96
  <SidebarItem icon={<Icon name="grid" />} label="Overview" render={<a href="/" />} />
97
- <SidebarItem icon={<Icon name="image-stack" />} label="Editions" render={<a href="/editions" />} />
98
- <SidebarItem icon={<Icon name="user" />} label="Collectors" render={<a href="/collectors" />} />
97
+ <SidebarItem icon={<Icon name="folder" />} label="Accounts" render={<a href="/accounts" />} />
98
+ <SidebarItem icon={<Icon name="user" />} label="Customers" render={<a href="/customers" />} />
99
99
  <SidebarItem
100
100
  icon={<Icon name="bell" />}
101
101
  label="Activity"
@@ -149,7 +149,7 @@ export function SettingsPage() {
149
149
  <Card id="profile" className="scroll-mt-6">
150
150
  <CardHeader>
151
151
  <CardTitle render={<h2 />}>Profile</CardTitle>
152
- <CardDescription>How collectors see you on Atelier.</CardDescription>
152
+ <CardDescription>How your team sees you on Atelier.</CardDescription>
153
153
  </CardHeader>
154
154
  {/* The one explicit save on the page: profile text is drafted, then
155
155
  committed. Toggles below apply the moment they change. */}
@@ -180,14 +180,14 @@ export function SettingsPage() {
180
180
  <Input defaultValue="ada" autoComplete="username" spellCheck={false} />
181
181
  </Field>
182
182
  </Grid>
183
- <Field label="Bio" name="bio" description="Shown on your profile and edition pages.">
183
+ <Field label="Bio" name="bio" description="Shown on your profile and in comments.">
184
184
  <Textarea
185
185
  rows={3}
186
- defaultValue="Generative artist working in plotted ink and code. New editions of 25 to 100 every month."
186
+ defaultValue="Product designer working on tools for small teams. Writing about process every month."
187
187
  />
188
188
  </Field>
189
189
  <Grid cols={{ base: 1, sm: 2 }} gap={3}>
190
- <Field label="Timezone" name="timezone" description="Release times use this zone.">
190
+ <Field label="Timezone" name="timezone" description="Due dates use this zone.">
191
191
  <Select defaultValue="europe-london" items={timezones}>
192
192
  <SelectTrigger />
193
193
  <SelectContent>
@@ -212,7 +212,7 @@ export function SettingsPage() {
212
212
  <CardHeader>
213
213
  <CardTitle render={<h2 />}>Notifications</CardTitle>
214
214
  <CardDescription>
215
- Email updates about your editions. Changes save automatically.
215
+ Email updates about your projects. Changes save automatically.
216
216
  </CardDescription>
217
217
  </CardHeader>
218
218
  <CardList>
@@ -275,7 +275,7 @@ export function SettingsPage() {
275
275
  <Entity
276
276
  leading={<Icon name="download" className="text-lg text-muted-foreground" />}
277
277
  title="Export data"
278
- subtitle="Editions, sales, and collectors"
278
+ subtitle="Projects, invoices, and members"
279
279
  action={
280
280
  <Button variant="outline" size="sm">
281
281
  Export
@@ -289,8 +289,8 @@ export function SettingsPage() {
289
289
  <CardHeader>
290
290
  <CardTitle render={<h2 />}>Delete account</CardTitle>
291
291
  <CardDescription>
292
- Permanently remove your profile, editions, and sales history. Collectors keep
293
- the editions they own.
292
+ Permanently remove your profile, projects, and billing history. Files you shared
293
+ stay with your team.
294
294
  </CardDescription>
295
295
  </CardHeader>
296
296
  <CardFooter className="justify-end">
@@ -307,7 +307,7 @@ export function SettingsPage() {
307
307
  open={deleteOpen}
308
308
  onOpenChange={setDeleteOpen}
309
309
  title="Delete your account?"
310
- description="This permanently removes your profile, 12 editions, and sales history. Pending payouts are still sent. This can't be undone."
310
+ description="This permanently removes your profile, 12 projects, and billing history. Your final invoice is still sent. This can't be undone."
311
311
  confirmLabel="Delete account"
312
312
  confirmingLabel="Deleting…"
313
313
  confirmText="ada"
@@ -50,23 +50,23 @@ Which token to reach for, and what it is most often confused with. Generated fro
50
50
  - **Not** `tone-info`. Success asserts an outcome; info asserts a fact. 'Saved' is success, '3 items' is info.
51
51
  - **`success-foreground`** — Ink paired with `success`. Evaluate the rendered contrast together; never choose it independently. *Use for:* Whenever the background is `success`. Use them as a pair — `bg-success text-success-foreground` — so a theme can retune the surface and the ink together.
52
52
  - **Not** `foreground`. That is the ink for `background` only; on any other surface it is a contrast gamble that happens to pass in the default theme and fails in another.
53
- - **`tone-standard`** — Domain tone: the baseline classification in a set. Part of the `tone-*` family, which exists so a product can classify content without inventing colours per feature. *Use for:* The default category of a classified item — the one that means 'nothing special'.
53
+ - **`tone-3`** — Extra colour 3: the third, and usually the quietest, category in a classified set. *Use for:* A third category, or the baseline one that means 'nothing special'.
54
54
  - **Not** `muted`. A tone is *semantic classification* that a reader is meant to decode; `muted` is de-emphasis. If a legend would help the user, it is a tone.
55
- - **`tone-collectible`** — Domain tone: a scarce or owned item. *Use for:* Marking an item as collectible/owned in a classified set.
56
- - **Not** `primary`. A tone classifies the *thing*; primary drives an *action*. A collectible badge is not a button.
57
- - **`tone-edition`** — Domain tone: an edition or release. *Use for:* Marking editioned content in a classified set.
58
- - **Not** `tone-collectible`. Distinct classifications must stay visually distinct.
55
+ - **`tone-2`** — Extra colour 2: the second category in a classified set. *Use for:* A second category, distinct from tone-1, in a badge, dot, card or chart.
56
+ - **Not** `tone-1`. Distinct categories must stay visually distinct.
57
+ - **`tone-1`** — Extra colour 1, the lead of the three a theme defines beyond its status colours. The numbered tones exist so a product can classify content (categories, plans, series) without inventing colours per feature; the product decides what each one means. *Use for:* The most prominent category in a classified set, or the first series of a chart.
58
+ - **Not** `primary`. A tone classifies the *thing*; primary drives an *action*. A category badge is not a button.
59
59
  - **`tone-info`** — Domain tone: neutral, factual information. *Use for:* An informational note or banner, a neutral count, a 'did you know' surface.
60
60
  - **Not** `success`. Info states a fact; success states an outcome. Also not `primary` — an info banner is not an action.
61
61
  - **`tone-warning`** — Domain tone: proceed with care, nothing is broken yet. *Use for:* A caution banner, a nearing-limit indicator, a soloed/overridden state in a tool.
62
62
  - **Not** `destructive`. Warning is *advisory*; destructive is *consequential*. If nothing is lost by continuing, it is a warning.
63
63
  - **`highlight`** — A marker on content the user is meant to notice — search hits, diffs, annotations. *Use for:* Highlighting matched text, a changed line, a called-out passage.
64
64
  - **Not** `accent`. `accent` is UI state that follows the pointer or selection; `highlight` marks the *content* and persists independently of interaction.
65
- - **`tone-standard-foreground`** — Ink paired with `tone-standard`. Evaluate the rendered contrast together; never choose it independently. *Use for:* Whenever the background is `tone-standard`. Use them as a pair — `bg-tone-standard text-tone-standard-foreground` — so a theme can retune the surface and the ink together.
65
+ - **`tone-3-foreground`** — Ink paired with `tone-3`. Evaluate the rendered contrast together; never choose it independently. *Use for:* Whenever the background is `tone-3`. Use them as a pair — `bg-tone-3 text-tone-3-foreground` — so a theme can retune the surface and the ink together.
66
66
  - **Not** `foreground`. That is the ink for `background` only; on any other surface it is a contrast gamble that happens to pass in the default theme and fails in another.
67
- - **`tone-collectible-foreground`** — Ink paired with `tone-collectible`. Evaluate the rendered contrast together; never choose it independently. *Use for:* Whenever the background is `tone-collectible`. Use them as a pair — `bg-tone-collectible text-tone-collectible-foreground` — so a theme can retune the surface and the ink together.
67
+ - **`tone-2-foreground`** — Ink paired with `tone-2`. Evaluate the rendered contrast together; never choose it independently. *Use for:* Whenever the background is `tone-2`. Use them as a pair — `bg-tone-2 text-tone-2-foreground` — so a theme can retune the surface and the ink together.
68
68
  - **Not** `foreground`. That is the ink for `background` only; on any other surface it is a contrast gamble that happens to pass in the default theme and fails in another.
69
- - **`tone-edition-foreground`** — Ink paired with `tone-edition`. Evaluate the rendered contrast together; never choose it independently. *Use for:* Whenever the background is `tone-edition`. Use them as a pair — `bg-tone-edition text-tone-edition-foreground` — so a theme can retune the surface and the ink together.
69
+ - **`tone-1-foreground`** — Ink paired with `tone-1`. Evaluate the rendered contrast together; never choose it independently. *Use for:* Whenever the background is `tone-1`. Use them as a pair — `bg-tone-1 text-tone-1-foreground` — so a theme can retune the surface and the ink together.
70
70
  - **Not** `foreground`. That is the ink for `background` only; on any other surface it is a contrast gamble that happens to pass in the default theme and fails in another.
71
71
  - **`tone-info-foreground`** — Ink paired with `tone-info`. Evaluate the rendered contrast together; never choose it independently. *Use for:* Whenever the background is `tone-info`. Use them as a pair — `bg-tone-info text-tone-info-foreground` — so a theme can retune the surface and the ink together.
72
72
  - **Not** `foreground`. That is the ink for `background` only; on any other surface it is a contrast gamble that happens to pass in the default theme and fails in another.
@@ -173,11 +173,11 @@ Which token to reach for, and what it is most often confused with. Generated fro
173
173
 
174
174
  ### layout (11)
175
175
 
176
- - **`rhythm-unit`** — The vertical rhythm base — two spacing steps (8px at the default scale). Every vertical measure is a multiple of it, and it follows the density control with the spacing scale. *Use for:* Through `Stack`/`Row`/`Grid` gap numbers, which are rhythm units rather than pixels. A gap of 2 is 16px at the default scale, and grows or tightens with density.
176
+ - **`rhythm-unit`** — The vertical rhythm base — one baseline step (8px at the default scale). Every vertical measure is a multiple of it, and it follows the type and the density control. *Use for:* Through `Stack`/`Row`/`Grid` gap numbers, which are rhythm units rather than pixels. A gap of 2 is 16px at the default scale, and grows or tightens with density.
177
177
  - **Not** arbitrary vertical spacing. The rhythm is what makes unrelated sections of a page feel like one document.
178
178
  - **`grid-columns`** — The column count of the content grid — 12. *Use for:* `Grid`/`Columns`, WITHIN a region, for genuinely multi-column content.
179
179
  - **Not** using a column span as the page's reading width. A span is not a measure — see `measure-prose`.
180
- - **`grid-gutter`** — The gap between grid columns. *Use for:* `Grid`/`Columns` spacing.
180
+ - **`grid-gutter`** — The gap between grid columns and rows — 2 baseline steps on phones, 3 on desktop, snapped to the step. *Use for:* `Grid`/`Columns` spacing.
181
181
  - **`page-inset`** — The page's outer breathing room, left and right. *Use for:* The gutter between content and the viewport edge, at every breakpoint.
182
182
  - **Not** a global max-width. Sable caps width per REGION by role, never once for the whole page.
183
183
  - **`measure-prose`** — The maximum comfortable line length for prose, in `ch`. *Use for:* Any long-form text column.
@@ -335,4 +335,18 @@ Which token to reach for, and what it is most often confused with. Generated fro
335
335
  - **`hairline-strong`** — A hairline that must be seen — an input edge, a swatch ring. *Use for:* Bounding a control whose fill is arbitrary (a colour swatch) or user content.
336
336
  - **Not** `hairline`, when the line would otherwise disappear against what it bounds.
337
337
  - **`border-floating`** — The edge of a floating surface. Fainter than `border`: the shadow carries the elevation. *Use for:* Every floating surface — popover, menu, select, tooltip, dialog, sheet, toast, a floating panel — as `border-border-floating` or `ring-border-floating`, together with `bg-popover` and a `shadow-md`+ shadow. Derived for every theme (a faint alpha of the foreground); a theme may tune it with `--theme-border-floating`.
338
- - **Not** `border`. A full hairline plus a shadow stacks into a heavy outline around anything that floats. `border` is for resting edges: inputs, cards, badges.
338
+ - **Not** `border`. A full hairline plus a shadow stacks into a heavy outline around anything that floats. `border` is for resting edges: inputs, cards, badges.
339
+
340
+ ### Generated palette
341
+
342
+ More colour for apps, generated from the active theme: neutral and eight hue families, plus a 50–950 scale under every tone. Each family keeps its hue and leans toward the brand (half the gap, at most 15°; --theme-palette-harmony scales it, 0 = own hues). Neutral is the theme's --background mixed toward its --foreground. Steps follow the mode: low steps sit near the page and high ones far from it in light and dark alike, so a pair needs no dark: variant. For decorative and categorical colour (tags, avatars, labels, legends, illustration); surfaces, text and actions take roles. Components never name a step.
343
+
344
+ - **Families:** `neutral`, `red`, `orange`, `yellow`, `green`, `teal`, `blue`, `purple`, `pink`, each 50–950.
345
+ - **Tone scales:** `tone-1-*`, `tone-2-*`, `tone-3-*`, `tone-info-*`, `tone-warning-*`, `success-*`, `destructive-*`; step 500 is the tone itself.
346
+ - **Use as:** bg-blue-100, text-blue-800, border-neutral-200, bg-tone-1-100 — or var(--teal-500). Tailwind's other families (slate, gray, zinc, stone, amber, lime, emerald, cyan, sky, indigo, violet, fuchsia, rose) are switched off.
347
+ - **tag / label:** bg-<family>-100 text-<family>-800 (held to 4.5:1 in every theme and mode)
348
+ - **text on the page:** text-<family>-700
349
+ - **solid fill:** bg-<family>-700 text-<family>-50
350
+ - **hairline:** border-<family>-300
351
+ - **Components:** Badge, Pill and StatusDot take a family as tone (tone="blue"): a category with no meaning attached.
352
+ - **Slots:** data-palette="<family>" on an element fills these from that family, so one set of classes paints any family: bg-palette-wash text-palette-text.
@@ -101,7 +101,7 @@ The `@utility` and `@custom-variant` layer in `styles.css`: what each one is, wh
101
101
  - `<ol className="sable-list-numbered"><li>Install</li><li>Import the styles</li></ol>`
102
102
  - **`sable-list-dl`** — Label/value pairs on a native `<dl>`: muted label-tier `<dt>`s and body-tier `<dd>`s on a baseline-aligned two-column grid; long values wrap inside their column. Colour a status value with a `text-*` utility on its `<dd>`. *Use for:* Read-only details: an order summary, a record's metadata, a settings summary, profile stats.
103
103
  - **Instead of** A grid of `<div>`s (screen readers lose the term/value pairing), or Table for a single record. For editable values use Form and Field.
104
- - `<dl className="sable-list-dl"><dt>Network</dt><dd>Solana</dd><dt>Status</dt><dd className="text-success">Active</dd></dl>`
104
+ - `<dl className="sable-list-dl"><dt>Plan</dt><dd>Studio</dd><dt>Status</dt><dd className="text-success">Active</dd></dl>`
105
105
  - **`sable-list-dl-2`** — Two label/value pairs a row once the nearest `@container` ancestor is at least 28rem wide. Add to `sable-list-dl`. *Use for:* A compact metadata block in a wide card or panel. Put `@container` on a parent so it measures the room it actually has.
106
106
  - **Instead of** A viewport breakpoint, which gives a narrow card on a wide screen four columns it cannot fit.
107
107
  - `<div className="@container"><dl className="sable-list-dl sable-list-dl-2">…</dl></div>`
@@ -81,7 +81,10 @@ because the meta wins *whole* and silently discards the other.
81
81
 
82
82
  ## The hard rules
83
83
 
84
- 1. **Semantic tokens only** — never hex/oklch, never a raw palette step.
84
+ 1. **Semantic tokens only** — never hex/oklch, never a raw palette step, not
85
+ even the generated palette's (`bg-blue-500`; that is for apps). A component
86
+ that takes a palette family as `tone` sets `data-palette` to it and paints
87
+ from the slots that fills (`bg-palette-wash text-palette-text`), as Badge does.
85
88
  2. **Paired typography utilities** — never `text-{size}` + `font-{weight}`.
86
89
  3. **`primitives/` is behaviour, `components/` is the public API.** Base UI is
87
90
  wrapped and re-exported; consumers import only from the root barrel.
@@ -71,6 +71,25 @@ Pick each route's `max` by what the person mainly does on it:
71
71
  (a copy in `light` or `dark` wins over it); keep the role names and change
72
72
  the values.
73
73
 
74
+ ## Columns and rhythm
75
+
76
+ - **Flex or grid.** One direction is `Stack` (column) or `Row` (row). Content
77
+ that has to line up across rows *and* columns is `Grid`/`Columns`. A card's
78
+ single column is a `Stack`, never a one-track grid.
79
+ - **Columns are a choice per route.** Record it in the brief next to the width:
80
+ which content spans which of the 12 columns, and where it folds
81
+ (`<Col span={{ base: 12, lg: 8 }}>`). The grid does not fold on its own. A
82
+ route that is one reading measure has no columns, and the brief says so.
83
+ - **Vertical space is measured in lines.** The baseline is one line of body
84
+ text split into steps (8px at the default type). Gap numbers on `Stack`/
85
+ `Row`/`Grid` are steps; in Tailwind, even steps (`gap-4`, `py-6`, `mt-12`)
86
+ are whole steps and odd ones (`py-3`, `gap-5`) are half a step. Title to
87
+ description is one step, between groups one to two lines, between sections
88
+ three or more.
89
+ - **It is a rhythm, not a lock.** A card with a button or a code block is as
90
+ tall as its content. Keep the spacing between blocks in steps and let
91
+ components be; never pad or nudge them to pin text to lines.
92
+
74
93
  ## Typography: pick the tier by ROLE, not by size
75
94
 
76
95
  | tier | for | not |
@@ -100,6 +119,27 @@ intent, and what it gets confused with, is in
100
119
  Ink is never chosen independently of its surface: `bg-card text-card-foreground`,
101
120
  as a pair.
102
121
 
122
+ ### More colour: the generated palette
123
+
124
+ When a page needs colour that is not a role (tags, avatars, project labels, a
125
+ chart legend, illustration), reach for the generated palette, not hex and not a
126
+ theme's own ramp. Every theme has `neutral`, `red`, `orange`, `yellow`,
127
+ `green`, `teal`, `blue`, `purple` and `pink` (50–950), plus a scale under
128
+ every tone (`tone-1-100`, `success-700`). Each family leans toward the brand, so
129
+ the set belongs to the theme, and neutral is the theme's own page-to-ink ramp.
130
+
131
+ - On a component, the family is the tone: `<Badge tone="teal">Research</Badge>`,
132
+ `<Pill tone="blue">`, `<StatusDot tone="pink" />`. A family is a category with
133
+ no meaning attached; a status is still `success`, `warning` or `destructive`.
134
+ - On your own element, use the pairs: `bg-blue-100 text-blue-800` (a tag),
135
+ `text-blue-700` (text on the page), `bg-blue-700 text-blue-50` (a solid
136
+ fill), `border-blue-300` (a hairline). Steps follow the mode (a low step is
137
+ always near the page), so these need no `dark:`.
138
+ - Surfaces, body text and actions still take roles. The palette never replaces
139
+ `bg-card` or `bg-primary`.
140
+
141
+ The full reference is `llms/reference/token-intent.md` → Generated palette.
142
+
103
143
  ## The traps
104
144
 
105
145
  - **A `Card` is a container, not a heading or a landmark.** If its title is the
@@ -35,7 +35,9 @@ loudest and least clearly ("invalid hook call").
35
35
 
36
36
  The most reliable signal that a conversion is real: the app's own CSS variable
37
37
  block shrinks to almost nothing. Anything that remains should be *domain* colour,
38
- not UI colour.
38
+ not UI colour. Most domain colour has a home too: a tag or category colour maps
39
+ to a palette family (`<Badge tone="blue">`, `bg-blue-100 text-blue-800`), which
40
+ follows the theme where the app's own hex never did.
39
41
 
40
42
  Grep for orphaned references afterwards. A CSS variable that no longer exists
41
43
  resolves to nothing and the declaration is dropped — **silently**. A checkerboard
@@ -17,6 +17,10 @@ prints a complete starting record; the public `PRESET_TOKEN_NAMES` is authoritat
17
17
  Font stacks are requirements, not downloaded fonts. Declare matching stacks in
18
18
  the font metadata and tokens. Resolve internal palette variables before saving;
19
19
  portable presets may reference public Sable tokens, not private palette names.
20
+ A preset does not carry the generated palette (`bg-blue-500` and the rest): it is
21
+ computed from the preset's own primary, page and ink. `theme-palette-harmony`
22
+ (0 keeps the families' own hues, 1 is the default lean toward the brand) is the
23
+ one palette token a preset may set.
20
24
  The validator rejects unknown tokens and CSS that can escape its declaration.
21
25
  `sable preset --check` also holds labels on brand and status fills to 4.5:1 and APCA Lc 60
22
26
  and suggests a pair that reads; a preset may keep a pair deliberately through