@heyramzi/ui 2.0.1 → 2.2.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 (341) hide show
  1. package/package.json +48 -24
  2. package/scripts/sync-shadcn.mjs +3 -4
  3. package/src/agents/agent-avatar.svelte +604 -575
  4. package/src/agents/agent-cast.svelte +179 -183
  5. package/src/agents/demo.svelte +125 -113
  6. package/src/agents/helpers.ts +23 -17
  7. package/src/agents/index.ts +4 -4
  8. package/src/agents/page-state.ts +6 -6
  9. package/src/agents/types.ts +6 -6
  10. package/src/ai/ai-button/AiButton.svelte +4 -12
  11. package/src/ai/generation-progress/GenerationProgress.svelte +10 -3
  12. package/src/ai/prompt-input/PromptInputTextarea.svelte +1 -2
  13. package/src/ai/response/Response.css +2 -3
  14. package/src/animations/avatar-group-hover.css +2 -16
  15. package/src/animations/card-tilt.css +3 -6
  16. package/src/animations/digit-pop-in.css +2 -15
  17. package/src/animations/dropdown.css +4 -17
  18. package/src/animations/input-clear-dissolve.css +5 -18
  19. package/src/animations/input-shake.css +9 -41
  20. package/src/animations/learn-more-hover.css +17 -9
  21. package/src/animations/like-button.css +2 -4
  22. package/src/animations/page-side-by-side.css +2 -10
  23. package/src/animations/plus-menu-morph.css +2 -5
  24. package/src/animations/shimmer-text.css +5 -18
  25. package/src/animations/spinning-counter.css +2 -6
  26. package/src/animations/success-check.css +2 -15
  27. package/src/animations/thinking-states.css +2 -7
  28. package/src/brand/brand.test.ts +21 -5
  29. package/src/brand/index.ts +4 -10
  30. package/src/canvas/README.md +9 -12
  31. package/src/canvas/card/card-frame.svelte +43 -39
  32. package/src/canvas/card/resize-handles.svelte +89 -80
  33. package/src/canvas/chrome/chrome-zoom.svelte +101 -100
  34. package/src/canvas/chrome/lock-badge.svelte +8 -8
  35. package/src/canvas/chrome/side-handles.svelte +24 -19
  36. package/src/canvas/chrome/size-chip.svelte +30 -30
  37. package/src/canvas/chrome/snap-guides.svelte +20 -20
  38. package/src/canvas/components/icons/ToolIcon.svelte +8 -8
  39. package/src/canvas/components/shared/svg/PreviewSvg.svelte +19 -19
  40. package/src/canvas/components/shared/svg/ShapeOutline.svelte +71 -48
  41. package/src/canvas/components/shared/svg/StrokeNode.svelte +21 -27
  42. package/src/canvas/components/shared/svg/TextRule.svelte +25 -17
  43. package/src/canvas/edges/bend-handle.svelte +46 -46
  44. package/src/canvas/edges/edge-gradient.svelte +10 -10
  45. package/src/canvas/edges/gradient-edge.svelte +45 -29
  46. package/src/canvas/editor/lock.test.ts +6 -1
  47. package/src/canvas/editor/style.ts +7 -1
  48. package/src/canvas/headless/svg-figure.test.ts +5 -1
  49. package/src/canvas/lod/lod-switch.svelte +111 -106
  50. package/src/canvas/pen/PenField.svelte +87 -81
  51. package/src/canvas/pen/PenOverlay.svelte +127 -127
  52. package/src/canvas/pen/ShapeNode.svelte +31 -32
  53. package/src/canvas/pen/TextNode.svelte +54 -53
  54. package/src/canvas/pen/host-field.test.svelte +7 -7
  55. package/src/canvas/pen/shapes.ts +7 -1
  56. package/src/canvas/screen/GlyphIcon.svelte +22 -17
  57. package/src/canvas/screen/PartView.svelte +138 -72
  58. package/src/canvas/screen/ScreenBody.svelte +81 -60
  59. package/src/canvas/screen/ScreenCard.svelte +20 -20
  60. package/src/canvas/ui/CanvasToolbar.svelte +173 -85
  61. package/src/canvas/ui/FrameLayer.svelte +59 -59
  62. package/src/canvas/ui/PenLayer.svelte +39 -30
  63. package/src/canvas/ui/StylePanel.svelte +119 -102
  64. package/src/canvas/ui/canvas-grid.svelte +137 -129
  65. package/src/charts/animated-value.svelte +1 -1
  66. package/src/charts/area-chart.css +2 -5
  67. package/src/charts/area-chart.svelte +1 -1
  68. package/src/charts/bar-chart.css +2 -3
  69. package/src/charts/bar-chart.svelte +1 -1
  70. package/src/charts/charts.css +5 -17
  71. package/src/charts/crosshair.svelte +1 -1
  72. package/src/charts/dashboard/dashboard-empty.svelte +25 -25
  73. package/src/charts/dashboard/dashboard-section.svelte +24 -24
  74. package/src/charts/dashboard/data-panel.svelte +50 -50
  75. package/src/charts/dashboard/data-sort-head.svelte +56 -56
  76. package/src/charts/dashboard/data-table.svelte +138 -138
  77. package/src/charts/dashboard/panel-grid.svelte +30 -30
  78. package/src/charts/dashboard/period-filter.svelte +25 -25
  79. package/src/charts/dashboard/rating-chip.svelte +19 -19
  80. package/src/charts/dashboard/stat-band.svelte +32 -32
  81. package/src/charts/dashboard/stat-tile.svelte +106 -99
  82. package/src/charts/donut-chart.svelte +1 -1
  83. package/src/charts/edge-fade.svelte +1 -1
  84. package/src/charts/figure.svelte +1 -1
  85. package/src/charts/gauge-chart.css +4 -7
  86. package/src/charts/gauge-chart.svelte +1 -1
  87. package/src/charts/hover-focus.svelte +1 -1
  88. package/src/charts/legend.css +1 -3
  89. package/src/charts/legend.svelte +1 -1
  90. package/src/charts/line-chart.svelte +1 -1
  91. package/src/charts/number-chart.css +6 -9
  92. package/src/charts/number-chart.svelte +1 -1
  93. package/src/charts/reference-line.svelte +19 -19
  94. package/src/charts/reveal.svelte +1 -1
  95. package/src/charts/ring-chart.css +2 -4
  96. package/src/charts/ring-chart.svelte +1 -1
  97. package/src/charts/sparkline.svelte +5 -2
  98. package/src/charts/stat-card.svelte +1 -1
  99. package/src/charts/time-series-chart.css +2 -5
  100. package/src/charts/trend-pill.css +2 -4
  101. package/src/charts/trend-pill.svelte +1 -1
  102. package/src/components/copy/copy-button.svelte +93 -98
  103. package/src/components/copy/copy-button.test.ts +10 -2
  104. package/src/components/data-table/infinite-scroll.svelte +42 -42
  105. package/src/components/data-table/pagination.svelte +34 -22
  106. package/src/components/data-table/row-arrow.svelte +19 -16
  107. package/src/components/data-table/row-context-menu.svelte +52 -52
  108. package/src/components/data-table/sortable-head.svelte +25 -25
  109. package/src/components/data-table/table-skeleton.svelte +41 -36
  110. package/src/components/docs/doc-page.svelte +18 -9
  111. package/src/components/docs/on-this-page.svelte +16 -3
  112. package/src/components/docs/scroll-spy.svelte.ts +2 -3
  113. package/src/components/field-row/field-row.svelte +10 -8
  114. package/src/components/hold-to-confirm/hold-to-confirm.svelte +5 -1
  115. package/src/components/icon/icon.svelte +14 -14
  116. package/src/components/language-flag/language-flag.svelte +3 -1
  117. package/src/components/list-page/detail-empty.svelte +34 -34
  118. package/src/components/list-page/detail-header.svelte +55 -47
  119. package/src/components/list-page/detail-panel.svelte +51 -59
  120. package/src/components/list-page/detail-row.svelte +19 -19
  121. package/src/components/list-page/detail-stack.svelte +21 -21
  122. package/src/components/list-page/empty-state.svelte +30 -30
  123. package/src/components/list-page/filter-item.svelte +20 -20
  124. package/src/components/list-page/filter-popover.svelte +60 -55
  125. package/src/components/list-page/grouped-list.svelte +4 -2
  126. package/src/components/list-page/index.ts +8 -4
  127. package/src/components/list-page/list-page-shell.svelte +2 -5
  128. package/src/components/list-page/master-detail.svelte +87 -88
  129. package/src/components/list-page/notice-bar.svelte +38 -38
  130. package/src/components/list-page/prev-next.svelte +63 -63
  131. package/src/components/list-page/rail-body.svelte +18 -18
  132. package/src/components/list-page/rail-empty.svelte +23 -30
  133. package/src/components/list-page/rail-head.svelte +24 -24
  134. package/src/components/list-page/rail-row.svelte +77 -73
  135. package/src/components/list-page/section-host.ts +2 -3
  136. package/src/components/locale-switch/locale-switch.svelte +41 -41
  137. package/src/components/mark/mark.svelte +34 -38
  138. package/src/components/open-in/index.ts +1 -5
  139. package/src/components/open-in/open-in.svelte +40 -40
  140. package/src/components/picker/mark-picker.svelte +49 -49
  141. package/src/components/picker/picker.svelte +5 -3
  142. package/src/components/section-header/index.ts +1 -0
  143. package/src/components/section-header/section-header.svelte +1 -1
  144. package/src/components/section-header/section-header.test.ts +7 -1
  145. package/src/components/section-header/section-label.svelte +39 -0
  146. package/src/components/segmented/animated-tabs.svelte +31 -2
  147. package/src/components/segmented/collapse.test.ts +2 -1
  148. package/src/components/segmented/index.ts +2 -0
  149. package/src/components/segmented/segment.svelte +52 -49
  150. package/src/components/segmented/segmented-filter.svelte +79 -80
  151. package/src/components/segmented/segmented-nav.svelte +34 -40
  152. package/src/components/segmented/segmented-overflow.svelte +53 -50
  153. package/src/components/segmented/segmented-track.svelte +62 -46
  154. package/src/components/segmented/segmented.ts +2 -3
  155. package/src/components/star-rating-input/star-rating-input.svelte +103 -103
  156. package/src/components/svg/svg.svelte +4 -4
  157. package/src/components/table-view/table-view.svelte +17 -2
  158. package/src/components/table-view/table-view.test.ts +7 -1
  159. package/src/components/table-view/types.ts +11 -11
  160. package/src/components/tags-input/index.ts +13 -0
  161. package/src/components/tags-input/tags-input.svelte +305 -0
  162. package/src/components/tags-input/tags.test.ts +64 -0
  163. package/src/components/tags-input/tags.ts +142 -0
  164. package/src/components/theme/index.ts +2 -4
  165. package/src/components/theme/theme-provider.svelte +1 -3
  166. package/src/components/toolbar/index.ts +2 -0
  167. package/src/components/{list-page → toolbar}/toolbar-search.svelte +25 -25
  168. package/src/components/toolbar/toolbar.svelte +13 -9
  169. package/src/components/toolbar/toolbar.test.ts +10 -1
  170. package/src/design/index.css +21 -78
  171. package/src/design/polish.css +26 -35
  172. package/src/editor/editor-toolbar.svelte +104 -99
  173. package/src/editor/editor.svelte +296 -266
  174. package/src/editor/image-toolbar.svelte +20 -22
  175. package/src/editor/index.ts +1 -4
  176. package/src/editor/inline-editor.svelte +280 -238
  177. package/src/editor/markdown.ts +15 -15
  178. package/src/editor/renderer.svelte +71 -71
  179. package/src/editor/slash-menu.svelte +24 -27
  180. package/src/effects/animated-beam/diagrams/BeamSvg.svelte +1 -1
  181. package/src/effects/image-comparison/ImageComparison.svelte +11 -1
  182. package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +59 -46
  183. package/src/effects/magic-card/MagicCard.css +14 -7
  184. package/src/effects/marquee/Marquee.svelte +3 -5
  185. package/src/effects/reveal/observe.ts +0 -3
  186. package/src/effects/spotlight/Spotlight.svelte +1 -1
  187. package/src/effects/theme-toggle/ThemeToggle.css +25 -22
  188. package/src/effects/theme-toggle/ThemeToggle.svelte +6 -7
  189. package/src/gallery.test.ts +14 -4
  190. package/src/inbox/README.md +27 -0
  191. package/src/inbox/inbox.test.ts +214 -0
  192. package/src/inbox/index.ts +31 -0
  193. package/src/inbox/logic.ts +169 -0
  194. package/src/inbox/thread-inbox.svelte +439 -0
  195. package/src/inbox/types.ts +161 -0
  196. package/src/lib/theme-transition.ts +2 -4
  197. package/src/lib/tone.ts +2 -4
  198. package/src/lib/utils.ts +2 -2
  199. package/src/modules.test.ts +105 -0
  200. package/src/onboarding/define-tours.test.ts +55 -40
  201. package/src/onboarding/define-tours.ts +23 -23
  202. package/src/onboarding/demo.svelte +24 -5
  203. package/src/onboarding/index.ts +1 -8
  204. package/src/onboarding/onboarding-provider.svelte +19 -7
  205. package/src/onboarding/onboarding.svelte.ts +16 -16
  206. package/src/onboarding/pick.test.ts +61 -52
  207. package/src/onboarding/pick.ts +16 -13
  208. package/src/onboarding/stores.test.ts +80 -80
  209. package/src/onboarding/stores.ts +41 -39
  210. package/src/onboarding/tour-card.svelte +30 -5
  211. package/src/onboarding/tour-runner.svelte +12 -3
  212. package/src/onboarding/types.ts +20 -12
  213. package/src/onboarding/wait.ts +22 -22
  214. package/src/panel/README.md +5 -0
  215. package/src/panel/index.ts +2 -0
  216. package/src/panel/side-panel.svelte +194 -0
  217. package/src/record/README.md +3 -0
  218. package/src/record/demo-data.ts +352 -0
  219. package/src/record/field-section.svelte +57 -0
  220. package/src/record/fields.ts +194 -0
  221. package/src/record/format.ts +94 -0
  222. package/src/{tasks/record → record}/index.ts +49 -35
  223. package/src/{tasks/record → record}/info-list.svelte +145 -114
  224. package/src/record/kinds.ts +42 -0
  225. package/src/record/logic.ts +326 -0
  226. package/src/record/next-up.svelte +81 -0
  227. package/src/{tasks/record → record}/project-list.svelte +56 -50
  228. package/src/{tasks/record → record}/record-demo.svelte +130 -110
  229. package/src/{tasks/record → record}/record-header.svelte +37 -28
  230. package/src/{tasks/record → record}/record-shell.svelte +54 -54
  231. package/src/record/record-stats.svelte +48 -0
  232. package/src/record/record-timeline.svelte +251 -0
  233. package/src/record/record.test.ts +471 -0
  234. package/src/{tasks/record → record}/steps-rail.svelte +225 -216
  235. package/src/record/types.ts +299 -0
  236. package/src/record/where-we-are.svelte +125 -0
  237. package/src/shadcn/button/button.svelte +1 -1
  238. package/src/shadcn/card/card-title.svelte +1 -5
  239. package/src/shadcn/hooks/use-highlighted-code.svelte.ts +2 -13
  240. package/src/shadcn/sheet/sheet-content.svelte +2 -4
  241. package/src/shadcn/table/table-cell.svelte +2 -3
  242. package/src/shadcn/utilities.css +3 -8
  243. package/src/slides/Controls.svelte +150 -124
  244. package/src/slides/Deck.svelte +243 -238
  245. package/src/slides/Fragment.svelte +64 -57
  246. package/src/slides/Overview.svelte +106 -101
  247. package/src/slides/Presenter.svelte +300 -266
  248. package/src/slides/Slide.svelte +185 -170
  249. package/src/slides/SlideList.svelte +16 -12
  250. package/src/slides/ambient.d.ts +1 -1
  251. package/src/slides/bridges.ts +42 -23
  252. package/src/slides/deck-controller.svelte.ts +47 -35
  253. package/src/slides/demo-slides.svelte +330 -306
  254. package/src/slides/demo.svelte +164 -160
  255. package/src/slides/export/capture.ts +20 -16
  256. package/src/slides/export/ffmpeg.ts +43 -38
  257. package/src/slides/export/index.ts +5 -5
  258. package/src/slides/export/launch.ts +3 -1
  259. package/src/slides/export/pdf.ts +30 -27
  260. package/src/slides/export/types.ts +10 -8
  261. package/src/slides/index.ts +11 -11
  262. package/src/slides/labels.ts +22 -19
  263. package/src/slides/layout.ts +9 -2
  264. package/src/slides/model.ts +4 -4
  265. package/src/slides/navigation.ts +43 -31
  266. package/src/slides/theme.css +5 -7
  267. package/src/slides/types.ts +9 -10
  268. package/src/status/README.md +18 -0
  269. package/src/status/define-statuses.ts +25 -0
  270. package/src/status/index.ts +11 -0
  271. package/src/{tasks → status}/status-badge.svelte +3 -1
  272. package/src/{tasks → status}/status-dot.svelte +1 -3
  273. package/src/{tasks → status}/status-icon.svelte +1 -1
  274. package/src/status/status-types.ts +40 -0
  275. package/src/tasks/README.md +1 -1
  276. package/src/tasks/board-order.ts +2 -4
  277. package/src/tasks/demo.svelte +192 -34
  278. package/src/tasks/detail/detail-demo.svelte +75 -15
  279. package/src/tasks/detail/detail-types.ts +45 -45
  280. package/src/tasks/detail/task-detail.svelte +40 -10
  281. package/src/tasks/detail/task-property.svelte +8 -2
  282. package/src/tasks/detail/task-thread.svelte +53 -12
  283. package/src/tasks/gantt/gantt-bar.svelte +17 -6
  284. package/src/tasks/gantt/gantt-grid.svelte +40 -9
  285. package/src/tasks/gantt/gantt-group-row.svelte +8 -2
  286. package/src/tasks/gantt/gantt-header.svelte +9 -3
  287. package/src/tasks/gantt/gantt-task-row.svelte +26 -6
  288. package/src/tasks/gantt/gantt.css +2 -1
  289. package/src/tasks/gantt/gantt.test.ts +4 -2
  290. package/src/tasks/gantt/logic.test.ts +110 -20
  291. package/src/tasks/gantt/logic.ts +42 -6
  292. package/src/tasks/inbox/inbox-card.svelte +15 -7
  293. package/src/tasks/inbox/inbox-draft.svelte +1 -1
  294. package/src/tasks/inbox/inbox-logic.ts +6 -40
  295. package/src/tasks/inbox/inbox-statuses.ts +24 -24
  296. package/src/tasks/inbox/inbox-trace.svelte +9 -3
  297. package/src/tasks/inbox/inbox-types.ts +54 -58
  298. package/src/tasks/inbox/index.ts +22 -21
  299. package/src/tasks/index.ts +52 -53
  300. package/src/tasks/kanban-board.svelte +16 -12
  301. package/src/tasks/kanban-types.ts +2 -3
  302. package/src/tasks/presets/sales.ts +7 -7
  303. package/src/tasks/task-gantt.svelte +28 -8
  304. package/src/tasks/task-list.svelte +41 -17
  305. package/src/tasks/time/duration.ts +40 -40
  306. package/src/tasks/time/time-chip.svelte +9 -2
  307. package/src/tasks/time/time-dot.svelte +1 -1
  308. package/src/tasks/time/time-ring.svelte +11 -3
  309. package/src/tasks/time/time-tracker.svelte +57 -15
  310. package/src/tasks/time/time-types.ts +57 -57
  311. package/src/tasks/use-kanban-dnd.svelte.ts +2 -3
  312. package/src/thread/README.md +31 -0
  313. package/src/thread/index.ts +12 -0
  314. package/src/thread/logic.ts +61 -0
  315. package/src/thread/thread.svelte +432 -0
  316. package/src/thread/thread.test.ts +73 -0
  317. package/src/thread/types.ts +93 -0
  318. package/src/tokens/craft.css +17 -53
  319. package/src/tokens/index.css +3 -13
  320. package/src/tokens/palette.css +13 -11
  321. package/src/tokens/primitives.css +10 -23
  322. package/src/components/list-page/section-label.svelte +0 -39
  323. package/src/tasks/define-statuses.ts +0 -32
  324. package/src/tasks/inbox/inbox.svelte +0 -203
  325. package/src/tasks/record/demo-data.ts +0 -286
  326. package/src/tasks/record/field-section.svelte +0 -53
  327. package/src/tasks/record/fields.ts +0 -142
  328. package/src/tasks/record/format.ts +0 -87
  329. package/src/tasks/record/kinds.ts +0 -42
  330. package/src/tasks/record/logic.ts +0 -324
  331. package/src/tasks/record/next-up.svelte +0 -70
  332. package/src/tasks/record/record-stats.svelte +0 -48
  333. package/src/tasks/record/record-timeline.svelte +0 -231
  334. package/src/tasks/record/record.test.ts +0 -350
  335. package/src/tasks/record/types.ts +0 -280
  336. package/src/tasks/record/where-we-are.svelte +0 -121
  337. package/src/tasks/side-panel.svelte +0 -193
  338. package/src/tasks/status-types.ts +0 -40
  339. /package/src/components/{list-page → toolbar}/toolbar-trigger.ts +0 -0
  340. /package/src/{tasks → panel}/side-panel-types.ts +0 -0
  341. /package/src/{tasks/record → record}/gutter.ts +0 -0
@@ -1,13 +1,15 @@
1
1
  /* Pure helpers for the avatar: numbers, theme, lights, idle scheduling. */
2
- import { DARK_INK, LIGHT_INK, luminance } from './vendor/color.js';
3
- import { stockLights } from './vendor/plastic.js';
2
+ import { DARK_INK, LIGHT_INK, luminance } from "./vendor/color.js";
3
+ import { stockLights } from "./vendor/plastic.js";
4
4
 
5
5
  const contrast = (a: number, b: number) => (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
6
6
 
7
7
  /** Off-black or off-white eyes, whichever reads stronger on the body: the vendor's fixed cutoff left 2:1 eyes on mid blues. */
8
8
  export function inkFor(body: string): string {
9
9
  const l = luminance(body);
10
- return contrast(l, luminance(DARK_INK)) >= contrast(l, luminance(LIGHT_INK)) ? DARK_INK : LIGHT_INK;
10
+ return contrast(l, luminance(DARK_INK)) >= contrast(l, luminance(LIGHT_INK))
11
+ ? DARK_INK
12
+ : LIGHT_INK;
11
13
  }
12
14
 
13
15
  export const clamp = (v: number, lo: number, hi: number) =>
@@ -16,7 +18,7 @@ export const q = (v: number, lo: number, hi: number) => Math.round(clamp(v, lo,
16
18
  export const clampOpt = (v: number | undefined, d: number, lo: number, hi: number) =>
17
19
  clamp(v ?? d, lo, hi);
18
20
  export const deviceDpr = () =>
19
- Math.min(2, (typeof devicePixelRatio === 'number' && devicePixelRatio) || 1);
21
+ Math.min(2, (typeof devicePixelRatio === "number" && devicePixelRatio) || 1);
20
22
 
21
23
  export function hashSeed(id: string): number {
22
24
  let h = 2166136261;
@@ -25,20 +27,23 @@ export function hashSeed(id: string): number {
25
27
  }
26
28
 
27
29
  export const reducedMotion = (): boolean =>
28
- typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;
30
+ typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
29
31
 
30
- export function resolveTheme(theme: 'auto' | 'dark' | 'light', el: HTMLElement | null): 'dark' | 'light' {
31
- if (theme !== 'auto') return theme;
32
- const host = el?.closest('[data-theme], .dark, .light') as HTMLElement | null;
32
+ export function resolveTheme(
33
+ theme: "auto" | "dark" | "light",
34
+ el: HTMLElement | null,
35
+ ): "dark" | "light" {
36
+ if (theme !== "auto") return theme;
37
+ const host = el?.closest("[data-theme], .dark, .light") as HTMLElement | null;
33
38
  if (host) {
34
- const v = host.getAttribute('data-theme');
35
- if (v === 'dark' || v === 'light') return v;
36
- if (host.classList.contains('dark')) return 'dark';
37
- if (host.classList.contains('light')) return 'light';
39
+ const v = host.getAttribute("data-theme");
40
+ if (v === "dark" || v === "light") return v;
41
+ if (host.classList.contains("dark")) return "dark";
42
+ if (host.classList.contains("light")) return "light";
38
43
  }
39
- return typeof matchMedia === 'function' && matchMedia('(prefers-color-scheme: light)').matches
40
- ? 'light'
41
- : 'dark';
44
+ return typeof matchMedia === "function" && matchMedia("(prefers-color-scheme: light)").matches
45
+ ? "light"
46
+ : "dark";
42
47
  }
43
48
 
44
49
  export function lightsFor(lightAt: number, backLight?: number, lightFront?: number) {
@@ -46,12 +51,13 @@ export function lightsFor(lightAt: number, backLight?: number, lightFront?: numb
46
51
  const b = ((backLight ?? 0) * Math.PI) / 180;
47
52
  const lights = stockLights(Math.sin(a), -Math.cos(a));
48
53
  if (backLight !== undefined) [lights.bx, lights.by] = [Math.sin(b), -Math.cos(b)];
49
- if (lightFront !== undefined) lights.front = (Math.min(85, Math.max(0, lightFront)) * Math.PI) / 180;
54
+ if (lightFront !== undefined)
55
+ lights.front = (Math.min(85, Math.max(0, lightFront)) * Math.PI) / 180;
50
56
  return lights;
51
57
  }
52
58
 
53
59
  export function warmIdle(fn: () => void): () => void {
54
- if (typeof requestIdleCallback === 'function') {
60
+ if (typeof requestIdleCallback === "function") {
55
61
  const id = requestIdleCallback(fn);
56
62
  return () => cancelIdleCallback(id);
57
63
  }
@@ -1,6 +1,6 @@
1
- export { default as AgentAvatar } from './agent-avatar.svelte';
2
- export { default as AgentCast } from './agent-cast.svelte';
3
- export type { Agent, AgentAvatarProps, AgentShape } from './types.js';
1
+ export { default as AgentAvatar } from "./agent-avatar.svelte";
2
+ export { default as AgentCast } from "./agent-cast.svelte";
3
+ export type { Agent, AgentAvatarProps, AgentShape } from "./types.js";
4
4
  export {
5
5
  agentPresets,
6
6
  agentShapes,
@@ -8,4 +8,4 @@ export {
8
8
  agentStates,
9
9
  agentPalette,
10
10
  agentStateLabels,
11
- } from './types.js';
11
+ } from "./types.js";
@@ -1,6 +1,6 @@
1
1
  /* What every avatar on the page shares: the batching shown-gate, so a row of
2
2
  them comes in together, the path caches, and one theme watcher. */
3
- import { bakesPending } from './vendor/plastic.js';
3
+ import { bakesPending } from "./vendor/plastic.js";
4
4
 
5
5
  export const SHOW_WITHIN = 4000;
6
6
  export const waiters = new Map<object, { ready: () => boolean; show: () => void }>();
@@ -45,19 +45,19 @@ const themeListeners = new Set<() => void>();
45
45
  let themeWatch: (() => void) | null = null;
46
46
  export function onThemeChange(fn: () => void): () => void {
47
47
  themeListeners.add(fn);
48
- if (!themeWatch && typeof MutationObserver === 'function' && typeof document !== 'undefined') {
48
+ if (!themeWatch && typeof MutationObserver === "function" && typeof document !== "undefined") {
49
49
  const fire = () => {
50
50
  for (const l of themeListeners) l();
51
51
  };
52
52
  const mo = new MutationObserver(fire);
53
- const opts = { attributes: true, attributeFilter: ['class', 'data-theme'] };
53
+ const opts = { attributes: true, attributeFilter: ["class", "data-theme"] };
54
54
  mo.observe(document.documentElement, opts);
55
55
  if (document.body) mo.observe(document.body, opts);
56
- const mq = typeof matchMedia === 'function' ? matchMedia('(prefers-color-scheme: dark)') : null;
57
- mq?.addEventListener('change', fire);
56
+ const mq = typeof matchMedia === "function" ? matchMedia("(prefers-color-scheme: dark)") : null;
57
+ mq?.addEventListener("change", fire);
58
58
  themeWatch = () => {
59
59
  mo.disconnect();
60
- mq?.removeEventListener('change', fire);
60
+ mq?.removeEventListener("change", fire);
61
61
  };
62
62
  }
63
63
  return () => {
@@ -1,4 +1,4 @@
1
- import type { BotAvatarFace, BotAvatarProps, BotAvatarType } from './vendor/types.js';
1
+ import type { BotAvatarFace, BotAvatarProps, BotAvatarType } from "./vendor/types.js";
2
2
 
3
3
  /** The body shapes an agent can be drawn as. */
4
4
  export type AgentShape = BotAvatarType;
@@ -11,7 +11,7 @@ export type {
11
11
  BotAvatarHat as AgentHat,
12
12
  BotAvatarGlasses as AgentGlasses,
13
13
  BotAvatarPreset as AgentPreset,
14
- } from './vendor/types.js';
14
+ } from "./vendor/types.js";
15
15
 
16
16
  export {
17
17
  botAvatarPresets as agentPresets,
@@ -20,7 +20,7 @@ export {
20
20
  botAvatarStates as agentStates,
21
21
  botAvatarPalette as agentPalette,
22
22
  stateLabels as agentStateLabels,
23
- } from './vendor/presets.js';
23
+ } from "./vendor/presets.js";
24
24
 
25
25
  /** One member of a cast: a name, a role, and the face they draw. */
26
26
  export type Agent = {
@@ -51,7 +51,7 @@ type KnownProps<T> = {
51
51
  */
52
52
  export type AgentAvatarProps = Omit<
53
53
  KnownProps<BotAvatarProps>,
54
- 'type' | 'face' | 'ink' | 'size' | 'className' | 'style'
54
+ "type" | "face" | "ink" | "size" | "className" | "style"
55
55
  > & {
56
56
  /** Display name, for the default aria-label. */
57
57
  name?: string;
@@ -68,7 +68,7 @@ export type AgentAvatarProps = Omit<
68
68
  class?: string;
69
69
  style?: string;
70
70
  onclick?: (event: MouseEvent) => void;
71
- 'aria-label'?: string;
71
+ "aria-label"?: string;
72
72
  /** Hide the canvas from assistive tech when a parent already names the agent. */
73
- 'aria-hidden'?: boolean | 'true' | 'false';
73
+ "aria-hidden"?: boolean | "true" | "false";
74
74
  };
@@ -50,12 +50,8 @@
50
50
  size="sm"
51
51
  icon
52
52
  disabled={disabled || status === "processing"}
53
- onclick={onclick}
54
- class={cn(
55
- "relative",
56
- status === "processing" && "pointer-events-none",
57
- className,
58
- )}
53
+ {onclick}
54
+ class={cn("relative", status === "processing" && "pointer-events-none", className)}
59
55
  >
60
56
  {#if status === "processing"}
61
57
  <Spinner class="size-4" />
@@ -68,12 +64,8 @@
68
64
  {variant}
69
65
  {size}
70
66
  disabled={disabled || status === "processing"}
71
- onclick={onclick}
72
- class={cn(
73
- "gap-1.5",
74
- status === "processing" && "pointer-events-none",
75
- className,
76
- )}
67
+ {onclick}
68
+ class={cn("gap-1.5", status === "processing" && "pointer-events-none", className)}
77
69
  >
78
70
  {#if status === "processing"}
79
71
  <Spinner class="size-3.5" />
@@ -41,7 +41,9 @@
41
41
  // DERIVED
42
42
  // =========================
43
43
  let heading = $derived(label || "Generating");
44
- let percent = $derived(progress && progress.total > 0 ? (progress.completed / progress.total) * 100 : 0);
44
+ let percent = $derived(
45
+ progress && progress.total > 0 ? (progress.completed / progress.total) * 100 : 0,
46
+ );
45
47
 
46
48
  // =========================
47
49
  // EFFECTS
@@ -82,7 +84,9 @@
82
84
  <!-- #key is the reflow: Svelte drops the node and builds a new one,
83
85
  which is what replays the pop-in on every step. -->
84
86
  {#key progress.completed}
85
- <span class="t-digit-group is-animating"><span class="t-digit">{progress.completed}</span></span>
87
+ <span class="t-digit-group is-animating"
88
+ ><span class="t-digit">{progress.completed}</span></span
89
+ >
86
90
  {/key}<span class="gen-total">/{progress.total}</span>
87
91
  </span>
88
92
  {/if}
@@ -93,7 +97,10 @@
93
97
  </div>
94
98
 
95
99
  <div class="gen-track" data-indeterminate={progress ? undefined : true}>
96
- <div class="gen-fill" style:transform={progress ? `scaleX(${percent / 100})` : undefined}></div>
100
+ <div
101
+ class="gen-fill"
102
+ style:transform={progress ? `scaleX(${percent / 100})` : undefined}
103
+ ></div>
97
104
  </div>
98
105
 
99
106
  {#if progress?.currentStep}
@@ -70,5 +70,4 @@
70
70
  bind:value
71
71
  onkeydown={handleKeyDown}
72
72
  {placeholder}
73
- {...rest}
74
- ></textarea>
73
+ {...rest}></textarea>
@@ -1,6 +1,5 @@
1
- /* WHY: the caret has to attach to the end of marked's {@html} output, which is
2
- never touched by Svelte's scoping, so the last direct child is reached with
3
- :global() while the parent class stays component-scoped. */
1
+ /* WHY: Svelte never scopes marked's {@html} output, so the caret reaches its last child
2
+ with :global() while the parent class stays scoped. */
4
3
  .ai-response.is-streaming > :last-child::after {
5
4
  content: "";
6
5
  display: inline-block;
@@ -2,22 +2,8 @@
2
2
  /* Source: https://github.com/Jakubantalik/transitions.dev */
3
3
 
4
4
  /*
5
- Usage:
6
- Apply .t-avatar to each item in your group (avatar, chip,
7
- badge, button). Bring your own size, shape, and stacking;
8
- this stylesheet only owns the hover transform + transition.
9
-
10
- <div class="t-avatar-group">
11
- <div class="t-avatar">…</div>
12
- <div class="t-avatar">…</div>
13
- </div>
14
-
15
- Wire-up (JS):
16
- On mouseenter of any .t-avatar, walk every sibling and set
17
- inline --shift and --scale-active with a distance falloff.
18
- Set transition-timing-function inline BEFORE the variable
19
- writes — --avatar-ease-in on hover-in, --avatar-ease-out on
20
- the root's mouseleave.
5
+ JS sets each sibling's --shift and --scale-active on hover, and must set
6
+ transition-timing-function inline before those writes, or the ease is wrong.
21
7
  */
22
8
 
23
9
  :root {
@@ -1,9 +1,6 @@
1
- /* Card hover tilt — transitions.dev `3d-tilt`.
2
- Bind pointermove to the flat outer `.t-tilt`, never the card: the rotating
3
- edges slip under the cursor and the hover flickers. JS writes --tilt-rx/ry
4
- and --tilt-gx/gy, adds `.is-tilting` while moving and `.is-hover` for the
5
- glare. Return and glare clocks have no token at their length, by design:
6
- the settle is meant to read slower than any surface. */
1
+ /* Card hover tilt, transitions.dev `3d-tilt`: bind pointermove to the flat outer
2
+ `.t-tilt`, never the card, or its rotating edges slip under the cursor and the
3
+ hover flickers. */
7
4
  :root {
8
5
  --tilt-perspective: 1000px;
9
6
  --tilt-return: 1000ms;
@@ -2,21 +2,8 @@
2
2
  /* Source: https://github.com/Jakubantalik/transitions.dev */
3
3
 
4
4
  /*
5
- Usage:
6
- <span class="t-digit-group is-animating">
7
- <span class="t-digit">1</span>
8
- <span class="t-digit">2</span>
9
- <span class="t-digit" data-stagger="1">.</span>
10
- <span class="t-digit" data-stagger="2">3</span>
11
- </span>
12
-
13
- Replay:
14
- Remove `.is-animating`, re-render digits (or swap text),
15
- force a reflow, then re-add `.is-animating`.
16
-
17
- Direction:
18
- --digit-dir-x / --digit-dir-y are unit-less multipliers
19
- (e.g. 1, -1, 0) applied to --digit-distance.
5
+ To replay, remove `.is-animating` from `.t-digit-group`, swap the digits, force a reflow, then
6
+ add it back, or the animation won't restart.
20
7
  */
21
8
 
22
9
  :root {
@@ -51,18 +51,8 @@
51
51
  }
52
52
 
53
53
  /* === Extension: bits-ui data-state integration === */
54
- /* WHY: bits-ui mounts content with [data-state] and [data-side]/[data-align]
55
- attributes. These selectors mirror the upstream states so consumers can drop
56
- .t-dropdown on a Popover/Menu/Tooltip Content.
57
-
58
- WHY "instant-open" is in the list: a tooltip reports three open states, not
59
- two. It says "delayed-open" when it waited out the hover delay and
60
- "instant-open" when it skipped that delay, which is every open while
61
- delayDuration is 0 and every neighbour opened inside the skip window. That
62
- third name was missing here, so those tooltips mounted, took no open rule,
63
- and stayed at opacity 0: present in the DOM, never on screen. Found
64
- 11 Sep 2026 in upsys, where the kit's provider defaulted delayDuration to 0
65
- and so produced nothing but "instant-open". */
54
+ /* WHY: a tooltip has three open states, and without "instant-open" every tooltip
55
+ with delayDuration 0 sat at opacity 0, never on screen (upsys, 11 Sep 2026). */
66
56
  .t-dropdown[data-state="open"],
67
57
  .t-dropdown[data-state="delayed-open"],
68
58
  .t-dropdown[data-state="instant-open"] {
@@ -111,11 +101,8 @@
111
101
  }
112
102
  }
113
103
 
114
- /* A tooltip that skipped its delay skips its entrance too. The first one in a
115
- group waits and animates in; the neighbours the pointer travels to inside the
116
- skip window are already open by the time the eye arrives, so animating them
117
- only adds a wait the delay was there to hide. Scoped to the tooltip slot
118
- because a menu or popover never reports this state. */
104
+ /* A tooltip that skipped its delay skips its entrance too, since a neighbour opened
105
+ inside the skip window is already there when the eye arrives. */
119
106
  [data-slot="tooltip-content"].t-dropdown[data-state="instant-open"] {
120
107
  transition: none;
121
108
  }
@@ -2,19 +2,9 @@
2
2
  /* Source: https://github.com/Jakubantalik/transitions.dev */
3
3
 
4
4
  /*
5
- Usage:
6
- <div class="t-clear has-value">
7
- <input type="text" value="…" />
8
- <div class="t-clear-mirror" aria-hidden="true">…</div>
9
- <div class="t-clear-placeholder" aria-hidden="true">Search</div>
10
- <div class="t-clear-glow" aria-hidden="true"></div>
11
- <button class="t-clear-btn" aria-label="Clear">…</button>
12
- </div>
13
-
14
- The transitions live in JS (per-frame transform/opacity/filter
15
- writes): the streak envelope and per-word gradient stack cannot
16
- be expressed as static @keyframes. This stylesheet only owns the
17
- resting state + the variables JS reads.
5
+ The clear runs in JS, since its per-word streak can't be static
6
+ @keyframes, so this file owns only the resting state and the
7
+ variables JS reads.
18
8
  */
19
9
 
20
10
  :root {
@@ -65,11 +55,8 @@
65
55
  .t-clear.has-value .t-clear-placeholder {
66
56
  opacity: 0;
67
57
  }
68
- /* The streak overlay: empty by default; JS writes a stack of
69
- radial-gradient(...) layers into background during a clear,
70
- then animates opacity. mix-blend-mode: multiply darkens the
71
- underlying input; flip to screen in dark mode so the same
72
- alpha values lighten instead of vanish. */
58
+ /* JS paints the streak's gradients here during a clear; dark mode
59
+ flips multiply to screen so the same alphas lighten, not vanish. */
73
60
  .t-clear-glow {
74
61
  position: absolute;
75
62
  inset: 0;
@@ -2,34 +2,9 @@
2
2
  /* Source: https://github.com/Jakubantalik/transitions.dev */
3
3
 
4
4
  /*
5
- Usage:
6
- Apply .t-input-wrap to your wrapper, .t-input to the
7
- element that should shake (your input field, its
8
- bordered wrapper, whatever owns the visible border),
9
- and .t-error-msg to the message you want to reveal.
10
- Bring your own sizing, padding, border colors, and
11
- typography.
12
-
13
- <div class="t-input-wrap">
14
- <div class="t-input">
15
- <input type="text">
16
- </div>
17
- <p class="t-error-msg">Please enter a valid email.</p>
18
- </div>
19
-
20
- Trigger:
21
- Add `.is-error` to .t-input-wrap and .t-input. Your
22
- own border-color rules drive the visible color; this
23
- stylesheet only owns the tween.
24
- Restart the shake by removing `.is-shaking` from
25
- .t-input, forcing a reflow, then re-adding it.
26
- Optional: after --revert-hold ms, drop both
27
- `.is-error` classes so border and message fade back
28
- to neutral over --revert-dur.
29
-
30
- Per-segment ease: each keyframe stop carries its own
31
- animation-timing-function so each leg follows the Figma
32
- cubic-bezier curve independently.
5
+ Put .is-error on .t-input-wrap and .t-input, and restart the
6
+ shake by removing `.is-shaking` from .t-input, forcing a
7
+ reflow, then re-adding it.
33
8
  */
34
9
 
35
10
  :root {
@@ -42,10 +17,8 @@
42
17
  --revert-dur: 280ms;
43
18
  }
44
19
 
45
- /* Border-color tween. Define your input's default / focused
46
- / error border-color in your own component CSS, this rule
47
- only owns the interpolation. Use a constant border-width
48
- across states so the tween never shifts inner content. */
20
+ /* This rule owns only the border-color tween, so keep the
21
+ border-width constant across states or the content shifts. */
49
22
  .t-input {
50
23
  transition: border-color 150ms ease-out;
51
24
  will-change: transform;
@@ -57,10 +30,8 @@
57
30
  transition: border-color var(--revert-dur, 280ms) ease-out;
58
31
  }
59
32
 
60
- /* Error message reveal. Visibility is delayed by --revert-dur
61
- on hide so the message stays painted for the full opacity
62
- fade-out. Entering .is-error drops the delay to 0 so the
63
- message becomes visible immediately. */
33
+ /* Hiding delays visibility by --revert-dur so the message stays
34
+ painted through its fade; .is-error drops the delay to 0. */
64
35
  .t-error-msg {
65
36
  opacity: 0;
66
37
  visibility: hidden;
@@ -76,11 +47,8 @@
76
47
  visibility 0s linear 0s;
77
48
  }
78
49
 
79
- /* Multi-segment keyframe with per-stop easing so each leg
80
- of the shake follows its own cubic-bezier independently.
81
- %-stops are cumulative durations as a fraction of the
82
- total (80, 60, 80, 60 = 280ms): 28.57%, 57.14%, 78.57%,
83
- 100%. Recompute if any segment duration changes. */
50
+ /* The %-stops are cumulative fractions of 280ms (80, 60, 80,
51
+ 60), so recompute them if any segment's duration changes. */
84
52
  .t-input.is-shaking {
85
53
  animation: t-input-shake calc(var(--shake-dur-a) * 2 + var(--shake-dur-b) * 2) linear;
86
54
  }
@@ -1,8 +1,5 @@
1
- /* Learn more hover — transitions.dev 24.
2
- The chevron shifts along the direction it goes and its two arms rotate
3
- apart about the apex, so the arrow leans into the move. Pure CSS.
4
- `transform-box: view-box` is what makes the arm origin resolve against
5
- the viewBox rather than each path's own bounding box. */
1
+ /* Learn more hover, transitions.dev 24: `transform-box: view-box` makes the arm origin
2
+ resolve against the viewBox, not each path's own bounding box. */
6
3
  :root {
7
4
  --learn-shift: 2px;
8
5
  --learn-spread: 8deg;
@@ -22,23 +19,34 @@
22
19
  vector-effect: non-scaling-stroke;
23
20
  transition: transform var(--learn-out) var(--learn-ease);
24
21
  }
25
- .t-learn:hover .t-learn-chevron,
26
22
  .t-learn:focus-visible .t-learn-chevron {
27
23
  transform: translateX(var(--learn-shift));
28
24
  transition-duration: var(--learn-in);
29
25
  }
30
- .t-learn:hover .t-learn-arm,
31
26
  .t-learn:focus-visible .t-learn-arm {
32
27
  transition-duration: var(--learn-in);
33
28
  }
34
- .t-learn:hover .t-learn-arm-top,
35
29
  .t-learn:focus-visible .t-learn-arm-top {
36
30
  transform: rotate(var(--learn-spread));
37
31
  }
38
- .t-learn:hover .t-learn-arm-bot,
39
32
  .t-learn:focus-visible .t-learn-arm-bot {
40
33
  transform: rotate(calc(var(--learn-spread) * -1));
41
34
  }
35
+ @media (hover: hover) and (pointer: fine) {
36
+ .t-learn:hover .t-learn-chevron {
37
+ transform: translateX(var(--learn-shift));
38
+ transition-duration: var(--learn-in);
39
+ }
40
+ .t-learn:hover .t-learn-arm {
41
+ transition-duration: var(--learn-in);
42
+ }
43
+ .t-learn:hover .t-learn-arm-top {
44
+ transform: rotate(var(--learn-spread));
45
+ }
46
+ .t-learn:hover .t-learn-arm-bot {
47
+ transform: rotate(calc(var(--learn-spread) * -1));
48
+ }
49
+ }
42
50
 
43
51
  @media (prefers-reduced-motion: reduce) {
44
52
  .t-learn-chevron,
@@ -1,7 +1,5 @@
1
- /* Like button — transitions.dev 23.
2
- Toggle `data-liked` to fill and pop the heart; add `.is-bursting` for
3
- one particle duration to fire the spray, writing --px/--py/--pdur/--pdelay
4
- per dot in JS so no two bursts match. */
1
+ /* Like button, transitions.dev 23. For the spray, JS writes --px/--py/--pdur/--pdelay
2
+ per dot while `.is-bursting` is on, so no two bursts match. */
5
3
  :root {
6
4
  --like-color: #f40051;
7
5
  --like-fill: var(--duration-quick, 150ms);
@@ -2,16 +2,8 @@
2
2
  /* Source: https://github.com/Jakubantalik/transitions.dev */
3
3
 
4
4
  /*
5
- Usage:
6
- <div class="t-page-slide" data-page="1">
7
- <section class="t-page" data-page-id="1">…</section>
8
- <section class="t-page" data-page-id="2">…</section>
9
- </div>
10
-
11
- State:
12
- Set data-page="1" or "2" on .t-page-slide.
13
- Page 1 exits to the left, page 2 exits to the right.
14
- --page-exit-enabled (0/1) disables the outgoing slide.
5
+ Set data-page="1" or "2" on .t-page-slide, which holds two .t-page
6
+ sections with data-page-id; --page-exit-enabled: 0 turns off the outgoing slide.
15
7
  */
16
8
 
17
9
  :root {
@@ -1,8 +1,5 @@
1
- /* Plus to menu morph — transitions.dev `dropdown-menu-morph`.
2
- The trigger becomes the surface: width, height and radius animate while the
3
- plus and the menu cross-fade through a blur. Set the open footprint on the
4
- consumer side; the two sizes here are the upstream demo's. Use `dropdown.css`
5
- instead when the surface is a separate popover that merely grows. */
1
+ /* transitions.dev `dropdown-menu-morph`: the trigger itself becomes the menu. Set the open
2
+ size on the consumer side, since these sizes are the upstream demo's. */
6
3
  :root {
7
4
  --morph-open-dur: var(--duration-medium, 350ms);
8
5
  --morph-close-dur: var(--duration-fast, 250ms);
@@ -2,17 +2,9 @@
2
2
  /* Source: https://github.com/Jakubantalik/transitions.dev */
3
3
 
4
4
  /*
5
- Usage:
6
- Duplicate the visible string into data-text so the ::before
7
- layer can mask the gradient onto the same glyphs. Keep them
8
- in sync if the text changes.
9
-
10
- <span class="t-shimmer" data-text="Planning next moves">
11
- Planning next moves
12
- </span>
13
-
14
- Pure CSS — no JS. Tune --shimmer-base / --shimmer-highlight in
15
- your own theme rules so the colors follow light / dark mode.
5
+ Copy the visible text into data-text and keep the two in sync, or the ::before
6
+ gradient lands on the wrong glyphs:
7
+ <span class="t-shimmer" data-text="Planning">Planning</span>
16
8
  */
17
9
 
18
10
  :root {
@@ -23,13 +15,8 @@
23
15
  --shimmer-ease: var(--ease-linear, linear);
24
16
  }
25
17
 
26
- /* Two-layer construction:
27
- 1. The base text renders normally in --shimmer-base.
28
- 2. ::before duplicates it via content: attr(data-text),
29
- paints a transparent → highlight → transparent gradient
30
- onto it, and clips that gradient to the glyphs via
31
- background-clip: text. Animating background-position
32
- sweeps the band across the text. */
18
+ /* ::before repeats the text from data-text and clips a moving gradient band to its
19
+ glyphs with background-clip: text. */
33
20
  .t-shimmer {
34
21
  position: relative;
35
22
  display: inline-block;
@@ -1,9 +1,5 @@
1
- /* Spinning counter — transitions.dev 26.
2
- One column per digit clips a 0-9 strip; JS translates each strip up by
3
- (spins * 10 + digit) cells and staggers the columns. The motion streak is an
4
- SVG feGaussianBlur with stdDeviation="0 Y" decayed per column: a CSS blur()
5
- is isotropic and would smear the digit sideways. Use `digit-pop-in.css` when
6
- a number simply updates in place. */
1
+ /* Spinning counter, transitions.dev 26: the streak is an SVG feGaussianBlur with
2
+ stdDeviation="0 Y" because a CSS blur() is isotropic and would smear digits sideways. */
7
3
  :root {
8
4
  --reel-dur: 1400ms;
9
5
  --reel-cell: 30px;
@@ -2,21 +2,8 @@
2
2
  /* Source: https://github.com/Jakubantalik/transitions.dev */
3
3
 
4
4
  /*
5
- Usage:
6
- Wrap your icon (SVG, image, anything) in .t-success-check.
7
- The wrapper drives fade + rotate + blur + Y-bob; if your
8
- icon is an SVG <path>, it gets the stroke-draw animation.
9
-
10
- <span class="t-success-check" data-state="out" aria-hidden="true">
11
- <svg viewBox="0 0 48 48" fill="none">…</svg>
12
- </span>
13
-
14
- Trigger:
15
- Cold load is data-state="out" (opacity 0; no animation).
16
- Show: set data-state="in".
17
-
18
- Replace the stroke-dasharray placeholder (20) with the result
19
- of path.getTotalLength() for your path, or set it inline in JS.
5
+ Wrap the icon in .t-success-check and flip data-state from "out" to "in".
6
+ Replace the stroke-dasharray placeholder (20) with your path's getTotalLength().
20
7
  */
21
8
 
22
9
  :root {