@humanforest/nuxt-layer 0.1.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 (324) hide show
  1. package/LICENSE +67 -0
  2. package/README.md +208 -0
  3. package/app.config.ts +10 -0
  4. package/assets/icons/forest/bike-asterisk.svg +21 -0
  5. package/assets/icons/forest/bike-down.svg +19 -0
  6. package/assets/icons/forest/bike-off.svg +20 -0
  7. package/assets/icons/forest/bike-up.svg +19 -0
  8. package/assets/icons/forest/bike-x.svg +19 -0
  9. package/assets/icons/forest/bike.svg +18 -0
  10. package/assets/icons/forest/mark-fill.svg +6 -0
  11. package/assets/icons/forest/mark.svg +6 -0
  12. package/assets/icons/forest/parking.svg +3 -0
  13. package/assets/icons/forest/star-fill.svg +4 -0
  14. package/assets/icons/forest/star.svg +4 -0
  15. package/assets/icons/forest/traffic-light-caution.svg +8 -0
  16. package/assets/icons/forest/traffic-light-go.svg +8 -0
  17. package/assets/icons/forest/traffic-light-lit.svg +8 -0
  18. package/assets/icons/forest/traffic-light-stop.svg +8 -0
  19. package/assets/icons/forest/traffic-light.svg +8 -0
  20. package/nuxt.config.ts +81 -0
  21. package/package.json +35 -0
  22. package/packages/charts/src/FBoroughShape.vue +52 -0
  23. package/packages/charts/src/FCalendarGrid.vue +332 -0
  24. package/packages/charts/src/FCellLegend.vue +54 -0
  25. package/packages/charts/src/FChartFrame.vue +201 -0
  26. package/packages/charts/src/FChartFrameSingle.vue +91 -0
  27. package/packages/charts/src/FChartLegend.vue +26 -0
  28. package/packages/charts/src/FDistributionBar.vue +224 -0
  29. package/packages/charts/src/FDottedMap.vue +335 -0
  30. package/packages/charts/src/FLondonMap.vue +399 -0
  31. package/packages/charts/src/FSparkline.vue +198 -0
  32. package/packages/charts/src/FStatusTrack.vue +151 -0
  33. package/packages/charts/src/cellSize.ts +46 -0
  34. package/packages/charts/src/distribution.ts +99 -0
  35. package/packages/charts/src/engine.ts +15 -0
  36. package/packages/charts/src/forestTooltip.ts +110 -0
  37. package/packages/charts/src/fromCategories.ts +43 -0
  38. package/packages/charts/src/index.ts +87 -0
  39. package/packages/charts/src/londonAreas.ts +75 -0
  40. package/packages/charts/src/londonGrid.ts +67 -0
  41. package/packages/charts/src/motionDuration.ts +49 -0
  42. package/packages/charts/src/presets.ts +143 -0
  43. package/packages/charts/src/resolveVar.ts +21 -0
  44. package/packages/charts/src/snapTooltip.ts +154 -0
  45. package/packages/charts/src/tooltipStandIn.ts +58 -0
  46. package/packages/charts/src/useCellScale.ts +155 -0
  47. package/packages/charts/src/useChartPalette.ts +61 -0
  48. package/packages/charts/src/useChartRepaintKey.ts +22 -0
  49. package/packages/charts/src/useThemeVersion.ts +17 -0
  50. package/packages/frames/src/FBrowserFrame.vue +53 -0
  51. package/packages/frames/src/FDeviceFrame.vue +242 -0
  52. package/packages/frames/src/FFitFrame.vue +83 -0
  53. package/packages/frames/src/art/iphone-11.svg +124 -0
  54. package/packages/frames/src/art/iphone-12.svg +601 -0
  55. package/packages/frames/src/art/iphone-13-pro.svg +820 -0
  56. package/packages/frames/src/art/iphone-13.svg +849 -0
  57. package/packages/frames/src/art/iphone-14.svg +681 -0
  58. package/packages/frames/src/art/iphone-15-pro.svg +633 -0
  59. package/packages/frames/src/art/iphone-15.svg +713 -0
  60. package/packages/frames/src/art/iphone-16-plus.svg +685 -0
  61. package/packages/frames/src/art/iphone-16-pro-max.svg +611 -0
  62. package/packages/frames/src/art/iphone-16-pro.svg +631 -0
  63. package/packages/frames/src/art/iphone-16.svg +713 -0
  64. package/packages/frames/src/art/iphone-17-pro-max.svg +355 -0
  65. package/packages/frames/src/art/iphone-17.svg +305 -0
  66. package/packages/frames/src/art/iphone-air.svg +389 -0
  67. package/packages/frames/src/art/iphone-se-3.svg +473 -0
  68. package/packages/frames/src/art/iphone-x.svg +652 -0
  69. package/packages/frames/src/art/pixel-10-pro-xl.svg +32 -0
  70. package/packages/frames/src/art/pixel-10-pro.svg +32 -0
  71. package/packages/frames/src/art/pixel-10.svg +32 -0
  72. package/packages/frames/src/art/pixel-8-pro.svg +208 -0
  73. package/packages/frames/src/art/pixel-8.svg +208 -0
  74. package/packages/frames/src/art/pixel-8a.svg +8 -0
  75. package/packages/frames/src/art/pixel-9-pro-xl.svg +32 -0
  76. package/packages/frames/src/art/pixel-9-pro.svg +34 -0
  77. package/packages/frames/src/art/pixel-9a.svg +25 -0
  78. package/packages/frames/src/art.ts +29 -0
  79. package/packages/frames/src/devices.ts +337 -0
  80. package/packages/frames/src/index.ts +15 -0
  81. package/packages/tokens/geo/london-boroughs.json +1 -0
  82. package/packages/tokens/geo/london-dots-coarse.json +1 -0
  83. package/packages/tokens/geo/london-dots-fine.json +1 -0
  84. package/packages/tokens/geo/london-dots-medium.json +1 -0
  85. package/packages/tokens/geo/london-dots-ultra.json +1 -0
  86. package/packages/tokens/geo/london-wards.json +1 -0
  87. package/packages/tokens/glyphs/glyphs.json +1 -0
  88. package/packages/tokens/logos/f-rot.svg +4 -0
  89. package/packages/tokens/logos/f.svg +4 -0
  90. package/packages/tokens/logos/favicon-c2w.svg +9 -0
  91. package/packages/tokens/logos/favicon-console.svg +9 -0
  92. package/packages/tokens/logos/favicon-ds.svg +9 -0
  93. package/packages/tokens/logos/favicon-fleet.svg +9 -0
  94. package/packages/tokens/logos/favicon-flex.svg +9 -0
  95. package/packages/tokens/logos/favicon-plus.svg +9 -0
  96. package/packages/tokens/logos/favicon-radar.svg +9 -0
  97. package/packages/tokens/logos/favicon-tower.svg +9 -0
  98. package/packages/tokens/logos/lockup-horizontal.svg +17 -0
  99. package/packages/tokens/logos/lockup-vertical.svg +17 -0
  100. package/packages/tokens/logos/mark-mono.svg +4 -0
  101. package/packages/tokens/logos/mark.svg +7 -0
  102. package/packages/tokens/logos/wordmark.svg +9 -0
  103. package/packages/tokens/src/colourEngine.ts +604 -0
  104. package/packages/tokens/src/glyphs.ts +127 -0
  105. package/packages/tokens/src/logo.ts +50 -0
  106. package/packages/tokens/src/subbrands.ts +44 -0
  107. package/packages/tokens/src/sublogo.ts +80 -0
  108. package/packages/ui/icons/forest/map/forest-place-count.svg +21 -0
  109. package/packages/ui/icons/forest/map/forest-place-marker.svg +17 -0
  110. package/packages/ui/icons/forest/map/forest-vehicle-marker.svg +73 -0
  111. package/packages/ui/icons/forest/map/manifest.json +373 -0
  112. package/packages/ui/icons/forest/map/place-count-manifest.json +83 -0
  113. package/packages/ui/icons/forest/map/place-manifest.json +74 -0
  114. package/packages/ui/src/address/address.ts +125 -0
  115. package/packages/ui/src/address/autofill.ts +78 -0
  116. package/packages/ui/src/address/geocode.ts +55 -0
  117. package/packages/ui/src/address/index.ts +31 -0
  118. package/packages/ui/src/address/validate.ts +91 -0
  119. package/packages/ui/src/canvas/FCanvasCard.vue +97 -0
  120. package/packages/ui/src/canvas/FCanvasControl.vue +121 -0
  121. package/packages/ui/src/canvas/FCanvasControlGroup.vue +100 -0
  122. package/packages/ui/src/canvas/FCanvasFlyout.vue +216 -0
  123. package/packages/ui/src/canvas/FCanvasHud.vue +402 -0
  124. package/packages/ui/src/canvas/canvasSurface.ts +39 -0
  125. package/packages/ui/src/canvas/index.ts +17 -0
  126. package/packages/ui/src/contexts/ForestContext.vue +53 -0
  127. package/packages/ui/src/contexts/contexts.ts +153 -0
  128. package/packages/ui/src/contexts/index.ts +23 -0
  129. package/packages/ui/src/contexts/marketing-theme.ts +214 -0
  130. package/packages/ui/src/contexts/mobile-theme.ts +402 -0
  131. package/packages/ui/src/filter/FFilterBar.vue +72 -0
  132. package/packages/ui/src/filter/FFilterChip.vue +362 -0
  133. package/packages/ui/src/filter/FFilterClauses.vue +104 -0
  134. package/packages/ui/src/filter/FFilterTrigger.vue +183 -0
  135. package/packages/ui/src/filter/filter.theme.ts +27 -0
  136. package/packages/ui/src/filter/filterClause.ts +265 -0
  137. package/packages/ui/src/filter/filterPredicate.ts +134 -0
  138. package/packages/ui/src/filter/filterSchema.ts +82 -0
  139. package/packages/ui/src/filter/index.ts +36 -0
  140. package/packages/ui/src/forest-preset.ts +68 -0
  141. package/packages/ui/src/icons.ts +79 -0
  142. package/packages/ui/src/index.ts +17 -0
  143. package/packages/ui/src/kpi/FKpi.vue +253 -0
  144. package/packages/ui/src/kpi/FKpiGroup.vue +161 -0
  145. package/packages/ui/src/kpi/index.ts +20 -0
  146. package/packages/ui/src/kpi/kpi.theme.ts +168 -0
  147. package/packages/ui/src/kpi/kpiDelta.ts +82 -0
  148. package/packages/ui/src/kpi/kpiFormat.ts +72 -0
  149. package/packages/ui/src/kpi/kpiGroupState.ts +63 -0
  150. package/packages/ui/src/logo/FLogo.vue +52 -0
  151. package/packages/ui/src/logo/FSubLogo.vue +214 -0
  152. package/packages/ui/src/logo/index.ts +8 -0
  153. package/packages/ui/src/map/FMap.vue +355 -0
  154. package/packages/ui/src/map/FMapCompass.vue +154 -0
  155. package/packages/ui/src/map/FMapCoordinates.vue +134 -0
  156. package/packages/ui/src/map/FMapDrawTools.vue +116 -0
  157. package/packages/ui/src/map/FMapFullscreen.vue +92 -0
  158. package/packages/ui/src/map/FMapGeolocate.vue +208 -0
  159. package/packages/ui/src/map/FMapLayers.vue +75 -0
  160. package/packages/ui/src/map/FMapLegend.vue +45 -0
  161. package/packages/ui/src/map/FMapPopup.vue +129 -0
  162. package/packages/ui/src/map/FMapRamp.vue +69 -0
  163. package/packages/ui/src/map/FMapRegion.vue +77 -0
  164. package/packages/ui/src/map/FMapScale.vue +107 -0
  165. package/packages/ui/src/map/FMapSearch.vue +362 -0
  166. package/packages/ui/src/map/FMapTilt.vue +87 -0
  167. package/packages/ui/src/map/FMapTools.vue +61 -0
  168. package/packages/ui/src/map/FMapZoom.vue +81 -0
  169. package/packages/ui/src/map/FMarker.vue +218 -0
  170. package/packages/ui/src/map/FTrackScrubber.vue +94 -0
  171. package/packages/ui/src/map/FVehicleLegend.vue +72 -0
  172. package/packages/ui/src/map/FVehicleMark.vue +166 -0
  173. package/packages/ui/src/map/bin.ts +196 -0
  174. package/packages/ui/src/map/coordinates.ts +83 -0
  175. package/packages/ui/src/map/density.ts +401 -0
  176. package/packages/ui/src/map/draw.ts +356 -0
  177. package/packages/ui/src/map/ease.ts +67 -0
  178. package/packages/ui/src/map/fullscreen.ts +59 -0
  179. package/packages/ui/src/map/heat.ts +160 -0
  180. package/packages/ui/src/map/index.ts +351 -0
  181. package/packages/ui/src/map/liveMarkers.ts +60 -0
  182. package/packages/ui/src/map/map.css +116 -0
  183. package/packages/ui/src/map/mapColor.ts +31 -0
  184. package/packages/ui/src/map/mapContext.ts +12 -0
  185. package/packages/ui/src/map/mapLayers.ts +55 -0
  186. package/packages/ui/src/map/mapLegend.ts +70 -0
  187. package/packages/ui/src/map/mapSearch.theme.ts +79 -0
  188. package/packages/ui/src/map/mapSearch.ts +279 -0
  189. package/packages/ui/src/map/mapUrl.ts +117 -0
  190. package/packages/ui/src/map/markerAsset.ts +3 -0
  191. package/packages/ui/src/map/padding.ts +39 -0
  192. package/packages/ui/src/map/place.ts +192 -0
  193. package/packages/ui/src/map/ramp.ts +95 -0
  194. package/packages/ui/src/map/regionSelect.ts +163 -0
  195. package/packages/ui/src/map/route.ts +167 -0
  196. package/packages/ui/src/map/scale.ts +329 -0
  197. package/packages/ui/src/map/scaleBar.ts +67 -0
  198. package/packages/ui/src/map/selectionModel.ts +50 -0
  199. package/packages/ui/src/map/sources/coordinates.ts +58 -0
  200. package/packages/ui/src/map/sources/mapboxPlaces.ts +71 -0
  201. package/packages/ui/src/map/style.ts +14 -0
  202. package/packages/ui/src/map/track.ts +279 -0
  203. package/packages/ui/src/map/useFeatureSelect.ts +230 -0
  204. package/packages/ui/src/map/useLiveMarkers.ts +84 -0
  205. package/packages/ui/src/map/useMap.ts +150 -0
  206. package/packages/ui/src/map/useMapDraw.ts +776 -0
  207. package/packages/ui/src/map/useMapOverlay.ts +421 -0
  208. package/packages/ui/src/map/useMapTableSelection.ts +101 -0
  209. package/packages/ui/src/map/useMapUrlState.ts +155 -0
  210. package/packages/ui/src/map/useMarkerSource.ts +163 -0
  211. package/packages/ui/src/map/useRegionSelect.ts +309 -0
  212. package/packages/ui/src/map/useTokenMode.ts +61 -0
  213. package/packages/ui/src/map/useTrackPlayback.ts +131 -0
  214. package/packages/ui/src/map/useVehicleFilter.ts +51 -0
  215. package/packages/ui/src/map/useVisibleFeatures.ts +124 -0
  216. package/packages/ui/src/map/vehicle.ts +807 -0
  217. package/packages/ui/src/map/vehicleFilter.ts +284 -0
  218. package/packages/ui/src/map/vehicleLegend.ts +155 -0
  219. package/packages/ui/src/map/visibleFeatures.ts +192 -0
  220. package/packages/ui/src/map/zone.ts +291 -0
  221. package/packages/ui/src/shell/FAppNavbar.vue +68 -0
  222. package/packages/ui/src/shell/FAppShell.vue +163 -0
  223. package/packages/ui/src/shell/FAppSidebar.vue +215 -0
  224. package/packages/ui/src/shell/FPageToolbar.vue +126 -0
  225. package/packages/ui/src/shell/FScrollShadow.vue +43 -0
  226. package/packages/ui/src/shell/FSidePanel.vue +258 -0
  227. package/packages/ui/src/shell/FToolbarActions.vue +32 -0
  228. package/packages/ui/src/shell/index.ts +33 -0
  229. package/packages/ui/src/shell/nav.ts +37 -0
  230. package/packages/ui/src/shell/pageToolbar.ts +69 -0
  231. package/packages/ui/src/shell/shell.ts +74 -0
  232. package/packages/ui/src/shell/sidePanel.ts +115 -0
  233. package/packages/ui/src/themes/accordion.ts +36 -0
  234. package/packages/ui/src/themes/alert.ts +16 -0
  235. package/packages/ui/src/themes/auth-form.ts +19 -0
  236. package/packages/ui/src/themes/avatar-group.ts +9 -0
  237. package/packages/ui/src/themes/avatar.ts +18 -0
  238. package/packages/ui/src/themes/badge.ts +51 -0
  239. package/packages/ui/src/themes/banner.ts +21 -0
  240. package/packages/ui/src/themes/breadcrumb.ts +10 -0
  241. package/packages/ui/src/themes/button.mechanics.ts +191 -0
  242. package/packages/ui/src/themes/button.ts +136 -0
  243. package/packages/ui/src/themes/calendar.ts +29 -0
  244. package/packages/ui/src/themes/card.ts +67 -0
  245. package/packages/ui/src/themes/carousel.ts +41 -0
  246. package/packages/ui/src/themes/checkbox-group.ts +20 -0
  247. package/packages/ui/src/themes/checkbox.ts +47 -0
  248. package/packages/ui/src/themes/chip.ts +50 -0
  249. package/packages/ui/src/themes/collapsible.ts +26 -0
  250. package/packages/ui/src/themes/color-picker.ts +13 -0
  251. package/packages/ui/src/themes/command-palette.ts +37 -0
  252. package/packages/ui/src/themes/container.ts +14 -0
  253. package/packages/ui/src/themes/context-menu.ts +38 -0
  254. package/packages/ui/src/themes/dashboard-group.ts +11 -0
  255. package/packages/ui/src/themes/dashboard-navbar.ts +10 -0
  256. package/packages/ui/src/themes/dashboard-panel.ts +18 -0
  257. package/packages/ui/src/themes/dashboard-resize-handle.ts +35 -0
  258. package/packages/ui/src/themes/dashboard-sidebar-collapse.ts +7 -0
  259. package/packages/ui/src/themes/dashboard-sidebar-toggle.ts +7 -0
  260. package/packages/ui/src/themes/dashboard-sidebar.ts +58 -0
  261. package/packages/ui/src/themes/dashboard-toolbar.ts +15 -0
  262. package/packages/ui/src/themes/drawer.ts +45 -0
  263. package/packages/ui/src/themes/dropdown-menu.ts +38 -0
  264. package/packages/ui/src/themes/empty.ts +43 -0
  265. package/packages/ui/src/themes/field-group.ts +52 -0
  266. package/packages/ui/src/themes/file-upload.ts +38 -0
  267. package/packages/ui/src/themes/footer-columns.ts +13 -0
  268. package/packages/ui/src/themes/footer.ts +9 -0
  269. package/packages/ui/src/themes/form-field.ts +25 -0
  270. package/packages/ui/src/themes/form.ts +22 -0
  271. package/packages/ui/src/themes/header.ts +12 -0
  272. package/packages/ui/src/themes/icon.ts +61 -0
  273. package/packages/ui/src/themes/index.ts +99 -0
  274. package/packages/ui/src/themes/input-date.ts +73 -0
  275. package/packages/ui/src/themes/input-menu.ts +66 -0
  276. package/packages/ui/src/themes/input-number.ts +58 -0
  277. package/packages/ui/src/themes/input-rating.ts +25 -0
  278. package/packages/ui/src/themes/input-tags.ts +63 -0
  279. package/packages/ui/src/themes/input-time.ts +70 -0
  280. package/packages/ui/src/themes/input.ts +148 -0
  281. package/packages/ui/src/themes/kbd.ts +27 -0
  282. package/packages/ui/src/themes/link.ts +27 -0
  283. package/packages/ui/src/themes/listbox.ts +48 -0
  284. package/packages/ui/src/themes/main.ts +6 -0
  285. package/packages/ui/src/themes/marquee.ts +45 -0
  286. package/packages/ui/src/themes/modal.ts +46 -0
  287. package/packages/ui/src/themes/navigation-menu.ts +80 -0
  288. package/packages/ui/src/themes/page-anchors.ts +7 -0
  289. package/packages/ui/src/themes/page-aside.ts +7 -0
  290. package/packages/ui/src/themes/page-card.ts +22 -0
  291. package/packages/ui/src/themes/page-cta.ts +18 -0
  292. package/packages/ui/src/themes/page-feature.ts +13 -0
  293. package/packages/ui/src/themes/page-header.ts +16 -0
  294. package/packages/ui/src/themes/page-hero.ts +15 -0
  295. package/packages/ui/src/themes/page-links.ts +12 -0
  296. package/packages/ui/src/themes/page-section.ts +14 -0
  297. package/packages/ui/src/themes/page.ts +7 -0
  298. package/packages/ui/src/themes/pagination.ts +17 -0
  299. package/packages/ui/src/themes/pin-input.ts +73 -0
  300. package/packages/ui/src/themes/popover.ts +30 -0
  301. package/packages/ui/src/themes/progress.ts +29 -0
  302. package/packages/ui/src/themes/prose.ts +45 -0
  303. package/packages/ui/src/themes/radio-group.ts +39 -0
  304. package/packages/ui/src/themes/scroll-area.ts +23 -0
  305. package/packages/ui/src/themes/select-menu.ts +71 -0
  306. package/packages/ui/src/themes/select.ts +72 -0
  307. package/packages/ui/src/themes/separator.ts +28 -0
  308. package/packages/ui/src/themes/sidebar.ts +127 -0
  309. package/packages/ui/src/themes/skeleton.ts +15 -0
  310. package/packages/ui/src/themes/slideover.ts +87 -0
  311. package/packages/ui/src/themes/slider.ts +48 -0
  312. package/packages/ui/src/themes/stepper.ts +41 -0
  313. package/packages/ui/src/themes/switch.ts +63 -0
  314. package/packages/ui/src/themes/table.ts +34 -0
  315. package/packages/ui/src/themes/tabs.ts +74 -0
  316. package/packages/ui/src/themes/textarea.ts +77 -0
  317. package/packages/ui/src/themes/timeline.ts +25 -0
  318. package/packages/ui/src/themes/toast.ts +29 -0
  319. package/packages/ui/src/themes/toaster.ts +66 -0
  320. package/packages/ui/src/themes/tooltip.ts +31 -0
  321. package/packages/ui/src/themes/tree.ts +41 -0
  322. package/packages/ui/src/themes/user.ts +28 -0
  323. package/styles.cdn.gen.css +2047 -0
  324. package/theme.gen.json +1 -0
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Forest theme fragment — UTable (data table, sticky header, loading bar).
3
+ *
4
+ * Forest opinions applied:
5
+ * - `th`: font-semibold is already stock — we bump it to `font-bold` so column headings read with
6
+ * the same confident weight as the rest of the Forest type system, and switch the text role from
7
+ * `text-highlighted` to `text-default` to sit one step quieter than page headings while still
8
+ * reading clearly. Slight uppercase + tracking gives the table header a structured ops-dashboard
9
+ * feel consistent with the Forest label vocabulary.
10
+ * - `td`: `text-default` instead of the stock `text-muted` — data cells carry primary content and
11
+ * should read at full default weight rather than the slightly dimmed muted role.
12
+ * - `tbody`: the selectable-row hover bg is already `bg-elevated/50`; no changes needed.
13
+ * - `empty`: align with `text-dimmed` (one step quieter than stock `text-muted`) to visually
14
+ * distinguish placeholder copy from real cell content.
15
+ *
16
+ * Slots touched: th, td, empty.
17
+ * Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/table.ts
18
+ *
19
+ * The loading bar colour is driven by the `loadingColor` compoundVariants in the generated theme —
20
+ * no override needed here; `primary` defaults to the forest ramp via the semantic colour wiring
21
+ * in docs.css / forest-preset.ts.
22
+ */
23
+
24
+ export const tableTheme = {
25
+ slots: {
26
+ // font-bold + uppercase tracking — gives column headings a confident, ops-dashboard weight.
27
+ // text-default sits one step quieter than text-highlighted (stock) without losing legibility.
28
+ th: 'text-xs font-bold uppercase tracking-wider text-default',
29
+ // text-default — data is primary content; stock text-muted reads too low for ops data cells.
30
+ td: 'text-default',
31
+ // text-dimmed — visually distinct from real data; subtler than stock text-muted placeholder.
32
+ empty: 'text-dimmed',
33
+ },
34
+ } as const;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Forest theme fragment — UTabs (tabbed panels). Deltas only; everything else is inherited from
3
+ * stock Nuxt UI.
4
+ *
5
+ * Forest opinions applied:
6
+ * - `trigger`: font-bold (stock font-medium) — one stable weight in every state, so the active tab
7
+ * is signalled by the coloured indicator alone, never a weight shift (which would relayout).
8
+ * Under a coarse (touch) pointer the trigger grows one size up per the size-variant ladder below.
9
+ * - `indicator`: the Forest motion tokens (stock is a flat duration-200).
10
+ * - Pill radius (compoundVariants): a CONCENTRIC per-size ladder — the sliding indicator sits on
11
+ * the input field's radius (xs/sm 8px, md/lg/xl 12px) and the tray rounds one step past it, so
12
+ * the pill nests as outer = inner + the 4px pad. Same relationship stock uses; only the small
13
+ * sizes are new. sm promotes to md's pair under coarse.
14
+ *
15
+ * Slots touched: trigger, indicator, list (pill radius + pill tray bg/border).
16
+ * Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/tabs.ts
17
+ */
18
+
19
+ export const tabsTheme = {
20
+ slots: {
21
+ // indicator — Forest motion tokens over stock's flat duration-200 (applies to both variants).
22
+ // Stock's `absolute transition-[translate,width]` is inherited. Radius is NOT set here — it's
23
+ // per-size and pill-scoped, so it lives in compoundVariants below (a base value would lose the
24
+ // ordering race to stock's `variant.pill` radius anyway).
25
+ indicator: 'duration-(--motion-base) ease-(--motion-ease-in-out)',
26
+ // trigger — font-bold over stock's font-medium: one stable weight in every state (legible at
27
+ // xs–sm, no active/inactive layout shift; colour carries the hierarchy, not weight). Stock's
28
+ // layout/state/rounded/transition classes are inherited, not restated.
29
+ trigger: 'font-bold',
30
+ },
31
+ // Touch: tab triggers are tap targets, so under a coarse (finger) primary pointer each size grows
32
+ // one size UP — the full trigger geometry (padding, gap, text, icon), same proportional step as the
33
+ // input field. Tabs is simpler than input here: no responsive `md:text-*` shrink to fight, and the
34
+ // leading icon is gap-spaced (no absolute `ps-9`), so horizontal `px` is safe to bump too — the step
35
+ // is the true next-size trigger. xl is the ceiling. Each size lists only its deltas up. `coarse:`
36
+ // carries the `:not(.cut-fixed)` escape, so the mobile cut (which bakes size lg) opts out below.
37
+ variants: {
38
+ size: {
39
+ // → sm: wider padding + gap (text/icon same)
40
+ xs: { trigger: 'coarse:px-2.5 coarse:py-1.5 coarse:gap-1.5' },
41
+ // → md: wider padding, larger text + icon (py/gap same)
42
+ sm: { trigger: 'coarse:px-3 coarse:text-sm', leadingIcon: 'coarse:size-5' },
43
+ // → lg: taller padding + gap (px/text/icon same)
44
+ md: { trigger: 'coarse:py-2 coarse:gap-2' },
45
+ // → xl: larger text + icon (padding/gap same)
46
+ lg: { trigger: 'coarse:text-base', leadingIcon: 'coarse:size-6' },
47
+ // xl: ceiling — no bump
48
+ },
49
+ },
50
+ // Pill radius is CONCENTRIC, the way stock builds it: the tray (`list`) has a p-1 (4px) inset, so
51
+ // the sliding `indicator` (the inner, filled pill) rounds one step TIGHTER than the tray — outer =
52
+ // inner + padding — and the active pill nests cleanly in the tray corner. The inner value is the
53
+ // input field's per-size ladder (xs/sm rounded-sm 8px, md/lg/xl rounded-md 12px), so the active tab
54
+ // reads at the same radius as a field; the tray is one step up (12 / 16). (md/lg/xl land back on
55
+ // stock's own values — tray rounded-lg, indicator rounded-md; only xs/sm add the smaller concentric
56
+ // pair.) Under coarse, sm promotes to md's pair (indicator 8→12, tray 12→16), tracking its size-up.
57
+ //
58
+ // Why compoundVariants: the radius must (a) beat stock's `variant.pill` values — compounds apply
59
+ // last, so they win — and (b) apply ONLY to the pill. A size-variant `indicator` would also hit the
60
+ // LINK variant and clobber its rounded-full underline ends; scoping to `variant: 'pill'` leaves link
61
+ // alone.
62
+ compoundVariants: [
63
+ // Pill tray as an outlined field, not a raised grey slab: bg-default (the base neutral-0 surface,
64
+ // mode-aware) over stock's bg-elevated, plus a 1px inset accented ring for the border. Scoped to
65
+ // `variant: 'pill'` (no size) so it hits every pill size and leaves LINK untouched; a compound
66
+ // applies last, so bg-default wins the tailwind-merge over the base variant's bg-elevated.
67
+ { variant: 'pill', class: { list: 'bg-default ring ring-inset ring-accented' } },
68
+ { variant: 'pill', size: 'xs', class: { list: 'rounded-md', indicator: 'rounded-sm' } },
69
+ { variant: 'pill', size: 'sm', class: { list: 'rounded-md coarse:rounded-lg', indicator: 'rounded-sm coarse:rounded-md' } },
70
+ { variant: 'pill', size: 'md', class: { list: 'rounded-lg', indicator: 'rounded-md' } },
71
+ { variant: 'pill', size: 'lg', class: { list: 'rounded-lg', indicator: 'rounded-md' } },
72
+ { variant: 'pill', size: 'xl', class: { list: 'rounded-lg', indicator: 'rounded-md' } },
73
+ ],
74
+ } as const;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Forest theme fragment — UTextarea (multiline input, autoresize).
3
+ *
4
+ * Textarea is a multiline UInput, so it wears the SAME Forest identity — this fragment mirrors
5
+ * themes/input.ts: the recessed depth line, the colour-tracking focus halo, the per-size radius
6
+ * ladder, and the touch ladder. Stock UTextarea shares UInput's size architecture verbatim
7
+ * (same px/py/text/gap/icon per size, same responsive `md:text-*` shrink), so the deltas are the same.
8
+ * Keeping the two in lockstep is deliberate — a note field and a single-line field on the same form
9
+ * must read as one control family. See input.ts for the full rationale on each opinion; the notes
10
+ * here are the textarea-specific deltas only.
11
+ *
12
+ * Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/textarea.ts
13
+ */
14
+
15
+ export const textareaTheme = {
16
+ slots: {
17
+ // Same base as UInput: the solid inset depth line at rest (stacks UNDER the ring via separate
18
+ // shadow vars), a box-shadow transition so focus eases, and the depth line + soft halo on focus.
19
+ // The old `focus:outline-none` is dropped ON PURPOSE — it was suppressing the very focus outline
20
+ // UInput keeps, so the two fields disagreed on focus; parity restores the shared treatment.
21
+ base: 'transition-[color,box-shadow] duration-(--motion-fast) shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)] focus-visible:shadow-[inset_0_var(--forest-input-depth)_0_0_var(--forest-input-recess),0_0_0_3px_var(--forest-input-halo,var(--forest-halo-primary))]',
22
+ },
23
+ // Touch ladder + per-size radius/depth — identical to input.ts. Under a coarse primary
24
+ // pointer each size grows PROPORTIONALLY to the next size up (height via py or type, gap, radius,
25
+ // icon, recess), reading as a bigger version of itself. Two things it does NOT bump: horizontal
26
+ // `px` (a `touch:px-*` emitted after the icon's inline padding would clobber it) and the naive
27
+ // base type (stock's responsive `md:text-*` shrink means the type bump must target the next size's
28
+ // EFFECTIVE value — sm→`text-sm`, lg→`text-base` — or the ladder inverts). sm also rounds up: its
29
+ // type-driven height gain earns the rounded-md step, same as md→lg. xl has a touch rung of
30
+ // its own (52). See input.ts.
31
+ // PER-SIZE RADIUS: xs/sm rounded-sm (8px); md/lg/xl keep stock's base rounded-md (12px) — only
32
+ // xs/sm are overridden, md+ not restated. Depth line scales per size.
33
+ // `touch:` = the shared TOUCH ladder (styles/forest.css) — height+type twin of button.ts/input.ts
34
+ // so a joined <UFieldGroup> matches. Fired by a coarse pointer or by the mobile cut's
35
+ // baked marker — same numbers either way, so a real phone can't step twice.
36
+ variants: {
37
+ size: {
38
+ // touch 28: taller padding + gap
39
+ xs: { base: 'rounded-sm [--forest-input-depth:2px] touch:min-h-7 touch:gap-1.5' },
40
+ // touch 36: larger type (md's effective 14/20) + icon + deeper recess, and rounder (type-driven
41
+ // height gain earns the rounded-md step)
42
+ sm: { base: 'rounded-sm [--forest-input-depth:2px] touch:min-h-9 touch:text-sm touch:rounded-md touch:[--forest-input-depth:3px]', leadingIcon: 'touch:size-5', trailingIcon: 'touch:size-5' },
43
+ // touch 40: taller padding + gap (radius inherits stock base rounded-md — not restated)
44
+ md: { base: '[--forest-input-depth:3px] touch:min-h-10 touch:text-sm touch:gap-2' },
45
+ // touch 44: larger type (xl's 16/24) + icon + deepest recess
46
+ lg: { base: '[--forest-input-depth:3px] touch:min-h-11 touch:text-base touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-6', trailingIcon: 'touch:size-6' },
47
+ // touch 52
48
+ xl: { base: '[--forest-input-depth:4px] touch:min-h-13 touch:text-lg touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-7', trailingIcon: 'touch:size-7' },
49
+ },
50
+ // Focus halo tracks `color` — FLAT strings (stock's colour variant is flat; a `{ base: … }` shape
51
+ // would be dropped by the merge). Each colour re-points --forest-input-halo at its own 200 step.
52
+ color: {
53
+ primary: '[--forest-input-halo:var(--forest-halo-primary)]',
54
+ secondary: '[--forest-input-halo:var(--forest-halo-secondary)]',
55
+ success: '[--forest-input-halo:var(--forest-halo-success)]',
56
+ info: '[--forest-input-halo:var(--forest-halo-info)]',
57
+ warning: '[--forest-input-halo:var(--forest-halo-warning)]',
58
+ error: '[--forest-input-halo:var(--forest-halo-error)]',
59
+ forest: '[--forest-input-halo:var(--forest-halo-forest)]',
60
+ maple: '[--forest-input-halo:var(--forest-halo-maple)]',
61
+ river: '[--forest-input-halo:var(--forest-halo-river)]',
62
+ warm: '[--forest-input-halo:var(--forest-halo-warm)]',
63
+ acid: '[--forest-input-halo:var(--forest-halo-acid)]',
64
+ neutral: '[--forest-input-halo:var(--forest-halo-neutral)]',
65
+ },
66
+ },
67
+ // Ghost drops the resting depth line (no fill/ring = nothing to recess into); it takes the line on
68
+ // hover/focus with the elevated fill. Same as input.
69
+ compoundVariants: [
70
+ {
71
+ variant: 'ghost',
72
+ class: {
73
+ base: 'shadow-none hover:shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)]',
74
+ },
75
+ },
76
+ ],
77
+ } as const;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Forest theme fragment — UTimeline (vertical / horizontal event track).
3
+ *
4
+ * Forest opinions applied:
5
+ * - `title`: steps up from stock `font-medium` to `font-bold` — gives the event name a
6
+ * clear hierarchy above the dimmed date and muted description without reaching for a display
7
+ * heading or extra font-size.
8
+ * - `date`: kept minimal; `text-xs/5` and `text-dimmed` are already stock, no opinion needed.
9
+ * - `description`: stock `text-muted text-sm` is correct — no override required.
10
+ * - `separator`: stock `rounded-full` matches Forest's pill language (chips, badges); no
11
+ * override needed. Background colours are handled by the colour + reverse compound variants
12
+ * already in the generated theme.
13
+ * - `indicator`: stock `text-muted` rest state is intentionally kept — the indicator picks up
14
+ * brand colour from the `color` variant when `state="active"` or `state="completed"`. No
15
+ * override needed here.
16
+ *
17
+ * Slots touched: title.
18
+ * Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/timeline.ts
19
+ */
20
+
21
+ export const timelineTheme = {
22
+ slots: {
23
+ title: 'font-bold',
24
+ },
25
+ } as const
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Forest theme fragment — UToast (transient notification).
3
+ *
4
+ * Forest opinions applied:
5
+ * - `root`: radius bumped to rounded-xl (matches the Forest card/alert language — 16 px, softer
6
+ * than the stock rounded-lg); the gap is comfortable at gap-3 for breathing room between
7
+ * icon/content/actions. Shadow, ring, and padding are unchanged from stock.
8
+ * - `title`: steps up from stock `font-medium` to `font-bold` — gives the notification
9
+ * headline a clear hierarchy above the description, matching the alert/banner convention.
10
+ * - `description`: text-sm text-muted is unchanged — the muted colour already reads as
11
+ * secondary copy, matching the Forest hierarchy. No override needed.
12
+ *
13
+ * Deliberately untouched (stock is already correct for Forest):
14
+ * - `wrapper`, `icon`, `avatar`, `actions`, `progress`, `close` — stock layout and sizing are
15
+ * appropriate; brand colour intent flows in automatically through the semantic colour map.
16
+ * - All `color` variants — the focus-visible ring and icon colour already resolve through the
17
+ * semantic wiring (primary→forest, error→maple, info→river, warning→amber, secondary→warm).
18
+ * - Orientation variants — stock horizontal/vertical layout is correct as-is.
19
+ *
20
+ * Slots touched: root, title.
21
+ * Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/toast.ts
22
+ */
23
+
24
+ export const toastTheme = {
25
+ slots: {
26
+ root: 'rounded-xl gap-3 focus:outline-none',
27
+ title: 'font-bold',
28
+ },
29
+ } as const;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Forest theme fragment — UToaster (the toast STACK: viewport, entry/exit, swipe, collapse).
3
+ *
4
+ * Distinct from the `toast` fragment, which styles a single notification's surface. Everything the
5
+ * stack moves lives here, and all of it was stock — this fragment exists only to bring that motion
6
+ * onto the shared tokens. Nothing else about the toaster needs a Forest opinion: the viewport
7
+ * position matrix, the stacking transforms and the swipe translate maths are structure.
8
+ *
9
+ * Timing, by what each thing is:
10
+ * - entry (`toast-slide-in-from-*`) — an overlay arriving, so --motion-base
11
+ * - exit (`toast-closed`, `toast-collapsed-closed`) and swipe-dismiss — --motion-fast, the
12
+ * overlay-exit bucket; a dismissal the user already committed to should get out of the way
13
+ * - the stack reflow (`transition-[transform,translate,height]`, running whenever a sibling
14
+ * enters or leaves) — --motion-base, since it is what visually carries the entry
15
+ * - `pulse-a` / `pulse-b`, the attention nudge on a repeat toast — --motion-base
16
+ * - the front-card opacity fade at duration-100 — --motion-instant
17
+ *
18
+ * Every curve becomes --motion-ease-out. Stock eases the entry and both exits with `ease-in-out`,
19
+ * which the doctrine reserves for movement that starts AND settles on screen; a toast slides in
20
+ * from outside the viewport and leaves it again.
21
+ *
22
+ * Slots touched: base (and its position compounds + the swipeDirection variant).
23
+ * Stock recipe: apps/docs/node_modules/.nuxt-ui/ui/toaster.ts
24
+ */
25
+
26
+ export const toasterTheme = {
27
+ slots: {
28
+ // Exits, the attention pulse, the front-card fade, and the stack reflow. Same keyframes and same
29
+ // property list as stock — only the durations and curves are restated, and tailwind-merge takes
30
+ // the last of each pair in the concat.
31
+ base: [
32
+ 'data-[front=false]:*:duration-(--motion-instant)',
33
+ 'data-[state=closed]:animate-[toast-closed_var(--motion-fast)_var(--motion-ease-out)]',
34
+ 'data-[state=closed]:data-[expanded=false]:data-[front=false]:animate-[toast-collapsed-closed_var(--motion-fast)_var(--motion-ease-out)]',
35
+ 'data-[state=open]:data-[pulsing=odd]:animate-[toast-pulse-a_var(--motion-base)_var(--motion-ease-out)]',
36
+ 'data-[state=open]:data-[pulsing=even]:animate-[toast-pulse-b_var(--motion-base)_var(--motion-ease-out)]',
37
+ 'duration-(--motion-base) ease-(--motion-ease-out)',
38
+ ].join(' '),
39
+ },
40
+ variants: {
41
+ // Swipe-to-dismiss — the fling that completes a gesture the user is already making, so it runs
42
+ // at the exit duration rather than the entry one.
43
+ swipeDirection: {
44
+ up: 'data-[swipe=end]:animate-[toast-slide-up_var(--motion-fast)_var(--motion-ease-out)]',
45
+ right: 'data-[swipe=end]:animate-[toast-slide-right_var(--motion-fast)_var(--motion-ease-out)]',
46
+ down: 'data-[swipe=end]:animate-[toast-slide-down_var(--motion-fast)_var(--motion-ease-out)]',
47
+ left: 'data-[swipe=end]:animate-[toast-slide-left_var(--motion-fast)_var(--motion-ease-out)]',
48
+ },
49
+ },
50
+ // Entry, which stock scopes to the position group (a top toast slides down, a bottom one up). The
51
+ // discriminator arrays mirror stock's exactly so these land as the same compound, applied last.
52
+ compoundVariants: [
53
+ {
54
+ position: ['top-left', 'top-center', 'top-right'],
55
+ class: {
56
+ base: 'data-[state=open]:animate-[toast-slide-in-from-top_var(--motion-base)_var(--motion-ease-out)]',
57
+ },
58
+ },
59
+ {
60
+ position: ['bottom-left', 'bottom-center', 'bottom-right'],
61
+ class: {
62
+ base: 'data-[state=open]:animate-[toast-slide-in-from-bottom_var(--motion-base)_var(--motion-ease-out)]',
63
+ },
64
+ },
65
+ ],
66
+ } as const;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Forest theme fragment — UTooltip (hover/focus hint).
3
+ *
4
+ * Deltas only (the preset APPENDS to stock Nuxt UI):
5
+ * content — flips stock's surface look (`bg-default text-highlighted rounded-sm`) to a floating
6
+ * inverted bubble (`bg-inverted text-inverted`) at the brand radius (`rounded-lg`,
7
+ * 0.5 rem / --ui-radius), and swaps stock's raw `100ms ease` open/close animation for
8
+ * the Forest motion tokens (fast enter, instant exit). Shadow, ring, height, padding,
9
+ * origin and pointer-events are inherited from stock and not restated.
10
+ * arrow — must follow the inverted bubble: stock fills the caret with `fill-bg` (the light
11
+ * surface), which reads as a white pointer on our dark bubble. Re-point it at the
12
+ * inverted bg so the caret matches the content. Stock's `stroke-default` is kept (it
13
+ * aligns with the bubble's inherited ring).
14
+ *
15
+ * Stock slots left untouched: text, kbds (kbds inherit the Forest UKbd theme).
16
+ *
17
+ * Slots sourced from: apps/docs/node_modules/.nuxt-ui/ui/tooltip.ts
18
+ * Slots touched: `content`
19
+ */
20
+
21
+ export const tooltipTheme = {
22
+ slots: {
23
+ // Both open states animate. Stock only ever reaches `delayed-open` through its own hover timer,
24
+ // but a tooltip whose `open` is controlled — the chart components drive theirs from their own
25
+ // hit-testing — reports `instant-open` instead, and matching only the delayed state left those
26
+ // appearing with no transition at all.
27
+ content: 'bg-inverted text-inverted rounded-lg data-[state=delayed-open]:animate-[scale-in_var(--motion-fast)_var(--motion-ease-out)] data-[state=instant-open]:animate-[scale-in_var(--motion-fast)_var(--motion-ease-out)] data-[state=closed]:animate-[scale-out_var(--motion-instant)_var(--motion-ease-out)]',
28
+ // Caret follows the inverted bubble (stock fills it with the light `fill-bg`). stroke-default kept.
29
+ arrow: 'fill-[var(--ui-bg-inverted)]',
30
+ },
31
+ } as const;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Forest theme fragment — UTree (hierarchical disclosure list).
3
+ *
4
+ * Deltas over stock (the preset appends to Nuxt UI):
5
+ * - `link`: a focused row draws an inset focus-visible ring on the before: pseudo that already
6
+ * carries the selection / hover pill.
7
+ * - `linkTrailingIcon`: the expand chevron rotates on --motion-fast / --motion-ease-out rather
8
+ * than stock's hard-coded duration-200 — a small near element, same bucket as the accordion
9
+ * and collapsible chevrons.
10
+ *
11
+ * The pill keeps its stock before:rounded-md (12px) — a tree node is a row, the same shape a sidebar
12
+ * nav row and a command-palette result carry.
13
+ *
14
+ * Everything else is stock: the indent guide (border-s border-default), the folder / chevron icons,
15
+ * the per-colour selected-label and focus colours, and the size ladder all read on the Forest ramps
16
+ * and semantic tokens without an override.
17
+ *
18
+ * Slots touched: link, linkTrailingIcon.
19
+ * Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/tree.ts
20
+ */
21
+
22
+ export const treeTheme = {
23
+ slots: {
24
+ link: 'focus-visible:before:ring-inset focus-visible:before:ring-2',
25
+ linkTrailingIcon: 'duration-(--motion-fast) ease-(--motion-ease-out)',
26
+ },
27
+
28
+ // Touch: each node promotes ONE size up under a coarse pointer (borrows the next size's padding /
29
+ // gap / type / icon) — same ladder as the menu/input family. Unlike the input field, tree links
30
+ // position their icons with flex `gap` (not an absolute ps-*/pe-* inset), so bumping horizontal
31
+ // padding here is safe. xl is the ceiling; deltas only. `coarse:` carries the :not(.cut-fixed)
32
+ // escape so a baked mobile cut opts out.
33
+ variants: {
34
+ size: {
35
+ xs: { link: 'coarse:px-2.5 coarse:py-1.5 coarse:gap-1.5' },
36
+ sm: { link: 'coarse:text-sm', linkLeadingIcon: 'coarse:size-5', linkTrailingIcon: 'coarse:size-5' },
37
+ md: { link: 'coarse:px-3 coarse:py-2 coarse:gap-2' },
38
+ lg: { link: 'coarse:text-base', linkLeadingIcon: 'coarse:size-6', linkTrailingIcon: 'coarse:size-6' },
39
+ },
40
+ },
41
+ } as const;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Forest theme fragment — UUser (name + avatar + description row)
3
+ *
4
+ * Deltas only (stock in apps/docs/node_modules/.nuxt-ui/ui/user.ts):
5
+ * - `name`: `font-bold` (stock base is `font-medium`) so the rider/operator name reads with
6
+ * clear hierarchy above the description at every size. Colour is left to stock: the `to:false`
7
+ * variant already sets `text-highlighted` on the non-link name, so restating it here would be
8
+ * dead weight; the `to:true` link state keeps its own `text-default → highlighted` transition.
9
+ * - `wrapper`: `min-w-0` guard so name + description truncate when the row sits inside a flex
10
+ * parent (table cell, narrow sidebar item, list row). Stock wrapper base is empty.
11
+ * - `to.true.avatar`: the hover scale runs on --motion-fast / --motion-ease-out instead of stock's
12
+ * hard-coded duration-200 (bare `ease`). A hover affordance on a small near element is the
13
+ * textbook --motion-fast case.
14
+ *
15
+ * Untouched (all stock): `description` (`text-muted`), `avatar` (`shrink-0`), the 3xs–3xl gap +
16
+ * text size ladder, orientation, chip, and the `to` hover/focus colour transitions.
17
+ */
18
+ export const userTheme = {
19
+ slots: {
20
+ name: 'font-bold',
21
+ wrapper: 'min-w-0',
22
+ },
23
+ variants: {
24
+ to: {
25
+ true: { avatar: 'duration-(--motion-fast) ease-(--motion-ease-out)' },
26
+ },
27
+ },
28
+ } as const;