@nuxtseo/design-system 0.0.0-stage → 0.1.1

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 (219) hide show
  1. package/README.md +181 -2
  2. package/app/app.config.ts +592 -0
  3. package/app/component-attributes.d.ts +8 -0
  4. package/app/components/README.md +38 -0
  5. package/app/components/brand/UiBrandMark.vue +63 -0
  6. package/app/components/brand/UiModuleIcon.vue +45 -0
  7. package/app/components/brand/UiProLettering.vue +26 -0
  8. package/app/components/brand/UiRangeTerrain.vue +311 -0
  9. package/app/components/brand/range-glyphs.ts +18 -0
  10. package/app/components/container/BrowserTab.vue +145 -0
  11. package/app/components/container/IntegrationRow.vue +120 -0
  12. package/app/components/container/KnowDoRails.vue +40 -0
  13. package/app/components/container/RailPanel.vue +93 -0
  14. package/app/components/container/UiAlert.vue +120 -0
  15. package/app/components/container/UiAppShell.vue +165 -0
  16. package/app/components/container/UiCard.vue +204 -0
  17. package/app/components/container/UiDisclosure.vue +43 -0
  18. package/app/components/container/UiEmptyState.vue +102 -0
  19. package/app/components/container/UiErrorState.vue +61 -0
  20. package/app/components/container/UiLoadingState.vue +20 -0
  21. package/app/components/container/UiPageHeader.vue +95 -0
  22. package/app/components/container/UiPopover.vue +102 -0
  23. package/app/components/container/UiSampleDataOverlay.vue +47 -0
  24. package/app/components/container/UiSectionHeader.vue +83 -0
  25. package/app/components/container/UiSummaryStrip.vue +40 -0
  26. package/app/components/container/UiToast.vue +230 -0
  27. package/app/components/container/UiToaster.vue +271 -0
  28. package/app/components/container/UiWidgetState.vue +143 -0
  29. package/app/components/container/ui-nav-drawer.ts +48 -0
  30. package/app/components/data/ActionRail.vue +152 -0
  31. package/app/components/data/FacetStrip.vue +93 -0
  32. package/app/components/data/UiBarCell.vue +37 -0
  33. package/app/components/data/UiBarChart.vue +281 -0
  34. package/app/components/data/UiChartAnnotationControls.vue +74 -0
  35. package/app/components/data/UiChartAnnotations.vue +163 -0
  36. package/app/components/data/UiChartBrushOverlay.vue +96 -0
  37. package/app/components/data/UiChartDataReveal.vue +81 -0
  38. package/app/components/data/UiChartFrame.vue +123 -0
  39. package/app/components/data/UiChartTooltip.vue +81 -0
  40. package/app/components/data/UiCoverageNote.vue +90 -0
  41. package/app/components/data/UiCwvSparkline.vue +188 -0
  42. package/app/components/data/UiDataList.vue +276 -0
  43. package/app/components/data/UiDataTableSection.vue +233 -0
  44. package/app/components/data/UiDistributionBars.vue +164 -0
  45. package/app/components/data/UiDonutChart.vue +132 -0
  46. package/app/components/data/UiDoorwayColumn.vue +108 -0
  47. package/app/components/data/UiDoorwayGrid.vue +58 -0
  48. package/app/components/data/UiDoorwayRow.vue +83 -0
  49. package/app/components/data/UiEntitySummary.vue +261 -0
  50. package/app/components/data/UiFactsGrid.vue +107 -0
  51. package/app/components/data/UiImpactMeter.vue +33 -0
  52. package/app/components/data/UiIssueRow.vue +149 -0
  53. package/app/components/data/UiLineChart.vue +431 -0
  54. package/app/components/data/UiMetricBarPopover.vue +121 -0
  55. package/app/components/data/UiMetricLabel.vue +30 -0
  56. package/app/components/data/UiMetricStat.vue +73 -0
  57. package/app/components/data/UiMetricToggle.vue +156 -0
  58. package/app/components/data/UiMetricsRow.vue +64 -0
  59. package/app/components/data/UiPositionMetric.vue +53 -0
  60. package/app/components/data/UiRelatedFixes.vue +113 -0
  61. package/app/components/data/UiRichText.vue +325 -0
  62. package/app/components/data/UiScatterPlot.vue +144 -0
  63. package/app/components/data/UiSeverityMarker.vue +30 -0
  64. package/app/components/data/UiSparkColumns.vue +160 -0
  65. package/app/components/data/UiSparkline.vue +681 -0
  66. package/app/components/data/UiStat.vue +445 -0
  67. package/app/components/data/UiStats.vue +76 -0
  68. package/app/components/data/UiTable.vue +517 -0
  69. package/app/components/data/UiTableExport.vue +40 -0
  70. package/app/components/data/UiTableFrame.vue +149 -0
  71. package/app/components/data/UiTablePagination.vue +37 -0
  72. package/app/components/data/UiTableShell.vue +48 -0
  73. package/app/components/data/UiTableTd.vue +39 -0
  74. package/app/components/data/UiTableTh.vue +61 -0
  75. package/app/components/data/UiTopEntityStackChart.vue +393 -0
  76. package/app/components/data/cells/UiTableDash.vue +3 -0
  77. package/app/components/data/cells/UiTableHeaderCell.vue +72 -0
  78. package/app/components/data/cells/UiTableMetricCell.vue +72 -0
  79. package/app/components/data/cells/UiTablePathCell.vue +76 -0
  80. package/app/components/data/cells/UiTableScoreTile.vue +49 -0
  81. package/app/components/data/cells/UiTableTrendCell.vue +41 -0
  82. package/app/components/element/UiAtmosphere.vue +64 -0
  83. package/app/components/element/UiAuthHeading.vue +24 -0
  84. package/app/components/element/UiAuthProviders.vue +46 -0
  85. package/app/components/element/UiBrandIcon.vue +39 -0
  86. package/app/components/element/UiButton.vue +549 -0
  87. package/app/components/element/UiCelebration.vue +65 -0
  88. package/app/components/element/UiChannelChips.vue +62 -0
  89. package/app/components/element/UiChatQuickLink.vue +319 -0
  90. package/app/components/element/UiChip.vue +101 -0
  91. package/app/components/element/UiConfirmDialog.vue +84 -0
  92. package/app/components/element/UiCopyButton.vue +90 -0
  93. package/app/components/element/UiDitherAvatar.vue +177 -0
  94. package/app/components/element/UiDotLabel.vue +19 -0
  95. package/app/components/element/UiEjectMenu.vue +181 -0
  96. package/app/components/element/UiEjectOverlay.vue +29 -0
  97. package/app/components/element/UiFavicon.vue +235 -0
  98. package/app/components/element/UiFaviconStack.vue +84 -0
  99. package/app/components/element/UiFilterMenu.vue +324 -0
  100. package/app/components/element/UiFocusedSurface.vue +129 -0
  101. package/app/components/element/UiHealthDot.vue +32 -0
  102. package/app/components/element/UiHelpLabel.vue +28 -0
  103. package/app/components/element/UiIcon.vue +22 -0
  104. package/app/components/element/UiInput.vue +35 -0
  105. package/app/components/element/UiLogoPlausible.vue +12 -0
  106. package/app/components/element/UiLogoPro.vue +25 -0
  107. package/app/components/element/UiLogoUmami.vue +12 -0
  108. package/app/components/element/UiNavIcon.vue +107 -0
  109. package/app/components/element/UiNavList.vue +156 -0
  110. package/app/components/element/UiOnboardingAnswers.vue +127 -0
  111. package/app/components/element/UiOverflowCount.vue +31 -0
  112. package/app/components/element/UiProBadge.vue +19 -0
  113. package/app/components/element/UiProgressCircle.vue +79 -0
  114. package/app/components/element/UiProgressPercent.vue +35 -0
  115. package/app/components/element/UiRelativeTime.vue +58 -0
  116. package/app/components/element/UiScrollFade.vue +16 -0
  117. package/app/components/element/UiSelect.vue +68 -0
  118. package/app/components/element/UiSeverityDot.vue +27 -0
  119. package/app/components/element/UiSiteFavicon.vue +24 -0
  120. package/app/components/element/UiSkeleton.vue +148 -0
  121. package/app/components/element/UiSlotText.vue +65 -0
  122. package/app/components/element/UiSourceLogos.vue +113 -0
  123. package/app/components/element/UiSourceRail.vue +71 -0
  124. package/app/components/element/UiStaticTerminal.vue +107 -0
  125. package/app/components/element/UiStatusBadge.vue +62 -0
  126. package/app/components/element/UiSyncDot.vue +46 -0
  127. package/app/components/element/UiTabs.vue +245 -0
  128. package/app/components/element/UiTogglePill.vue +86 -0
  129. package/app/components/element/UiTooltip.vue +390 -0
  130. package/app/components/element/UiTooltipGrid.vue +457 -0
  131. package/app/components/element/UiTrend.vue +184 -0
  132. package/app/components/element/UiTrialBenefits.vue +71 -0
  133. package/app/components/element/UiUrlLabel.vue +75 -0
  134. package/app/components/element/UiValenceDot.vue +37 -0
  135. package/app/components/element/UiWizardModal.vue +284 -0
  136. package/app/components/element/UiWizardNav.vue +59 -0
  137. package/app/components/element/UiWizardProgress.vue +78 -0
  138. package/app/components/element/UiWizardShell.vue +43 -0
  139. package/app/components/element/eject-menu.ts +359 -0
  140. package/app/components/element/eject-tracker.ts +34 -0
  141. package/app/components/element/onboarding-answers.ts +93 -0
  142. package/app/components/element/onboarding-intents.ts +19 -0
  143. package/app/composables/dataVizColors.ts +350 -0
  144. package/app/composables/formatting.ts +252 -0
  145. package/app/composables/semanticColors.ts +80 -0
  146. package/app/composables/useActivityOverlay.ts +55 -0
  147. package/app/composables/useAppShellNav.ts +21 -0
  148. package/app/composables/useChartBrush.ts +221 -0
  149. package/app/composables/useChartHover.ts +153 -0
  150. package/app/composables/useChartTickPlan.ts +186 -0
  151. package/app/composables/useCloseOnNavigation.ts +7 -0
  152. package/app/composables/useConfirm.ts +38 -0
  153. package/app/composables/useEdgeFade.ts +37 -0
  154. package/app/composables/useEject.ts +69 -0
  155. package/app/composables/useEntranceMotion.ts +22 -0
  156. package/app/composables/useFaviconBacking.ts +164 -0
  157. package/app/composables/useGridCols.ts +39 -0
  158. package/app/composables/useIssueOverlay.ts +43 -0
  159. package/app/composables/useOnboardingService.ts +106 -0
  160. package/app/composables/useOpenedOnce.ts +19 -0
  161. package/app/composables/useScrollSpy.ts +178 -0
  162. package/app/composables/useSquircleFallback.ts +21 -0
  163. package/app/composables/useWizardRoute.ts +123 -0
  164. package/app/plugins/favicon.ts +15 -0
  165. package/app/plugins/lazy-motion.ts +22 -0
  166. package/app/plugins/selection-highlight.client.ts +176 -0
  167. package/app/shared/cli.ts +10 -0
  168. package/app/shared/error-state.ts +150 -0
  169. package/app/shared/icons.ts +1 -0
  170. package/app/shared/motion.ts +1 -0
  171. package/app/shared/nav.ts +38 -0
  172. package/app/shared/navigation.ts +5 -0
  173. package/app/shared/static-terminal.ts +14 -0
  174. package/app/shared/table-export.ts +36 -0
  175. package/app/shared/table.ts +105 -0
  176. package/app/shared/ui-icons.ts +1 -0
  177. package/app/shared/view-state.ts +85 -0
  178. package/app/shared/widget-failure.ts +126 -0
  179. package/app/utils/app-favicon.ts +64 -0
  180. package/app/utils/chartAnnotations.ts +326 -0
  181. package/app/utils/countries.ts +337 -0
  182. package/app/utils/export-download.ts +100 -0
  183. package/app/utils/favicon-fallback.ts +12 -0
  184. package/app/utils/icon-color.ts +105 -0
  185. package/app/utils/number.ts +74 -0
  186. package/app/utils/render-link.ts +14 -0
  187. package/app/utils/slot-text.ts +18 -0
  188. package/app/utils/squircle.ts +154 -0
  189. package/app/utils/topEntityStack.ts +197 -0
  190. package/app/utils/vue.ts +57 -0
  191. package/build/design-system.ts +69 -0
  192. package/build/external-links.ts +38 -0
  193. package/build/fonts.ts +39 -0
  194. package/build/icon-server-bundle.ts +276 -0
  195. package/build/runtime/icon-server-bundle.ts +29 -0
  196. package/css/global.css +1896 -0
  197. package/nuxt.config.ts +143 -0
  198. package/package.json +93 -3
  199. package/public/fonts/README.md +33 -0
  200. package/public/fonts/fira-code-OFL.txt +93 -0
  201. package/public/fonts/fira-code-var-latin.woff2 +0 -0
  202. package/public/fonts/hubot-sans-OFL.txt +93 -0
  203. package/public/fonts/hubot-sans-var-latin.woff2 +0 -0
  204. package/server/api/favicon.get.ts +122 -0
  205. package/server/utils/favicon-source.ts +51 -0
  206. package/shared/contracts/feedback.ts +42 -0
  207. package/shared/contracts/index.ts +1 -0
  208. package/shared/delivery-channels.ts +53 -0
  209. package/shared/icons/index.ts +143 -0
  210. package/shared/icons/registry.ts +347 -0
  211. package/shared/icons/ui-slots.ts +58 -0
  212. package/shared/markdown.ts +44 -0
  213. package/shared/motion.ts +120 -0
  214. package/shared/rangi.ts +60 -0
  215. package/shared/rich-text.ts +34 -0
  216. package/shared/ui-icons.ts +6 -0
  217. package/shared/utils/urls.ts +64 -0
  218. package/types/index.ts +1 -0
  219. package/types/ui.ts +339 -0
package/README.md CHANGED
@@ -1,3 +1,182 @@
1
- # Temporary Holding Version
1
+ # Design System
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The design rules and rationale live in [`DESIGN.md`](../../DESIGN.md) (repo root) and this layer's [`AGENTS.md`](AGENTS.md); dated judgment calls in [`docs/design-decisions.md`](../../docs/design-decisions.md). This layer is the implementation those documents describe. When they disagree, the code here wins and the doc gets fixed.
4
+
5
+ Design system layer: design language extended by every app. It owns UI primitives, tokens, fonts, motion, chart helpers, formatters, design vocabularies (`Status`, severity, health, data-viz palette), and cross-cutting UI affordances (eject, feedback widget contracts).
6
+
7
+ ## Scope
8
+
9
+ **Owns:**
10
+ - UI primitives under `app/components/{container,data,element}/`
11
+ - Design tokens, fonts, motion, chart helpers
12
+ - Formatters and design vocabularies (`Status`, severity, health, data-viz palette)
13
+ - Cross-cutting UI affordances (eject, feedback widget contracts)
14
+ - CSS tokens and global stylesheet (`css/`)
15
+
16
+ **Depends on:** `nuxtseo-shared` (brand marks) and the published Nuxt modules in `package.json`. No workspace package.
17
+
18
+ **Consumed by:** `layers/brand`, which every Nuxt SEO app (`apps/site`, `apps/pro`, `apps/admin`, `apps/brand-kit`) extends in its place, and outside sites through the [npm](https://npmjs.com) package `@nuxtseo/design-system`.
19
+
20
+ ## Rules
21
+
22
+ - Per ADR-0042 (pragmatic rule): MAY know domain *shapes*; MUST NOT import runtime services. No `useFetch`, [Drizzle](https://orm.drizzle.team), Caller, billing, auth, or `useRuntimeConfig` at module scope. [Storybook](https://storybook.js.org) test: renders with prop fixtures alone.
23
+ - Component placement per ADR-0029. Components MUST NOT be prefixed `Pro/Admin/Tool/Docs/Learn`; the layer name is the scope.
24
+ - One of only two layers (with `core`) every app extends.
25
+
26
+ ## Consuming this layer
27
+
28
+ Outside this repository, install the published package and extend it.
29
+
30
+ ```bash
31
+ pnpm add @nuxtseo/design-system
32
+ pnpm add -D typescript@^6
33
+ ```
34
+
35
+ ```ts
36
+ // nuxt.config.ts
37
+ export default defineNuxtConfig({
38
+ extends: ['@nuxtseo/design-system'],
39
+ })
40
+ ```
41
+
42
+ - Peers: `nuxt` 4.6+, `vue` 3.5+, `typescript` 5.8 to 6, `@nuxt/ui` 4.11+, `motion-v` 2.4+, `tailwindcss` 4.3+, and `zod` 4. The Vue SFC compiler resolves the layer's prop types through the TypeScript JS API, and TypeScript 7 has none.
43
+ - The layer shares your copy of each peer, so the app runs one Nuxt UI, one Tailwind, one motion-v context, and one zod. pnpm and npm install a missing peer for you. You need no `overrides` for the layer.
44
+ - If [pnpm](https://pnpm.io) reports ignored build scripts, allow `esbuild` and `@parcel/watcher` under `allowBuilds` in `pnpm-workspace.yaml`.
45
+ - Import components from `#components`. The layer turns auto-imports off, in Nitro too.
46
+ - Write `app.config.ts` as a plain object. `defineAppConfig` is an auto-import, so the server bundle has no such function.
47
+ - Import other modules by their path: `@nuxtseo/design-system/app/composables/formatting`. A directory with an `index.ts` imports by its name: `@nuxtseo/design-system/shared/icons`, `@nuxtseo/design-system/shared/contracts`, and `@nuxtseo/design-system/types`.
48
+ - The layer ships no favicon and loads no fonts. Set both through the brand seams below.
49
+
50
+ ### Overrides
51
+
52
+ | What | How |
53
+ | --- | --- |
54
+ | Nuxt UI colours, slots, icons, toaster, favicon paths | `app.config.ts` in your app. It merges over the layer's `app/app.config.ts`. |
55
+ | Tokens: colours, fonts, density, elevation | CSS custom properties in your own stylesheet, loaded after the layer's `css/global.css`. Override `--ui-*`, `--font-*`, `--density-*`, and `--elevation-*`; never `--_depth-*` or `--_viz-*`. |
56
+ | One instance | Props and slots on the component. |
57
+ | Icon set, chart colours, icon colour roles | The brand seams below. |
58
+
59
+ Same-name shadowing does not work. A component in your `app/components/` with a layer component's name loses: the layer registers its components at priority 10. A composable with a layer composable's name is never used: layer files import each other by path. If you need a change that props, slots, tokens, or `app.config` cannot express, open an issue for a new prop or slot.
60
+
61
+ ### Releasing
62
+
63
+ The UI packages release on their own `ui-v*` tag, apart from the `public-v*` CLI cohort.
64
+
65
+ 1. Set the version: `pnpm --dir layers/design-system pkg set version=X.Y.Z`. Merge it to `main` through a pull request.
66
+ 2. Check it: `pnpm release:ui:check ui-vX.Y.Z`.
67
+ 3. Pack and smoke it: `pnpm --dir layers/design-system pack --pack-destination /tmp/ui`, then `pnpm release:ui:smoke /tmp/ui/nuxtseo-design-system-X.Y.Z.tgz`.
68
+ 4. Tag the merged commit `ui-vX.Y.Z` and push the tag. `.github/workflows/publish-ui-packages.yml` verifies, packs, smokes, and publishes. A prerelease such as `X.Y.Z-beta.1` goes to the `next` dist-tag.
69
+
70
+ ## Brand seams
71
+
72
+ A site that extends this layer cannot shadow its components or composables: they register at priority 10 and auto-import is off. It sets its brand through these seams instead. Unset, each seam renders what Nuxt SEO renders.
73
+
74
+ **Icon set.** Pick the set every semantic icon role renders from. The default is `hugeicons`. Install the matching `@iconify-json/<set>` collection. The icon aliases, the client bundle, and the server icon bundle follow the choice.
75
+
76
+ ```ts
77
+ // nuxt.config.ts
78
+ export default defineNuxtConfig({
79
+ extends: ['@nuxtseo/design-system'],
80
+ designSystem: { iconSet: 'lucide' },
81
+ })
82
+ ```
83
+
84
+ **Favicon.** The layer's favicon plugin emits a theme-aware icon link and an Apple touch icon link from `favicon` in `app.config.ts`. Unset, it emits neither. Each link's MIME type follows the file extension, so an SVG declares `image/svg+xml`. A mode without its own path uses the other mode's path. The links carry `id: 'favicon'` and `id: 'apple-touch-icon'`.
85
+
86
+ ```ts
87
+ // app.config.ts
88
+ export default {
89
+ favicon: {
90
+ light: '/icon-light.svg',
91
+ dark: '/icon-dark.svg',
92
+ appleTouchLight: '/touch-icon.png',
93
+ appleTouchDark: '/touch-icon-dark.png',
94
+ },
95
+ }
96
+ ```
97
+
98
+ **Type.** Set `--font-sans`, `--font-display`, `--font-title`, and `--font-mono` in your stylesheet, and register the faces with `fonts.families`. `--font-title` carries page titles (`.text-title` and the `font-title` utility). Its default is the display family. The layer self-hosts Nuxt SEO's Hubot Sans and Fira Code but registers neither by default, so no page preloads them. To use them, opt in:
99
+
100
+ ```ts
101
+ // nuxt.config.ts
102
+ export default defineNuxtConfig({
103
+ extends: ['@nuxtseo/design-system'],
104
+ designSystem: { fonts: true },
105
+ })
106
+ ```
107
+
108
+ **Own-site links.** An absolute HTTP or HTTPS prose link gets an external-link arrow. List the hosts that count as your site, and links to them get none. Unset, the layer lists no host.
109
+
110
+ ```ts
111
+ // nuxt.config.ts
112
+ export default defineNuxtConfig({
113
+ designSystem: { internalLinkHosts: ['example.com', 'www.example.com'] },
114
+ })
115
+ ```
116
+
117
+ **OG images.** [nuxt-og-image](https://nuxtseo.com/docs/og-image) compiles OG images against one Tailwind entry: the `#tailwindcss` alias, or else the first CSS entry that imports Tailwind, which is the layer's. Runtime `:root` overrides never reach it. To give OG images your theme, write an entry that imports the layer's stylesheet and restates your theme values. Then point the alias at it. Browsers never load this file.
118
+
119
+ ```css
120
+ /* app/assets/css/og-theme.css */
121
+ @import '@nuxtseo/design-system/css/global.css';
122
+
123
+ @theme {
124
+ --font-sans: 'DM Sans', system-ui, sans-serif;
125
+ --font-display: 'Poppins', system-ui, sans-serif;
126
+ --font-title: 'Poppins', system-ui, sans-serif;
127
+ }
128
+ ```
129
+
130
+ ```ts
131
+ // nuxt.config.ts
132
+ export default defineNuxtConfig({
133
+ alias: { '#tailwindcss': fileURLToPath(new URL('./app/assets/css/og-theme.css', import.meta.url)) },
134
+ })
135
+ ```
136
+
137
+ **Text and dashboard neutrals.** Three light mode text tokens sit on Nuxt SEO's violet hue, off the neutral ramp. The dashboard (`.dashboard-theme`) swaps the neutral ramp to mauve. Set these properties to re-hue them; never override the selectors. Unset, each keeps Nuxt SEO's value.
138
+
139
+ | Property | Sets |
140
+ | --- | --- |
141
+ | `--ui-light-text`, `--ui-light-text-dimmed`, `--ui-light-text-highlighted` | `--ui-text`, `--ui-text-dimmed`, `--ui-text-highlighted` in light mode |
142
+ | `--ui-dashboard-neutral-50` to `--ui-dashboard-neutral-950` | The dashboard's neutral ramp, both modes |
143
+ | `--ui-dashboard-light-text-dimmed` | Dashboard `--ui-text-dimmed`, light mode |
144
+ | `--ui-dashboard-dark-text-dimmed`, `--ui-dashboard-dark-text-muted` | Dashboard `--ui-text-dimmed` and `--ui-text-muted`, dark mode |
145
+
146
+ ```css
147
+ :root {
148
+ --ui-light-text: var(--color-olive-800);
149
+ --ui-dashboard-neutral-50: var(--color-olive-50);
150
+ /* and each step to 950 */
151
+ }
152
+ ```
153
+
154
+ A `var()` inside a custom property resolves on the element that declares it. So `:root { --ui-dashboard-dark-text-muted: var(--ui-color-neutral-400) }` reads the marketing ramp's 400 step. Name a fixed colour or a `--color-*` step instead.
155
+
156
+ **Chart colours.** Every chart identity slot in `dataVizColors.ts` reads a `--ui-viz-<slot>` custom property: `clicks`, `impressions`, `ctr`, `position`, `sessions`, `users`, `pageviews`, `lcp`, `inp`, `cls`, `current`, `comparison`, `device-desktop`, `device-mobile`, `device-tablet`, `brand`, `non-brand`, `rank-1` to `rank-10`, `resource-document`, `resource-script`, `resource-stylesheet`, `resource-image`, `resource-font`, `category-1` to `category-5`, and `neutral`. The SVG paint, the `bg-viz-*` and `text-viz-*` classes, and the `/15` fills all follow it. Unset, light mode reads a deeper default for any slot whose stock hue falls under 3:1 on white; dark mode keeps the stock hue. Text classes use the mark colour unless `--ui-viz-<slot>-text` is set. If the mark colour fails AA as text, set it.
157
+
158
+ ```css
159
+ :root {
160
+ --ui-viz-clicks: var(--ui-primary);
161
+ --ui-viz-neutral: #94a3b8;
162
+ --ui-viz-comparison: #a3a292;
163
+ --ui-viz-comparison-text: #67713a;
164
+ }
165
+ ```
166
+
167
+ A palette `hex` field is a CSS colour, such as `var(--ui-viz-clicks, #3b82f6)`. Mix it with `color-mix()`; never parse it as hex.
168
+
169
+ **Icon colour roles.** Add or remap a role that `getIconColor()` resolves. Write the classes in full, so Tailwind finds them in your source.
170
+
171
+ ```ts
172
+ // app.config.ts
173
+ export default {
174
+ designSystem: {
175
+ iconColors: { lime: { bg: 'bg-lime-500/10', text: 'text-lime-500' } },
176
+ },
177
+ }
178
+ ```
179
+
180
+ **Onboarding copy.** `UiOnboardingAnswers` takes an `intents` prop for the goal list and a `copy` prop for its strings: `roleQuestion`, `siteCountQuestion`, `seoExperienceQuestion`, `intentsQuestion`, `intentsHint`, `otherLabel`, and `otherPlaceholder`. Pass any of them. Unset keys keep the strings in `ONBOARDING_ANSWERS_COPY`. Onboarding Answers store the option ids, so the ids never change.
181
+
182
+ **Motion.** The layer provides motion-v's `domAnimation` features to the whole app, `error.vue` included. A site needs no `<LazyMotion>` wrapper.