@heyramzi/ui 0.0.0-stage → 6.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 (599) hide show
  1. package/COMPONENTS.md +141 -0
  2. package/README.md +130 -2
  3. package/package.json +215 -3
  4. package/scripts/lib/sync-core.mjs +113 -0
  5. package/scripts/relative-imports.mjs +39 -0
  6. package/scripts/sf-symbol.mjs +93 -0
  7. package/scripts/sync-shadcn.mjs +341 -0
  8. package/scripts/sync-transitions.mjs +146 -0
  9. package/scripts/validate-apple-symbol-exports.mjs +45 -0
  10. package/src/agents/agent-avatar.svelte +639 -0
  11. package/src/agents/agent-cast.svelte +173 -0
  12. package/src/agents/demo.svelte +78 -0
  13. package/src/agents/index.ts +11 -0
  14. package/src/agents/types.ts +72 -0
  15. package/src/agents/vendor/LICENSE +21 -0
  16. package/src/agents/vendor/color.ts +155 -0
  17. package/src/agents/vendor/draw.ts +840 -0
  18. package/src/agents/vendor/engine.ts +845 -0
  19. package/src/agents/vendor/mesh.ts +838 -0
  20. package/src/agents/vendor/plastic.ts +4958 -0
  21. package/src/agents/vendor/presets.ts +103 -0
  22. package/src/agents/vendor/shapes.ts +41 -0
  23. package/src/agents/vendor/ticker.ts +67 -0
  24. package/src/agents/vendor/types.ts +261 -0
  25. package/src/agents/vendor/wear.ts +1699 -0
  26. package/src/ai/composer/Composer.css +108 -0
  27. package/src/ai/composer/Composer.svelte +111 -0
  28. package/src/ai/composer/index.ts +10 -0
  29. package/src/ai/confirmation/Confirmation.svelte +54 -0
  30. package/src/ai/confirmation/ConfirmationAccepted.svelte +23 -0
  31. package/src/ai/confirmation/ConfirmationAction.svelte +53 -0
  32. package/src/ai/confirmation/ConfirmationActions.svelte +24 -0
  33. package/src/ai/confirmation/ConfirmationFailed.svelte +23 -0
  34. package/src/ai/confirmation/ConfirmationRejected.svelte +23 -0
  35. package/src/ai/confirmation/ConfirmationRequest.svelte +25 -0
  36. package/src/ai/confirmation/ConfirmationTitle.svelte +25 -0
  37. package/src/ai/confirmation/confirmation-context.svelte.ts +22 -0
  38. package/src/ai/confirmation/index.ts +50 -0
  39. package/src/ai/conversation/Conversation.svelte +28 -0
  40. package/src/ai/conversation/ConversationContent.svelte +35 -0
  41. package/src/ai/conversation/ConversationEmptyState.svelte +46 -0
  42. package/src/ai/conversation/ConversationScrollButton.svelte +51 -0
  43. package/src/ai/conversation/index.ts +33 -0
  44. package/src/ai/conversation/stick-to-bottom-context.svelte.ts +131 -0
  45. package/src/ai/index.ts +119 -0
  46. package/src/ai/loading-state/PixelLoader.svelte +138 -0
  47. package/src/ai/loading-state/index.ts +5 -0
  48. package/src/ai/prompt-input/PromptInput.svelte +38 -0
  49. package/src/ai/prompt-input/PromptInputBody.svelte +19 -0
  50. package/src/ai/prompt-input/PromptInputSubmit.svelte +73 -0
  51. package/src/ai/prompt-input/PromptInputTextarea.svelte +74 -0
  52. package/src/ai/prompt-input/PromptInputToolbar.svelte +19 -0
  53. package/src/ai/prompt-input/index.ts +34 -0
  54. package/src/ai/reasoning/Reasoning.svelte +47 -0
  55. package/src/ai/reasoning/ReasoningContent.svelte +27 -0
  56. package/src/ai/reasoning/ReasoningTrigger.svelte +48 -0
  57. package/src/ai/reasoning/index.ts +22 -0
  58. package/src/ai/reasoning/reasoning-context.svelte.ts +20 -0
  59. package/src/ai/response/Response.css +32 -0
  60. package/src/ai/response/Response.svelte +130 -0
  61. package/src/ai/response/index.ts +5 -0
  62. package/src/ai/suggestion/Suggestion.svelte +43 -0
  63. package/src/ai/suggestion/Suggestions.svelte +25 -0
  64. package/src/ai/suggestion/index.ts +14 -0
  65. package/src/ai/thinking-dots/ThinkingDots.svelte +42 -0
  66. package/src/ai/thinking-dots/index.ts +5 -0
  67. package/src/ai/typing-dots/TypingDots.css +39 -0
  68. package/src/ai/typing-dots/TypingDots.svelte +27 -0
  69. package/src/ai/typing-dots/index.ts +10 -0
  70. package/src/ai/voice-waveform/VoiceWaveform.css +40 -0
  71. package/src/ai/voice-waveform/VoiceWaveform.svelte +46 -0
  72. package/src/ai/voice-waveform/index.ts +5 -0
  73. package/src/animations/README.md +84 -0
  74. package/src/animations/accordion.css +58 -0
  75. package/src/animations/avatar-group-hover.css +47 -0
  76. package/src/animations/card-tilt.css +74 -0
  77. package/src/animations/digit-pop-in.css +78 -0
  78. package/src/animations/dropdown.css +121 -0
  79. package/src/animations/icon-swap.css +43 -0
  80. package/src/animations/index.css +34 -0
  81. package/src/animations/input-clear-dissolve.css +86 -0
  82. package/src/animations/input-shake.css +114 -0
  83. package/src/animations/learn-more-hover.css +48 -0
  84. package/src/animations/like-button.css +93 -0
  85. package/src/animations/modal.css +75 -0
  86. package/src/animations/notification-badge.css +81 -0
  87. package/src/animations/page-side-by-side.css +63 -0
  88. package/src/animations/panel.css +86 -0
  89. package/src/animations/plus-menu-morph.css +97 -0
  90. package/src/animations/reasoning-stream.css +49 -0
  91. package/src/animations/resize.css +20 -0
  92. package/src/animations/shimmer-text.css +72 -0
  93. package/src/animations/skeleton-reveal.css +97 -0
  94. package/src/animations/spinning-counter.css +52 -0
  95. package/src/animations/streaming-text.css +31 -0
  96. package/src/animations/success-check.css +120 -0
  97. package/src/animations/tabs-sliding.css +83 -0
  98. package/src/animations/text-swap.css +40 -0
  99. package/src/animations/text-swap.ts +40 -0
  100. package/src/animations/texts-reveal.css +70 -0
  101. package/src/animations/thinking-states.css +65 -0
  102. package/src/animations/tooltip.css +72 -0
  103. package/src/animations/upstream-coverage.test.ts +65 -0
  104. package/src/animations/view-transition-reveal.ts +74 -0
  105. package/src/charts/animated-value.css +7 -0
  106. package/src/charts/animated-value.svelte +110 -0
  107. package/src/charts/area-chart.css +29 -0
  108. package/src/charts/area-chart.svelte +195 -0
  109. package/src/charts/bar-chart.css +119 -0
  110. package/src/charts/bar-chart.svelte +269 -0
  111. package/src/charts/charts.css +201 -0
  112. package/src/charts/crosshair.svelte +35 -0
  113. package/src/charts/donut-chart.css +56 -0
  114. package/src/charts/donut-chart.svelte +158 -0
  115. package/src/charts/edge-fade.svelte +43 -0
  116. package/src/charts/edge-fade.ts +16 -0
  117. package/src/charts/figure.css +100 -0
  118. package/src/charts/figure.svelte +122 -0
  119. package/src/charts/gauge-chart.css +94 -0
  120. package/src/charts/gauge-chart.svelte +303 -0
  121. package/src/charts/hover-band.test.ts +30 -0
  122. package/src/charts/hover-band.ts +21 -0
  123. package/src/charts/hover-focus.svelte +85 -0
  124. package/src/charts/index.ts +30 -0
  125. package/src/charts/legend.css +131 -0
  126. package/src/charts/legend.svelte +112 -0
  127. package/src/charts/line-chart.css +26 -0
  128. package/src/charts/line-chart.svelte +256 -0
  129. package/src/charts/motion.ts +19 -0
  130. package/src/charts/number-chart.css +168 -0
  131. package/src/charts/number-chart.svelte +177 -0
  132. package/src/charts/primitives/chart-container.svelte +57 -0
  133. package/src/charts/primitives/chart-style.svelte +36 -0
  134. package/src/charts/primitives/chart-tooltip.svelte +161 -0
  135. package/src/charts/primitives/chart-utils.ts +54 -0
  136. package/src/charts/primitives/index.ts +11 -0
  137. package/src/charts/reveal.svelte +61 -0
  138. package/src/charts/ring-chart.css +96 -0
  139. package/src/charts/ring-chart.svelte +158 -0
  140. package/src/charts/sparkline.css +45 -0
  141. package/src/charts/sparkline.svelte +140 -0
  142. package/src/charts/stat-card.css +103 -0
  143. package/src/charts/stat-card.svelte +267 -0
  144. package/src/charts/time-series-chart.css +28 -0
  145. package/src/charts/time-series-chart.svelte +179 -0
  146. package/src/charts/trend-pill.css +38 -0
  147. package/src/charts/trend-pill.svelte +48 -0
  148. package/src/design/index.css +270 -0
  149. package/src/design/polish.css +159 -0
  150. package/src/effects/animated-beam/AnimatedBeam.svelte +132 -0
  151. package/src/effects/animated-beam/diagrams/BeamSvg.svelte +91 -0
  152. package/src/effects/animated-beam/index.ts +2 -0
  153. package/src/effects/animated-beam/path-calculator.svelte.ts +70 -0
  154. package/src/effects/animated-beam/types.ts +23 -0
  155. package/src/effects/border-beam/BorderBeam.svelte +223 -0
  156. package/src/effects/border-beam/css.test.ts +46 -0
  157. package/src/effects/border-beam/css.ts +574 -0
  158. package/src/effects/border-beam/presets.ts +699 -0
  159. package/src/effects/border-beam/register-properties.test.ts +74 -0
  160. package/src/effects/border-beam/register-properties.ts +73 -0
  161. package/src/effects/border-beam/types.ts +38 -0
  162. package/src/effects/image-comparison/ImageComparison.css +66 -0
  163. package/src/effects/image-comparison/ImageComparison.svelte +92 -0
  164. package/src/effects/image-reveal/ImageReveal.css +10 -0
  165. package/src/effects/image-reveal/ImageReveal.svelte +357 -0
  166. package/src/effects/image-reveal/index.ts +2 -0
  167. package/src/effects/image-reveal/types.ts +35 -0
  168. package/src/effects/magnetic/magnetic.ts +81 -0
  169. package/src/effects/marquee/Marquee.css +52 -0
  170. package/src/effects/marquee/Marquee.svelte +96 -0
  171. package/src/effects/progressive-blur/ProgressiveBlur.css +9 -0
  172. package/src/effects/progressive-blur/ProgressiveBlur.svelte +63 -0
  173. package/src/effects/reveal/AnimatedGroup.svelte +101 -0
  174. package/src/effects/reveal/InView.svelte +77 -0
  175. package/src/effects/reveal/TextEffect.svelte +142 -0
  176. package/src/effects/reveal/index.ts +10 -0
  177. package/src/effects/reveal/observe.ts +33 -0
  178. package/src/effects/reveal/reveal.css +141 -0
  179. package/src/effects/reveal/types.ts +25 -0
  180. package/src/effects/shader-gradient/ShaderGradient.svelte +227 -0
  181. package/src/effects/shader-gradient/color.ts +44 -0
  182. package/src/effects/shader-gradient/index.ts +5 -0
  183. package/src/effects/shader-gradient/renderer.ts +456 -0
  184. package/src/effects/shader-gradient/shaders.ts +324 -0
  185. package/src/effects/shader-gradient/types.ts +68 -0
  186. package/src/effects/spotlight/Spotlight.css +14 -0
  187. package/src/effects/spotlight/Spotlight.svelte +61 -0
  188. package/src/effects/theme-toggle/ThemeToggle.css +21 -0
  189. package/src/effects/theme-toggle/ThemeToggle.svelte +101 -0
  190. package/src/icons/TradeIcon.svelte +16 -0
  191. package/src/icons/apple-symbol-exports.ts +135 -0
  192. package/src/icons/sf-symbols.ts +527 -0
  193. package/src/icons/trades.ts +89 -0
  194. package/src/index.ts +49 -0
  195. package/src/lib/arrive.ts +26 -0
  196. package/src/lib/hooks/is-mobile.svelte.ts +11 -0
  197. package/src/lib/icon-types.ts +17 -0
  198. package/src/lib/layout.ts +8 -0
  199. package/src/lib/panel.ts +15 -0
  200. package/src/lib/theme-transition.ts +51 -0
  201. package/src/lib/utils.ts +45 -0
  202. package/src/shadcn/accordion/accordion-content.svelte +22 -0
  203. package/src/shadcn/accordion/accordion-item.svelte +17 -0
  204. package/src/shadcn/accordion/accordion-trigger.svelte +35 -0
  205. package/src/shadcn/accordion/accordion.svelte +19 -0
  206. package/src/shadcn/accordion/index.ts +16 -0
  207. package/src/shadcn/alert/alert-description.svelte +23 -0
  208. package/src/shadcn/alert/alert-title.svelte +20 -0
  209. package/src/shadcn/alert/alert.svelte +44 -0
  210. package/src/shadcn/alert/index.ts +14 -0
  211. package/src/shadcn/alert-dialog/alert-dialog-action.svelte +18 -0
  212. package/src/shadcn/alert-dialog/alert-dialog-cancel.svelte +18 -0
  213. package/src/shadcn/alert-dialog/alert-dialog-content.svelte +29 -0
  214. package/src/shadcn/alert-dialog/alert-dialog-description.svelte +17 -0
  215. package/src/shadcn/alert-dialog/alert-dialog-footer.svelte +20 -0
  216. package/src/shadcn/alert-dialog/alert-dialog-header.svelte +20 -0
  217. package/src/shadcn/alert-dialog/alert-dialog-overlay.svelte +17 -0
  218. package/src/shadcn/alert-dialog/alert-dialog-portal.svelte +7 -0
  219. package/src/shadcn/alert-dialog/alert-dialog-title.svelte +17 -0
  220. package/src/shadcn/alert-dialog/alert-dialog-trigger.svelte +7 -0
  221. package/src/shadcn/alert-dialog/alert-dialog.svelte +7 -0
  222. package/src/shadcn/alert-dialog/index.ts +37 -0
  223. package/src/shadcn/attachment/attachment-action.svelte +23 -0
  224. package/src/shadcn/attachment/attachment-actions.svelte +23 -0
  225. package/src/shadcn/attachment/attachment-content.svelte +23 -0
  226. package/src/shadcn/attachment/attachment-description.svelte +23 -0
  227. package/src/shadcn/attachment/attachment-group.svelte +23 -0
  228. package/src/shadcn/attachment/attachment-media.svelte +44 -0
  229. package/src/shadcn/attachment/attachment-title.svelte +23 -0
  230. package/src/shadcn/attachment/attachment-trigger.svelte +29 -0
  231. package/src/shadcn/attachment/attachment.svelte +55 -0
  232. package/src/shadcn/attachment/index.ts +40 -0
  233. package/src/shadcn/avatar/avatar-badge.svelte +26 -0
  234. package/src/shadcn/avatar/avatar-fallback.svelte +20 -0
  235. package/src/shadcn/avatar/avatar-group-count.svelte +23 -0
  236. package/src/shadcn/avatar/avatar-group.svelte +23 -0
  237. package/src/shadcn/avatar/avatar-image.svelte +17 -0
  238. package/src/shadcn/avatar/avatar.svelte +26 -0
  239. package/src/shadcn/avatar/index.ts +22 -0
  240. package/src/shadcn/badge/badge.svelte +53 -0
  241. package/src/shadcn/badge/index.ts +2 -0
  242. package/src/shadcn/breadcrumb/breadcrumb-ellipsis.svelte +23 -0
  243. package/src/shadcn/breadcrumb/breadcrumb-item.svelte +20 -0
  244. package/src/shadcn/breadcrumb/breadcrumb-link.svelte +31 -0
  245. package/src/shadcn/breadcrumb/breadcrumb-list.svelte +23 -0
  246. package/src/shadcn/breadcrumb/breadcrumb-page.svelte +23 -0
  247. package/src/shadcn/breadcrumb/breadcrumb-separator.svelte +27 -0
  248. package/src/shadcn/breadcrumb/breadcrumb.svelte +21 -0
  249. package/src/shadcn/breadcrumb/index.ts +25 -0
  250. package/src/shadcn/bubble/bubble-content.svelte +31 -0
  251. package/src/shadcn/bubble/bubble-group.svelte +20 -0
  252. package/src/shadcn/bubble/bubble-reactions.svelte +52 -0
  253. package/src/shadcn/bubble/bubble.svelte +58 -0
  254. package/src/shadcn/bubble/index.ts +25 -0
  255. package/src/shadcn/button/button.svelte +121 -0
  256. package/src/shadcn/button/index.ts +17 -0
  257. package/src/shadcn/calendar/calendar-caption.svelte +76 -0
  258. package/src/shadcn/calendar/calendar-cell.svelte +19 -0
  259. package/src/shadcn/calendar/calendar-day.svelte +35 -0
  260. package/src/shadcn/calendar/calendar-grid-body.svelte +12 -0
  261. package/src/shadcn/calendar/calendar-grid-head.svelte +12 -0
  262. package/src/shadcn/calendar/calendar-grid-row.svelte +12 -0
  263. package/src/shadcn/calendar/calendar-grid.svelte +16 -0
  264. package/src/shadcn/calendar/calendar-head-cell.svelte +19 -0
  265. package/src/shadcn/calendar/calendar-header.svelte +19 -0
  266. package/src/shadcn/calendar/calendar-heading.svelte +16 -0
  267. package/src/shadcn/calendar/calendar-month-select.svelte +44 -0
  268. package/src/shadcn/calendar/calendar-month.svelte +15 -0
  269. package/src/shadcn/calendar/calendar-months.svelte +19 -0
  270. package/src/shadcn/calendar/calendar-nav.svelte +19 -0
  271. package/src/shadcn/calendar/calendar-next-button.svelte +31 -0
  272. package/src/shadcn/calendar/calendar-prev-button.svelte +31 -0
  273. package/src/shadcn/calendar/calendar-year-select.svelte +43 -0
  274. package/src/shadcn/calendar/calendar.svelte +118 -0
  275. package/src/shadcn/calendar/index.ts +40 -0
  276. package/src/shadcn/card/card-action.svelte +23 -0
  277. package/src/shadcn/card/card-content.svelte +20 -0
  278. package/src/shadcn/card/card-description.svelte +20 -0
  279. package/src/shadcn/card/card-footer.svelte +23 -0
  280. package/src/shadcn/card/card-header.svelte +23 -0
  281. package/src/shadcn/card/card-title.svelte +29 -0
  282. package/src/shadcn/card/card.svelte +25 -0
  283. package/src/shadcn/card/index.ts +25 -0
  284. package/src/shadcn/checkbox/checkbox.svelte +38 -0
  285. package/src/shadcn/checkbox/index.ts +6 -0
  286. package/src/shadcn/collapsible/collapsible-content.svelte +7 -0
  287. package/src/shadcn/collapsible/collapsible-trigger.svelte +7 -0
  288. package/src/shadcn/collapsible/collapsible.svelte +11 -0
  289. package/src/shadcn/collapsible/index.ts +13 -0
  290. package/src/shadcn/command/command-dialog.svelte +66 -0
  291. package/src/shadcn/command/command-empty.svelte +17 -0
  292. package/src/shadcn/command/command-group.svelte +40 -0
  293. package/src/shadcn/command/command-input.svelte +64 -0
  294. package/src/shadcn/command/command-item.svelte +37 -0
  295. package/src/shadcn/command/command-link-item.svelte +20 -0
  296. package/src/shadcn/command/command-list.svelte +20 -0
  297. package/src/shadcn/command/command-loading.svelte +7 -0
  298. package/src/shadcn/command/command-separator.svelte +17 -0
  299. package/src/shadcn/command/command-shortcut.svelte +23 -0
  300. package/src/shadcn/command/command.svelte +28 -0
  301. package/src/shadcn/command/index.ts +37 -0
  302. package/src/shadcn/context-menu/context-menu-checkbox-item.svelte +41 -0
  303. package/src/shadcn/context-menu/context-menu-content.svelte +28 -0
  304. package/src/shadcn/context-menu/context-menu-group-heading.svelte +21 -0
  305. package/src/shadcn/context-menu/context-menu-group.svelte +7 -0
  306. package/src/shadcn/context-menu/context-menu-item.svelte +27 -0
  307. package/src/shadcn/context-menu/context-menu-label.svelte +27 -0
  308. package/src/shadcn/context-menu/context-menu-portal.svelte +7 -0
  309. package/src/shadcn/context-menu/context-menu-radio-group.svelte +16 -0
  310. package/src/shadcn/context-menu/context-menu-radio-item.svelte +35 -0
  311. package/src/shadcn/context-menu/context-menu-separator.svelte +17 -0
  312. package/src/shadcn/context-menu/context-menu-shortcut.svelte +23 -0
  313. package/src/shadcn/context-menu/context-menu-sub-content.svelte +25 -0
  314. package/src/shadcn/context-menu/context-menu-sub-trigger.svelte +29 -0
  315. package/src/shadcn/context-menu/context-menu-sub.svelte +7 -0
  316. package/src/shadcn/context-menu/context-menu-trigger.svelte +17 -0
  317. package/src/shadcn/context-menu/context-menu.svelte +7 -0
  318. package/src/shadcn/context-menu/index.ts +52 -0
  319. package/src/shadcn/dialog/dialog-close.svelte +11 -0
  320. package/src/shadcn/dialog/dialog-content.svelte +57 -0
  321. package/src/shadcn/dialog/dialog-description.svelte +20 -0
  322. package/src/shadcn/dialog/dialog-footer.svelte +32 -0
  323. package/src/shadcn/dialog/dialog-header.svelte +20 -0
  324. package/src/shadcn/dialog/dialog-overlay.svelte +20 -0
  325. package/src/shadcn/dialog/dialog-portal.svelte +7 -0
  326. package/src/shadcn/dialog/dialog-title.svelte +17 -0
  327. package/src/shadcn/dialog/dialog-trigger.svelte +11 -0
  328. package/src/shadcn/dialog/dialog.svelte +7 -0
  329. package/src/shadcn/dialog/index.ts +34 -0
  330. package/src/shadcn/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  331. package/src/shadcn/dropdown-menu/dropdown-menu-checkbox-item.svelte +43 -0
  332. package/src/shadcn/dropdown-menu/dropdown-menu-content.svelte +31 -0
  333. package/src/shadcn/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  334. package/src/shadcn/dropdown-menu/dropdown-menu-group.svelte +7 -0
  335. package/src/shadcn/dropdown-menu/dropdown-menu-item.svelte +29 -0
  336. package/src/shadcn/dropdown-menu/dropdown-menu-label.svelte +27 -0
  337. package/src/shadcn/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  338. package/src/shadcn/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  339. package/src/shadcn/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
  340. package/src/shadcn/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  341. package/src/shadcn/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  342. package/src/shadcn/dropdown-menu/dropdown-menu-sub-content.svelte +20 -0
  343. package/src/shadcn/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  344. package/src/shadcn/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  345. package/src/shadcn/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  346. package/src/shadcn/dropdown-menu/dropdown-menu.svelte +7 -0
  347. package/src/shadcn/dropdown-menu/index.ts +56 -0
  348. package/src/shadcn/dropdown-menu/menu-item.ts +43 -0
  349. package/src/shadcn/empty/empty-content.svelte +23 -0
  350. package/src/shadcn/empty/empty-description.svelte +23 -0
  351. package/src/shadcn/empty/empty-header.svelte +20 -0
  352. package/src/shadcn/empty/empty-media.svelte +41 -0
  353. package/src/shadcn/empty/empty-title.svelte +20 -0
  354. package/src/shadcn/empty/empty.svelte +23 -0
  355. package/src/shadcn/empty/index.ts +22 -0
  356. package/src/shadcn/field/field-content.svelte +20 -0
  357. package/src/shadcn/field/field-description.svelte +25 -0
  358. package/src/shadcn/field/field-error.svelte +58 -0
  359. package/src/shadcn/field/field-group.svelte +23 -0
  360. package/src/shadcn/field/field-label.svelte +26 -0
  361. package/src/shadcn/field/field-legend.svelte +29 -0
  362. package/src/shadcn/field/field-separator.svelte +35 -0
  363. package/src/shadcn/field/field-set.svelte +24 -0
  364. package/src/shadcn/field/field-title.svelte +23 -0
  365. package/src/shadcn/field/field.svelte +53 -0
  366. package/src/shadcn/field/index.ts +33 -0
  367. package/src/shadcn/hooks/is-mobile.svelte.ts +9 -0
  368. package/src/shadcn/hover-card/hover-card-content.svelte +31 -0
  369. package/src/shadcn/hover-card/hover-card-portal.svelte +7 -0
  370. package/src/shadcn/hover-card/hover-card-trigger.svelte +7 -0
  371. package/src/shadcn/hover-card/hover-card.svelte +7 -0
  372. package/src/shadcn/hover-card/index.ts +15 -0
  373. package/src/shadcn/input/index.ts +9 -0
  374. package/src/shadcn/input/input.svelte +48 -0
  375. package/src/shadcn/input/secret-input.svelte +75 -0
  376. package/src/shadcn/input-otp/index.ts +15 -0
  377. package/src/shadcn/input-otp/input-otp-group.svelte +20 -0
  378. package/src/shadcn/input-otp/input-otp-separator.svelte +25 -0
  379. package/src/shadcn/input-otp/input-otp-slot.svelte +26 -0
  380. package/src/shadcn/input-otp/input-otp.svelte +22 -0
  381. package/src/shadcn/label/index.ts +7 -0
  382. package/src/shadcn/label/label.svelte +20 -0
  383. package/src/shadcn/marker/index.ts +15 -0
  384. package/src/shadcn/marker/marker-content.svelte +23 -0
  385. package/src/shadcn/marker/marker-icon.svelte +21 -0
  386. package/src/shadcn/marker/marker.svelte +52 -0
  387. package/src/shadcn/message/index.ts +22 -0
  388. package/src/shadcn/message/message-avatar.svelte +23 -0
  389. package/src/shadcn/message/message-content.svelte +23 -0
  390. package/src/shadcn/message/message-footer.svelte +23 -0
  391. package/src/shadcn/message/message-group.svelte +20 -0
  392. package/src/shadcn/message/message-header.svelte +23 -0
  393. package/src/shadcn/message/message.svelte +27 -0
  394. package/src/shadcn/popover/index.ts +28 -0
  395. package/src/shadcn/popover/popover-close.svelte +7 -0
  396. package/src/shadcn/popover/popover-content.svelte +38 -0
  397. package/src/shadcn/popover/popover-description.svelte +20 -0
  398. package/src/shadcn/popover/popover-header.svelte +20 -0
  399. package/src/shadcn/popover/popover-portal.svelte +7 -0
  400. package/src/shadcn/popover/popover-title.svelte +15 -0
  401. package/src/shadcn/popover/popover-trigger.svelte +17 -0
  402. package/src/shadcn/popover/popover.svelte +7 -0
  403. package/src/shadcn/progress/index.ts +7 -0
  404. package/src/shadcn/progress/progress.svelte +30 -0
  405. package/src/shadcn/radio-group/index.ts +10 -0
  406. package/src/shadcn/radio-group/radio-group-item.svelte +31 -0
  407. package/src/shadcn/radio-group/radio-group.svelte +19 -0
  408. package/src/shadcn/scroll-area/index.ts +10 -0
  409. package/src/shadcn/scroll-area/scroll-area-scrollbar.svelte +30 -0
  410. package/src/shadcn/scroll-area/scroll-area.svelte +43 -0
  411. package/src/shadcn/select/index.ts +37 -0
  412. package/src/shadcn/select/select-content.svelte +45 -0
  413. package/src/shadcn/select/select-group-heading.svelte +21 -0
  414. package/src/shadcn/select/select-group.svelte +17 -0
  415. package/src/shadcn/select/select-item.svelte +38 -0
  416. package/src/shadcn/select/select-label.svelte +20 -0
  417. package/src/shadcn/select/select-portal.svelte +7 -0
  418. package/src/shadcn/select/select-scroll-down-button.svelte +23 -0
  419. package/src/shadcn/select/select-scroll-up-button.svelte +23 -0
  420. package/src/shadcn/select/select-separator.svelte +18 -0
  421. package/src/shadcn/select/select-trigger.svelte +33 -0
  422. package/src/shadcn/select/select.svelte +11 -0
  423. package/src/shadcn/separator/index.ts +7 -0
  424. package/src/shadcn/separator/separator.svelte +23 -0
  425. package/src/shadcn/sheet/index.ts +34 -0
  426. package/src/shadcn/sheet/sheet-close.svelte +7 -0
  427. package/src/shadcn/sheet/sheet-content.svelte +72 -0
  428. package/src/shadcn/sheet/sheet-description.svelte +17 -0
  429. package/src/shadcn/sheet/sheet-footer.svelte +20 -0
  430. package/src/shadcn/sheet/sheet-header.svelte +20 -0
  431. package/src/shadcn/sheet/sheet-overlay.svelte +20 -0
  432. package/src/shadcn/sheet/sheet-portal.svelte +7 -0
  433. package/src/shadcn/sheet/sheet-title.svelte +17 -0
  434. package/src/shadcn/sheet/sheet-trigger.svelte +7 -0
  435. package/src/shadcn/sheet/sheet.svelte +7 -0
  436. package/src/shadcn/sidebar/constants.ts +6 -0
  437. package/src/shadcn/sidebar/context.svelte.ts +81 -0
  438. package/src/shadcn/sidebar/index.ts +75 -0
  439. package/src/shadcn/sidebar/sidebar-content.svelte +24 -0
  440. package/src/shadcn/sidebar/sidebar-footer.svelte +21 -0
  441. package/src/shadcn/sidebar/sidebar-group-action.svelte +33 -0
  442. package/src/shadcn/sidebar/sidebar-group-content.svelte +21 -0
  443. package/src/shadcn/sidebar/sidebar-group-label.svelte +33 -0
  444. package/src/shadcn/sidebar/sidebar-group.svelte +21 -0
  445. package/src/shadcn/sidebar/sidebar-header.svelte +21 -0
  446. package/src/shadcn/sidebar/sidebar-input.svelte +21 -0
  447. package/src/shadcn/sidebar/sidebar-inset.svelte +23 -0
  448. package/src/shadcn/sidebar/sidebar-menu-action.svelte +37 -0
  449. package/src/shadcn/sidebar/sidebar-menu-badge.svelte +24 -0
  450. package/src/shadcn/sidebar/sidebar-menu-button.svelte +103 -0
  451. package/src/shadcn/sidebar/sidebar-menu-item.svelte +21 -0
  452. package/src/shadcn/sidebar/sidebar-menu-skeleton.svelte +36 -0
  453. package/src/shadcn/sidebar/sidebar-menu-sub-button.svelte +39 -0
  454. package/src/shadcn/sidebar/sidebar-menu-sub-item.svelte +21 -0
  455. package/src/shadcn/sidebar/sidebar-menu-sub.svelte +24 -0
  456. package/src/shadcn/sidebar/sidebar-menu.svelte +21 -0
  457. package/src/shadcn/sidebar/sidebar-provider.svelte +62 -0
  458. package/src/shadcn/sidebar/sidebar-rail.svelte +36 -0
  459. package/src/shadcn/sidebar/sidebar-separator.svelte +19 -0
  460. package/src/shadcn/sidebar/sidebar-trigger.svelte +37 -0
  461. package/src/shadcn/sidebar/sidebar.svelte +109 -0
  462. package/src/shadcn/skeleton/index.ts +7 -0
  463. package/src/shadcn/skeleton/skeleton.svelte +17 -0
  464. package/src/shadcn/slider/index.ts +7 -0
  465. package/src/shadcn/slider/slider.svelte +52 -0
  466. package/src/shadcn/sonner/index.ts +1 -0
  467. package/src/shadcn/sonner/sonner.svelte +34 -0
  468. package/src/shadcn/spinner/index.ts +1 -0
  469. package/src/shadcn/spinner/spinner.svelte +26 -0
  470. package/src/shadcn/switch/index.ts +7 -0
  471. package/src/shadcn/switch/switch.svelte +31 -0
  472. package/src/shadcn/table/index.ts +28 -0
  473. package/src/shadcn/table/table-body.svelte +20 -0
  474. package/src/shadcn/table/table-caption.svelte +20 -0
  475. package/src/shadcn/table/table-cell.svelte +20 -0
  476. package/src/shadcn/table/table-footer.svelte +20 -0
  477. package/src/shadcn/table/table-head.svelte +23 -0
  478. package/src/shadcn/table/table-header.svelte +20 -0
  479. package/src/shadcn/table/table-row.svelte +23 -0
  480. package/src/shadcn/table/table.svelte +25 -0
  481. package/src/shadcn/tabs/index.ts +16 -0
  482. package/src/shadcn/tabs/tabs-content.svelte +17 -0
  483. package/src/shadcn/tabs/tabs-list.svelte +25 -0
  484. package/src/shadcn/tabs/tabs-trigger.svelte +20 -0
  485. package/src/shadcn/tabs/tabs.svelte +19 -0
  486. package/src/shadcn/textarea/index.ts +7 -0
  487. package/src/shadcn/textarea/textarea.svelte +23 -0
  488. package/src/shadcn/toggle/index.ts +13 -0
  489. package/src/shadcn/toggle/toggle.svelte +53 -0
  490. package/src/shadcn/toggle-group/index.ts +10 -0
  491. package/src/shadcn/toggle-group/toggle-group-item.svelte +35 -0
  492. package/src/shadcn/toggle-group/toggle-group.svelte +59 -0
  493. package/src/shadcn/tooltip/context.ts +16 -0
  494. package/src/shadcn/tooltip/index.ts +19 -0
  495. package/src/shadcn/tooltip/tooltip-content.svelte +38 -0
  496. package/src/shadcn/tooltip/tooltip-portal.svelte +7 -0
  497. package/src/shadcn/tooltip/tooltip-provider.svelte +16 -0
  498. package/src/shadcn/tooltip/tooltip-trigger.svelte +7 -0
  499. package/src/shadcn/tooltip/tooltip.svelte +19 -0
  500. package/src/shadcn/utilities.css +549 -0
  501. package/src/showcase/AiSection.svelte +157 -0
  502. package/src/showcase/AnimationsSection.svelte +1658 -0
  503. package/src/showcase/ChartsSection.svelte +458 -0
  504. package/src/showcase/EffectsSection.svelte +152 -0
  505. package/src/showcase/ShadcnSection.svelte +27 -0
  506. package/src/showcase/ShowcaseImport.svelte +126 -0
  507. package/src/showcase/ShowcaseList.svelte +132 -0
  508. package/src/showcase/ShowcaseNav.svelte +247 -0
  509. package/src/showcase/ShowcaseSection.svelte +112 -0
  510. package/src/showcase/ShowcaseShell.svelte +55 -0
  511. package/src/showcase/ShowcaseStage.svelte +342 -0
  512. package/src/showcase/ShowcaseVariant.svelte +109 -0
  513. package/src/showcase/assets/image-reveal/art-1.jpg +0 -0
  514. package/src/showcase/assets/image-reveal/art-2.jpg +0 -0
  515. package/src/showcase/assets/image-reveal/art-3.jpg +0 -0
  516. package/src/showcase/check.svg +1 -0
  517. package/src/showcase/chevron-arms.svg +2 -0
  518. package/src/showcase/chevron-down.svg +1 -0
  519. package/src/showcase/copy.svg +2 -0
  520. package/src/showcase/demos/ai/confirmation.svelte +59 -0
  521. package/src/showcase/demos/ai/conversation.svelte +59 -0
  522. package/src/showcase/demos/ai/loading-state.svelte +19 -0
  523. package/src/showcase/demos/ai/prompt-input.svelte +57 -0
  524. package/src/showcase/demos/ai/reasoning.svelte +19 -0
  525. package/src/showcase/demos/ai/thinking-dots.svelte +15 -0
  526. package/src/showcase/demos/ai/voice-waveform.svelte +24 -0
  527. package/src/showcase/demos/effects/animated-beam.svelte +50 -0
  528. package/src/showcase/demos/effects/animated-group.svelte +47 -0
  529. package/src/showcase/demos/effects/border-beam-default.svelte +20 -0
  530. package/src/showcase/demos/effects/border-beam-line.svelte +20 -0
  531. package/src/showcase/demos/effects/border-beam-mono.svelte +20 -0
  532. package/src/showcase/demos/effects/border-beam-sunset.svelte +20 -0
  533. package/src/showcase/demos/effects/image-comparison.svelte +25 -0
  534. package/src/showcase/demos/effects/image-reveal.svelte +49 -0
  535. package/src/showcase/demos/effects/in-view.svelte +41 -0
  536. package/src/showcase/demos/effects/integrations-hub.svelte +82 -0
  537. package/src/showcase/demos/effects/magnetic.svelte +31 -0
  538. package/src/showcase/demos/effects/marquee.svelte +33 -0
  539. package/src/showcase/demos/effects/progressive-blur.svelte +47 -0
  540. package/src/showcase/demos/effects/spotlight.svelte +40 -0
  541. package/src/showcase/demos/effects/text-effect.svelte +55 -0
  542. package/src/showcase/demos/shadcn/accordion.svelte +45 -0
  543. package/src/showcase/demos/shadcn/alert-dialog.svelte +23 -0
  544. package/src/showcase/demos/shadcn/alert.svelte +30 -0
  545. package/src/showcase/demos/shadcn/attachment.svelte +71 -0
  546. package/src/showcase/demos/shadcn/avatar.svelte +30 -0
  547. package/src/showcase/demos/shadcn/badge.svelte +26 -0
  548. package/src/showcase/demos/shadcn/breadcrumb.svelte +34 -0
  549. package/src/showcase/demos/shadcn/bubble.svelte +36 -0
  550. package/src/showcase/demos/shadcn/button.svelte +11 -0
  551. package/src/showcase/demos/shadcn/calendar.svelte +8 -0
  552. package/src/showcase/demos/shadcn/card.svelte +39 -0
  553. package/src/showcase/demos/shadcn/checkbox.svelte +39 -0
  554. package/src/showcase/demos/shadcn/collapsible.svelte +20 -0
  555. package/src/showcase/demos/shadcn/command.svelte +48 -0
  556. package/src/showcase/demos/shadcn/context-menu.svelte +54 -0
  557. package/src/showcase/demos/shadcn/demo-harness.svelte +12 -0
  558. package/src/showcase/demos/shadcn/demos.test.ts +20 -0
  559. package/src/showcase/demos/shadcn/dialog.svelte +38 -0
  560. package/src/showcase/demos/shadcn/dropdown-menu.svelte +59 -0
  561. package/src/showcase/demos/shadcn/empty.svelte +29 -0
  562. package/src/showcase/demos/shadcn/field.svelte +115 -0
  563. package/src/showcase/demos/shadcn/hover-card.svelte +32 -0
  564. package/src/showcase/demos/shadcn/index.ts +358 -0
  565. package/src/showcase/demos/shadcn/input-otp.svelte +19 -0
  566. package/src/showcase/demos/shadcn/input.svelte +5 -0
  567. package/src/showcase/demos/shadcn/label.svelte +11 -0
  568. package/src/showcase/demos/shadcn/marker.svelte +30 -0
  569. package/src/showcase/demos/shadcn/message.svelte +75 -0
  570. package/src/showcase/demos/shadcn/popover.svelte +36 -0
  571. package/src/showcase/demos/shadcn/progress.svelte +13 -0
  572. package/src/showcase/demos/shadcn/radio-group.svelte +19 -0
  573. package/src/showcase/demos/shadcn/scroll-area.svelte +18 -0
  574. package/src/showcase/demos/shadcn/select.svelte +29 -0
  575. package/src/showcase/demos/shadcn/separator.svelte +12 -0
  576. package/src/showcase/demos/shadcn/sheet.svelte +48 -0
  577. package/src/showcase/demos/shadcn/skeleton.svelte +11 -0
  578. package/src/showcase/demos/shadcn/slider.svelte +7 -0
  579. package/src/showcase/demos/shadcn/sonner.svelte +18 -0
  580. package/src/showcase/demos/shadcn/spinner.svelte +11 -0
  581. package/src/showcase/demos/shadcn/switch.svelte +9 -0
  582. package/src/showcase/demos/shadcn/table.svelte +76 -0
  583. package/src/showcase/demos/shadcn/tabs.svelte +62 -0
  584. package/src/showcase/demos/shadcn/textarea.svelte +5 -0
  585. package/src/showcase/demos/shadcn/toggle-group.svelte +18 -0
  586. package/src/showcase/demos/shadcn/toggle.svelte +14 -0
  587. package/src/showcase/demos/shadcn/tooltip.svelte +13 -0
  588. package/src/showcase/heart.svg +1 -0
  589. package/src/showcase/index.ts +38 -0
  590. package/src/showcase/kit.test.ts +72 -0
  591. package/src/showcase/kit.ts +17 -0
  592. package/src/showcase/plus.svg +1 -0
  593. package/src/showcase/showcase-shell.css +91 -0
  594. package/src/showcase/stacked-section.css +15 -0
  595. package/src/showcase/success-check.svg +1 -0
  596. package/src/showcase/types.ts +29 -0
  597. package/src/svg-raw.d.ts +7 -0
  598. package/src/test-setup.ts +34 -0
  599. package/src/tokens.css +993 -0
@@ -0,0 +1,1658 @@
1
+ <!-- ========================== -->
2
+ <!-- IMPORTS -->
3
+ <!-- ========================== -->
4
+ <script lang="ts">
5
+ import { untrack } from "svelte";
6
+ import { swapText } from "../animations/text-swap.js";
7
+ import Bell from "@lucide/svelte/icons/bell";
8
+ import Info from "@lucide/svelte/icons/info";
9
+ import Menu from "@lucide/svelte/icons/menu";
10
+ import X from "@lucide/svelte/icons/x";
11
+ import ShowcaseStage from "./ShowcaseStage.svelte";
12
+ import chevronArms from "./chevron-arms.svg?raw";
13
+ import chevronDown from "./chevron-down.svg?raw";
14
+ import heart from "./heart.svg?raw";
15
+ import plus from "./plus.svg?raw";
16
+ import successCheck from "./success-check.svg?raw";
17
+
18
+ // =========================
19
+ // CONST
20
+ // =========================
21
+ const CLEAR_TEXT = "project deadline";
22
+
23
+ // =========================
24
+ // STATE
25
+ // =========================
26
+ let target = null;
27
+ const phrases = [
28
+ "Build the system.",
29
+ "Ship the route.",
30
+ "Verify the output.",
31
+ "Repeat tomorrow.",
32
+ ];
33
+ let cursor = 0;
34
+
35
+ let digitGroup = null;
36
+ let digitAnimating = $state(false);
37
+ let digitValue = $state("1234");
38
+
39
+ let resizeSmall = $state(false);
40
+ let badgeOpen = $state(true);
41
+ let badgeCount = $state(3);
42
+ let activePage = $state<"1" | "2">("1");
43
+
44
+ let modalOpen = $state(true);
45
+ let dropdownOpen = $state(true);
46
+ let panelOpen = $state(true);
47
+ let iconState = $state<"a" | "b">("a");
48
+
49
+ let checkEl = null;
50
+
51
+ let avatarRoot = null;
52
+ // Dummy team members so the hover-lift reads as a real avatar stack.
53
+ const avatars = [
54
+ { initials: "RK", hue: 24 },
55
+ { initials: "KA", hue: 158 },
56
+ { initials: "AM", hue: 268 },
57
+ { initials: "MT", hue: 334 },
58
+ { initials: "ZL", hue: 200 },
59
+ ];
60
+
61
+ let shakeWrap = null;
62
+ let shakeInput = null;
63
+ let shakeRevert;
64
+
65
+ let clearWrap = null;
66
+ let clearInput = null;
67
+ let clearMirror = null;
68
+ let clearPhold = null;
69
+ let clearGlow = null;
70
+ let clearBusy = false;
71
+
72
+ let skelEl = null;
73
+ let skelSkeleton = null;
74
+
75
+ let tabsBar = null;
76
+ let tabsPill = null;
77
+ const tabs = ["Plan", "Debug", "Ask"];
78
+ let activeTab = $state(0);
79
+
80
+ let staggerEl = null;
81
+
82
+ // =========================
83
+ // EFFECTS
84
+ // =========================
85
+ $effect(() => {
86
+ const checkPath = checkEl?.querySelector("path");
87
+ if (!checkPath) return;
88
+ const len = Math.ceil(checkPath.getTotalLength());
89
+ checkPath.style.strokeDasharray = String(len);
90
+ checkPath.style.strokeDashoffset = String(len);
91
+ });
92
+
93
+ $effect(() => {
94
+ untrack(() => positionTabsPill(false));
95
+ const onResize = () => untrack(() => positionTabsPill(false));
96
+ window.addEventListener("resize", onResize);
97
+ return () => window.removeEventListener("resize", onResize);
98
+ });
99
+
100
+ // =========================
101
+ // FUNCTIONS
102
+ // =========================
103
+ function cssNum(name: string, fallback: number) {
104
+ const v = parseFloat(getComputedStyle(document.documentElement).getPropertyValue(name));
105
+ return Number.isFinite(v) ? v : fallback;
106
+ }
107
+ function nextPhrase() {
108
+ if (!target) return;
109
+ cursor = (cursor + 1) % phrases.length;
110
+ swapText(target, phrases[cursor]);
111
+ }
112
+
113
+ function replayDigits() {
114
+ if (!digitGroup) return;
115
+ digitAnimating = false;
116
+ digitValue = String(Math.floor(1000 + Math.random() * 8999));
117
+ // WHY: force reflow so removing+re-adding .is-animating restarts the keyframes
118
+ void digitGroup.offsetWidth;
119
+ digitAnimating = true;
120
+ }
121
+
122
+ function bumpBadge() {
123
+ badgeOpen = false;
124
+ setTimeout(() => {
125
+ badgeCount += 1;
126
+ badgeOpen = true;
127
+ }, 220);
128
+ }
129
+
130
+ function togglePage() {
131
+ activePage = activePage === "1" ? "2" : "1";
132
+ }
133
+
134
+ function replayCheck() {
135
+ if (!checkEl) return;
136
+ checkEl.setAttribute("data-state", "out");
137
+ // WHY: force reflow so the appear keyframes restart from offset 0
138
+ void checkEl.offsetWidth;
139
+ checkEl.setAttribute("data-state", "in");
140
+ }
141
+
142
+ function liftAvatars(activeIdx: number | null) {
143
+ if (!avatarRoot) return;
144
+ const lift = cssNum("--avatar-lift", -4);
145
+ const falloff = cssNum("--avatar-falloff", 0.45);
146
+ const scale = cssNum("--avatar-scale", 1.05);
147
+ const ease = "cubic-bezier(0.22, 1, 0.36, 1)";
148
+ avatarRoot.querySelectorAll(".t-avatar").forEach((el, i) => {
149
+ el.style.transitionTimingFunction = ease;
150
+ if (activeIdx === null) {
151
+ el.style.setProperty("--shift", "0px");
152
+ el.style.setProperty("--scale-active", "1");
153
+ return;
154
+ }
155
+ const d = Math.abs(i - activeIdx);
156
+ el.style.setProperty("--shift", `${(lift * Math.pow(falloff, d)).toFixed(3)}px`);
157
+ el.style.setProperty("--scale-active", i === activeIdx ? String(scale) : "1");
158
+ });
159
+ }
160
+
161
+ function showError() {
162
+ if (!shakeWrap || !shakeInput) return;
163
+ shakeWrap.classList.add("is-error");
164
+ shakeInput.classList.add("is-error");
165
+ // Replay the shake from a clean baseline.
166
+ shakeInput.classList.remove("is-shaking");
167
+ void shakeInput.offsetWidth;
168
+ shakeInput.classList.add("is-shaking");
169
+ const shakeMs = cssNum("--shake-dur-a", 80) * 2 + cssNum("--shake-dur-b", 60) * 2;
170
+ setTimeout(() => shakeInput?.classList.remove("is-shaking"), shakeMs + 20);
171
+ if (shakeRevert) clearTimeout(shakeRevert);
172
+ const hold = cssNum("--revert-hold", 3000);
173
+ shakeRevert = setTimeout(() => {
174
+ shakeWrap?.classList.remove("is-error");
175
+ shakeInput?.classList.remove("is-error");
176
+ }, shakeMs + hold);
177
+ }
178
+
179
+ // Minimal cubic-bezier sampler so the JS easing matches the CSS curves.
180
+ function cubicBezier(str: string) {
181
+ const m = str.match(/cubic-bezier\(([-\d.]+),\s*([-\d.]+),\s*([-\d.]+),\s*([-\d.]+)\)/);
182
+ if (!m) return (t: number) => t;
183
+ const [x1, y1, x2, y2] = m.slice(1).map(Number);
184
+ const cx = 3 * x1;
185
+ const bx = 3 * (x2 - x1) - cx;
186
+ const ax = 1 - cx - bx;
187
+ const cy = 3 * y1;
188
+ const by = 3 * (y2 - y1) - cy;
189
+ const ay = 1 - cy - by;
190
+ return (t: number) => {
191
+ if (t <= 0) return 0;
192
+ if (t >= 1) return 1;
193
+ let s = t;
194
+ for (let i = 0; i < 8; i++) {
195
+ const dx = ((ax * s + bx) * s + cx) * s - t;
196
+ const d = (3 * ax * s + 2 * bx) * s + cx;
197
+ if (Math.abs(dx) < 1e-6 || d === 0) break;
198
+ s -= dx / d;
199
+ }
200
+ return ((ay * s + by) * s + cy) * s;
201
+ };
202
+ }
203
+
204
+ function buildClearGlow(text: string, isDark: boolean) {
205
+ if (!clearInput || !clearWrap) return "";
206
+ const ctx = document.createElement("canvas").getContext("2d");
207
+ if (!ctx) return "";
208
+ ctx.font = getComputedStyle(clearInput).font;
209
+ const rgb = isDark ? "255,255,255" : "0,0,0";
210
+ const w = clearWrap.clientWidth || 280;
211
+ const padLeft = parseFloat(getComputedStyle(clearInput).paddingLeft) || 12;
212
+ const spread = cssNum("--glow-spread", 1.5);
213
+ const layers: string[] = [];
214
+ let x = 0;
215
+ text.split(/(\s+)/).forEach((seg) => {
216
+ const segW = ctx.measureText(seg).width;
217
+ if (seg.trim()) {
218
+ const cx = padLeft + x + segW / 2;
219
+ const hw = Math.max(segW * 0.45, 8) * spread;
220
+ (
221
+ [
222
+ [0, 0.8, 7, 0.22],
223
+ [hw * 0.45, 0.55, 8, 0.18],
224
+ [-hw * 0.4, 0.65, 6, 0.16],
225
+ [hw * 0.15, 0.9, 5, 0.14],
226
+ ] as const
227
+ ).forEach(([dx, rwm, rh, a]) => {
228
+ const lx = (((cx + dx) / w) * 100).toFixed(2);
229
+ layers.push(
230
+ `radial-gradient(ellipse ${Math.max(hw * rwm, 2).toFixed(1)}px ${rh}px at ${lx}% 100%, rgba(${rgb},${a}), transparent)`,
231
+ );
232
+ });
233
+ }
234
+ x += segW;
235
+ });
236
+ return layers.join(", ");
237
+ }
238
+
239
+ function triggerClear() {
240
+ if (clearBusy || !clearWrap || !clearInput || !clearMirror || !clearPhold || !clearGlow) return;
241
+ // Repeatable demo: an empty field refills instantly instead of clearing.
242
+ if (!clearInput.value) {
243
+ clearInput.value = CLEAR_TEXT;
244
+ clearMirror.textContent = CLEAR_TEXT;
245
+ clearWrap.classList.add("has-value");
246
+ return;
247
+ }
248
+ clearBusy = true;
249
+ const isDark = !document.documentElement.classList.contains("light");
250
+ const total = cssNum("--clear-dur", 1000);
251
+ const outDur = cssNum("--clear-out-dur", 400);
252
+ const inDur = cssNum("--clear-in-dur", 400);
253
+ const outFly = cssNum("--clear-out-fly", 12);
254
+ const inFly = cssNum("--clear-in-fly", 12);
255
+ const blur = cssNum("--clear-blur", 2);
256
+ const delay = cssNum("--glow-delay", 50);
257
+ const peakAt = cssNum("--glow-peak-at", 0.15);
258
+ const gOp = isDark ? 0.85 : cssNum("--glow-opacity", 0.42);
259
+ const cs = getComputedStyle(document.documentElement);
260
+ const easeOut = cubicBezier(cs.getPropertyValue("--clear-out-ease"));
261
+ const easeIn = cubicBezier(cs.getPropertyValue("--clear-in-ease"));
262
+
263
+ const text = clearInput.value;
264
+ clearMirror.textContent = text;
265
+ clearInput.value = "";
266
+ clearWrap.classList.remove("has-value");
267
+ clearWrap.classList.add("is-clearing");
268
+ clearGlow.style.mixBlendMode = isDark ? "screen" : "multiply";
269
+ clearGlow.style.background = buildClearGlow(text, isDark);
270
+ clearGlow.style.opacity = "0";
271
+ clearPhold.style.transform = `translateY(-${inFly}px)`;
272
+ clearPhold.style.opacity = "0.9";
273
+ clearPhold.style.filter = `blur(${blur}px)`;
274
+
275
+ const start = performance.now();
276
+ const tick = (now: number) => {
277
+ if (!clearWrap || !clearMirror || !clearPhold || !clearGlow) return;
278
+ const el = now - start;
279
+ const eo = easeOut(Math.min(1, el / outDur));
280
+ clearMirror.style.transform = `translateY(${(eo * outFly).toFixed(1)}px)`;
281
+ clearMirror.style.opacity = (1 - eo).toFixed(3);
282
+ clearMirror.style.filter = `blur(${(eo * blur).toFixed(1)}px)`;
283
+
284
+ const ei = easeIn(Math.min(1, el / inDur));
285
+ clearPhold.style.transform = `translateY(${(-inFly + ei * inFly).toFixed(1)}px)`;
286
+ clearPhold.style.opacity = (0.9 + ei * 0.1).toFixed(3);
287
+ clearPhold.style.filter = `blur(${(blur - ei * blur).toFixed(1)}px)`;
288
+
289
+ let g = 0;
290
+ if (el > delay) {
291
+ const gp = Math.min(1, (el - delay) / Math.max(1, total - delay));
292
+ g = gp < peakAt ? gp / peakAt : 1 - (gp - peakAt) / (1 - peakAt);
293
+ }
294
+ clearGlow.style.opacity = (g * gOp).toFixed(3);
295
+
296
+ if (el < total) {
297
+ requestAnimationFrame(tick);
298
+ } else {
299
+ clearWrap.classList.remove("is-clearing");
300
+ clearMirror.style.cssText = "";
301
+ clearPhold.style.cssText = "";
302
+ clearMirror.textContent = "";
303
+ clearGlow.style.opacity = "0";
304
+ clearGlow.style.background = "";
305
+ clearBusy = false;
306
+ }
307
+ };
308
+ requestAnimationFrame(tick);
309
+ }
310
+
311
+ function replaySkeleton() {
312
+ if (!skelEl || !skelSkeleton) return;
313
+ skelEl.classList.add("is-resetting");
314
+ skelEl.classList.remove("is-revealed");
315
+ skelSkeleton.classList.remove("is-pulsing");
316
+ void skelSkeleton.offsetWidth;
317
+ skelEl.classList.remove("is-resetting");
318
+ skelSkeleton.classList.add("is-pulsing");
319
+ const total = cssNum("--pulse-dur", 1000) * cssNum("--pulse-count", 1);
320
+ setTimeout(() => skelEl?.classList.add("is-revealed"), total);
321
+ }
322
+
323
+ function positionTabsPill(animate: boolean) {
324
+ if (!tabsBar || !tabsPill) return;
325
+ const tab = tabsBar.querySelectorAll(".t-tab")[activeTab];
326
+ if (!tab) return;
327
+ if (animate) {
328
+ tabsPill.style.transform = `translateX(${tab.offsetLeft}px)`;
329
+ tabsPill.style.width = `${tab.offsetWidth}px`;
330
+ } else {
331
+ const prev = tabsPill.style.transition;
332
+ tabsPill.style.transition = "none";
333
+ tabsPill.style.transform = `translateX(${tab.offsetLeft}px)`;
334
+ tabsPill.style.width = `${tab.offsetWidth}px`;
335
+ void tabsPill.offsetWidth;
336
+ tabsPill.style.transition = prev;
337
+ }
338
+ }
339
+
340
+ function selectTab(i: number) {
341
+ activeTab = i;
342
+ positionTabsPill(true);
343
+ }
344
+
345
+ function replayStagger() {
346
+ if (!staggerEl) return;
347
+ staggerEl.classList.remove("is-hiding");
348
+ staggerEl.classList.remove("is-shown");
349
+ void staggerEl.offsetHeight;
350
+ staggerEl.classList.add("is-shown");
351
+ }
352
+
353
+ // =========================
354
+ // THE NINE THE SECTION USED TO SKIP
355
+ // =========================
356
+ // Four are pure CSS. The rest carry the small JS each upstream usage note
357
+ // calls for; the markup follows `.upstream/transitions/<slug>.css`.
358
+ let accOpen = $state(true);
359
+ let morphOpen = $state(false);
360
+ let liked = $state(false);
361
+ let bursting = $state(false);
362
+
363
+ let tiltEl = null;
364
+ let tiltCard = null;
365
+ let reelEl = null;
366
+ let streamEl = null;
367
+ let reasonScroll = null;
368
+ let thinkEl = null;
369
+
370
+ const STREAM_TEXT =
371
+ "The parser reads the diff, keeps the hunks it can apply, and hands the rest back with a reason.";
372
+ const THINK_STATES = ["Thinking...", "Reading the repository...", "Drafting the patch..."];
373
+ const REASON_LINES = [
374
+ "Checking the lockfile for a version that moved.",
375
+ "Two primitives changed upstream since the last sync.",
376
+ "One of them is retuned here, so it stays ours.",
377
+ "Writing the other and formatting what landed.",
378
+ ];
379
+
380
+ function tiltMove(event: PointerEvent) {
381
+ const rect = tiltEl.getBoundingClientRect();
382
+ const x = (event.clientX - rect.left) / rect.width;
383
+ const y = (event.clientY - rect.top) / rect.height;
384
+ tiltCard.classList.add("is-tilting");
385
+ tiltEl.classList.add("is-hover");
386
+ tiltEl.style.setProperty("--tilt-rx", `${(0.5 - y) * 14}deg`);
387
+ tiltEl.style.setProperty("--tilt-ry", `${(x - 0.5) * 14}deg`);
388
+ tiltEl.style.setProperty("--tilt-gx", `${x * 100}%`);
389
+ tiltEl.style.setProperty("--tilt-gy", `${y * 100}%`);
390
+ }
391
+
392
+ function tiltLeave() {
393
+ tiltCard.classList.remove("is-tilting");
394
+ tiltEl.classList.remove("is-hover");
395
+ tiltEl.style.setProperty("--tilt-rx", "0deg");
396
+ tiltEl.style.setProperty("--tilt-ry", "0deg");
397
+ }
398
+
399
+ // A spray nobody can predict: every dot takes its own angle, distance and
400
+ // clock, which is what keeps two likes from looking like one animation.
401
+ function toggleLike(event: MouseEvent) {
402
+ liked = !liked;
403
+ if (!liked) return;
404
+ const root = event.currentTarget as HTMLElement;
405
+ for (const dot of root.querySelectorAll<HTMLElement>(".t-like-particles i")) {
406
+ const angle = Math.random() * Math.PI * 2;
407
+ const dist = 14 + Math.random() * 14;
408
+ dot.style.setProperty("--px", `${Math.cos(angle) * dist}px`);
409
+ dot.style.setProperty("--py", `${Math.sin(angle) * dist}px`);
410
+ dot.style.setProperty("--pdur", `${480 + Math.random() * 240}ms`);
411
+ dot.style.setProperty("--pdelay", `${Math.random() * 60}ms`);
412
+ dot.style.setProperty("--psize", `${0.7 + Math.random() * 0.8}`);
413
+ }
414
+ bursting = false;
415
+ void root.offsetHeight;
416
+ bursting = true;
417
+ setTimeout(() => (bursting = false), 700);
418
+ }
419
+
420
+ /** One column per digit, each clipping a 0-9 strip it spins past. */
421
+ function spinReel(value = "482") {
422
+ reelEl.replaceChildren();
423
+ value.split("").forEach((digit, index) => {
424
+ const col = document.createElement("div");
425
+ col.className = "t-reel-col";
426
+ const strip = document.createElement("div");
427
+ strip.className = "t-reel-strip";
428
+ for (let n = 0; n < 30; n++) {
429
+ const cell = document.createElement("div");
430
+ cell.className = "t-reel-digit";
431
+ cell.textContent = String(n % 10);
432
+ strip.append(cell);
433
+ }
434
+ col.append(strip);
435
+ reelEl.append(col);
436
+ const cells = 20 + Number(digit);
437
+ strip.style.transform = "translateY(0)";
438
+ strip.style.filter = "blur(0px)";
439
+ void strip.offsetHeight;
440
+ strip.style.transition = `transform var(--reel-dur) var(--reel-ease) ${index * 90}ms, filter var(--reel-dur) linear ${index * 90}ms`;
441
+ strip.style.transform = `translateY(calc(var(--reel-cell) * -${cells}))`;
442
+ });
443
+ }
444
+
445
+ /** Wrap each word once, then let them in one --stream-gap apart. */
446
+ function replayStream() {
447
+ const words = streamEl.querySelectorAll<HTMLElement>(".t-stream-w");
448
+ for (const word of words) {
449
+ word.style.transition = "none";
450
+ word.classList.remove("is-in");
451
+ }
452
+ void streamEl.offsetHeight;
453
+ words.forEach((word, index) => {
454
+ word.style.transition = "";
455
+ setTimeout(() => word.classList.add("is-in"), index * 60);
456
+ });
457
+ }
458
+
459
+ // The two that run on their own: a transcript stepping up while a model
460
+ // thinks, and the line under it swapping state.
461
+ $effect(() => {
462
+ if (!reasonScroll || !thinkEl) return;
463
+ replayStream();
464
+ spinReel();
465
+
466
+ let offset = 0;
467
+ const step = setInterval(() => {
468
+ offset = (offset + 2) % REASON_LINES.length;
469
+ reasonScroll.style.transition = "transform var(--reason-step) var(--reason-ease)";
470
+ reasonScroll.style.transform = `translateY(calc(var(--reason-line) * -${offset}))`;
471
+ }, 840);
472
+
473
+ let state = 0;
474
+ const swap = setInterval(() => {
475
+ state = (state + 1) % THINK_STATES.length;
476
+ thinkEl.classList.add("is-exit");
477
+ setTimeout(() => {
478
+ thinkEl.textContent = THINK_STATES[state];
479
+ thinkEl.dataset.text = THINK_STATES[state];
480
+ thinkEl.classList.remove("is-exit");
481
+ thinkEl.classList.add("is-enter-start");
482
+ void thinkEl.offsetHeight;
483
+ thinkEl.classList.remove("is-enter-start");
484
+ }, 200);
485
+ }, 2000);
486
+
487
+ return () => {
488
+ clearInterval(step);
489
+ clearInterval(swap);
490
+ };
491
+ });
492
+ </script>
493
+
494
+ <!-- ========================== -->
495
+ <!-- MARKUP -->
496
+ <!-- ========================== -->
497
+ <div class="grid">
498
+ <ShowcaseStage
499
+ title="Text states swap"
500
+ note="Text swap with translate and blur"
501
+ importPath={"import { swapText } from '@heyramzi/ui/animations/text-swap';"}
502
+ onaction={nextPhrase}
503
+ >
504
+ <span bind:this={target} class="phrase">{phrases[0]}</span>
505
+ </ShowcaseStage>
506
+
507
+ <ShowcaseStage
508
+ title="Number pop-in"
509
+ note="Digit flip with blur and stagger"
510
+ importPath={"import '@heyramzi/ui/animations/digit-pop-in.css';"}
511
+ onaction={replayDigits}
512
+ >
513
+ <span
514
+ bind:this={digitGroup}
515
+ class="t-digit-group digit-display"
516
+ class:is-animating={digitAnimating}
517
+ >
518
+ {#each digitValue.split("") as ch, i (i + ch)}
519
+ <span class="t-digit" data-stagger={i}>{ch}</span>
520
+ {/each}
521
+ </span>
522
+ </ShowcaseStage>
523
+
524
+ <ShowcaseStage
525
+ title="Card resize"
526
+ note="Smooth width and height transition"
527
+ importPath={"import '@heyramzi/ui/animations/resize.css';"}
528
+ onaction={() => (resizeSmall = !resizeSmall)}
529
+ >
530
+ <div class="t-resize sk-card" class:is-small={resizeSmall}>
531
+ <span class="sk sk-1"></span>
532
+ <span class="sk sk-2"></span>
533
+ <span class="sk sk-3"></span>
534
+ <span class="sk sk-4"></span>
535
+ <span class="sk sk-5"></span>
536
+ <span class="sk sk-6"></span>
537
+ </div>
538
+ </ShowcaseStage>
539
+
540
+ <ShowcaseStage
541
+ title="Notification badge"
542
+ note="Diagonal slide with spring pop-in"
543
+ importPath={"import '@heyramzi/ui/animations/notification-badge.css';"}
544
+ onaction={bumpBadge}
545
+ >
546
+ <button type="button" class="bell-trigger" onclick={bumpBadge} aria-label="Notifications">
547
+ <Bell class="size-5" />
548
+ <span class="t-badge" data-open={badgeOpen ? "true" : "false"}>
549
+ <span class="t-badge-dot">{badgeCount}</span>
550
+ </span>
551
+ </button>
552
+ </ShowcaseStage>
553
+
554
+ <ShowcaseStage
555
+ title="Modal open / close"
556
+ note="Scale and blur transition"
557
+ importPath={"import '@heyramzi/ui/animations/modal.css';"}
558
+ onaction={() => (modalOpen = !modalOpen)}
559
+ >
560
+ <div class="t-modal sk-modal" class:is-open={modalOpen}>
561
+ <div class="sk sk-mtitle"></div>
562
+ <div class="sk sk-mclose"></div>
563
+ <div class="sk sk-line full"></div>
564
+ <div class="sk sk-line full"></div>
565
+ <div class="sk sk-line three-q"></div>
566
+ <div class="sk-pills">
567
+ <div class="sk sk-pill"></div>
568
+ <div class="sk sk-pill"></div>
569
+ </div>
570
+ </div>
571
+ </ShowcaseStage>
572
+
573
+ <ShowcaseStage
574
+ title="Menu dropdown"
575
+ note="Origin-aware open and close"
576
+ importPath={"import '@heyramzi/ui/animations/dropdown.css';"}
577
+ onaction={() => (dropdownOpen = !dropdownOpen)}
578
+ >
579
+ <div class="dropdown-stack">
580
+ <div class="sk-trigger"></div>
581
+ <div class="t-dropdown sk-dropdown" class:is-open={dropdownOpen}>
582
+ <div class="sk sk-row full"></div>
583
+ <div class="sk sk-row three-q"></div>
584
+ <div class="sk sk-row half"></div>
585
+ </div>
586
+ </div>
587
+ </ShowcaseStage>
588
+
589
+ <ShowcaseStage
590
+ title="Panel reveal"
591
+ note="Translate and blur entrance"
592
+ importPath={"import '@heyramzi/ui/animations/panel.css';"}
593
+ onaction={() => (panelOpen = !panelOpen)}
594
+ >
595
+ <div class="panel-clip">
596
+ <div class="t-panel-slide sk-panel" data-open={panelOpen ? "true" : "false"}>
597
+ <div class="sk sk-line full"></div>
598
+ <div class="sk sk-line three-q"></div>
599
+ <div class="sk-tiles">
600
+ <div class="sk sk-tile"></div>
601
+ <div class="sk sk-tile"></div>
602
+ <div class="sk sk-tile"></div>
603
+ <div class="sk sk-tile"></div>
604
+ </div>
605
+ </div>
606
+ </div>
607
+ </ShowcaseStage>
608
+
609
+ <ShowcaseStage
610
+ title="Page side-by-side"
611
+ note="Forward and back page slide"
612
+ importPath={"import '@heyramzi/ui/animations/page-side-by-side.css';"}
613
+ actionLabel={activePage === "1" ? "Next" : "Back"}
614
+ onaction={togglePage}
615
+ >
616
+ <div class="t-page-slide sk-page-stage" data-page={activePage}>
617
+ <section class="t-page sk-page" data-page-id="1">
618
+ <div class="sk sk-row full"></div>
619
+ <div class="sk sk-row three-q"></div>
620
+ <div class="sk sk-row half"></div>
621
+ </section>
622
+ <section class="t-page sk-page sk-page-2" data-page-id="2">
623
+ <div class="sk-amount">$10</div>
624
+ <div class="sk-pill-row">
625
+ <div class="sk sk-mini-pill"></div>
626
+ <div class="sk sk-mini-pill"></div>
627
+ <div class="sk sk-mini-pill"></div>
628
+ </div>
629
+ </section>
630
+ </div>
631
+ </ShowcaseStage>
632
+
633
+ <ShowcaseStage
634
+ title="Icon swap"
635
+ note="Crossfade with blur between icons"
636
+ importPath={"import '@heyramzi/ui/animations/icon-swap.css';"}
637
+ onaction={() => (iconState = iconState === "a" ? "b" : "a")}
638
+ >
639
+ <div class="t-icon-swap icon-stack" data-state={iconState}>
640
+ <div class="t-icon" data-icon="a"><Menu class="size-7" /></div>
641
+ <div class="t-icon" data-icon="b"><X class="size-7" /></div>
642
+ </div>
643
+ </ShowcaseStage>
644
+
645
+ <ShowcaseStage
646
+ title="Success check"
647
+ note="Fade, rotate, bob, and stroke draw"
648
+ importPath={"import '@heyramzi/ui/animations/success-check.css';"}
649
+ onaction={replayCheck}
650
+ >
651
+ <div class="check-badge">
652
+ <span bind:this={checkEl} class="t-success-check" data-state="in" aria-hidden="true">
653
+ {@html successCheck}
654
+ </span>
655
+ </div>
656
+ </ShowcaseStage>
657
+
658
+ <ShowcaseStage
659
+ title="Avatar group hover"
660
+ note="Distance falloff lift with spring return"
661
+ importPath={"import '@heyramzi/ui/animations/avatar-group-hover.css';"}
662
+ >
663
+ <div
664
+ bind:this={avatarRoot}
665
+ class="t-avatar-group avatar-row"
666
+ role="group"
667
+ aria-label="Team"
668
+ onmouseleave={() => liftAvatars(null)}
669
+ >
670
+ {#each avatars as person, i (person.initials)}
671
+ <div
672
+ class="t-avatar avatar-chip"
673
+ style="z-index: {avatars.length -
674
+ i}; background: linear-gradient(145deg, hsl({person.hue} 52% 52%), hsl({person.hue} 56% 38%)); color: #fff;"
675
+ onmouseenter={() => liftAvatars(i)}
676
+ >
677
+ {person.initials}
678
+ </div>
679
+ {/each}
680
+ </div>
681
+ </ShowcaseStage>
682
+
683
+ <ShowcaseStage
684
+ title="Error state shake"
685
+ note="Percussive shake with auto-revert"
686
+ importPath={"import '@heyramzi/ui/animations/input-shake.css';"}
687
+ actionLabel="Submit"
688
+ onaction={showError}
689
+ >
690
+ <div bind:this={shakeWrap} class="t-input-wrap shake-wrap">
691
+ <div bind:this={shakeInput} class="t-input shake-input">name@email</div>
692
+ <p class="t-error-msg shake-msg">Enter a valid email address.</p>
693
+ </div>
694
+ </ShowcaseStage>
695
+
696
+ <ShowcaseStage
697
+ title="Input clear"
698
+ note="Fly-out text with per-word streak"
699
+ importPath={"import '@heyramzi/ui/animations/input-clear-dissolve.css';"}
700
+ actionLabel="Clear"
701
+ onaction={triggerClear}
702
+ >
703
+ <div bind:this={clearWrap} class="t-clear clear-field has-value">
704
+ <input
705
+ bind:this={clearInput}
706
+ class="clear-input"
707
+ type="text"
708
+ value={CLEAR_TEXT}
709
+ readonly
710
+ aria-label="Search"
711
+ />
712
+ <div bind:this={clearMirror} class="t-clear-mirror clear-text" aria-hidden="true">
713
+ {CLEAR_TEXT}
714
+ </div>
715
+ <div
716
+ bind:this={clearPhold}
717
+ class="t-clear-placeholder clear-text clear-ph"
718
+ aria-hidden="true"
719
+ >
720
+ Search
721
+ </div>
722
+ <div bind:this={clearGlow} class="t-clear-glow" aria-hidden="true"></div>
723
+ <button type="button" class="t-clear-btn clear-x" onclick={triggerClear} aria-label="Clear">
724
+ <X class="size-3.5" />
725
+ </button>
726
+ </div>
727
+ </ShowcaseStage>
728
+
729
+ <ShowcaseStage
730
+ title="Skeleton loader"
731
+ note="Pulse, then cross-blur to content"
732
+ importPath={"import '@heyramzi/ui/animations/skeleton-reveal.css';"}
733
+ actionLabel="Reload"
734
+ onaction={replaySkeleton}
735
+ >
736
+ <div bind:this={skelEl} class="t-skel skel-card is-revealed">
737
+ <div bind:this={skelSkeleton} class="t-skel-skeleton skel-layer">
738
+ <span class="sk skel-avatar"></span>
739
+ <span class="skel-bars">
740
+ <span class="sk skel-l1"></span>
741
+ <span class="sk skel-l2"></span>
742
+ </span>
743
+ </div>
744
+ <div class="t-skel-content skel-layer">
745
+ <div class="skel-avatar-real">R</div>
746
+ <div class="skel-lines">
747
+ <div class="skel-name">Ramzi K.</div>
748
+ <div class="skel-sub">Shipped 14 routes</div>
749
+ </div>
750
+ </div>
751
+ </div>
752
+ </ShowcaseStage>
753
+
754
+ <ShowcaseStage
755
+ title="Shimmer text"
756
+ note="Sweeping highlight on a loop"
757
+ importPath={"import '@heyramzi/ui/animations/shimmer-text.css';"}
758
+ >
759
+ <span class="t-shimmer shimmer-demo" data-text="Generating response">Generating response</span>
760
+ </ShowcaseStage>
761
+
762
+ <ShowcaseStage
763
+ title="Tabs sliding"
764
+ note="Active pill slides between options"
765
+ importPath={"import '@heyramzi/ui/animations/tabs-sliding.css';"}
766
+ >
767
+ <div bind:this={tabsBar} class="t-tabs tabs-demo" role="tablist" aria-label="View">
768
+ <span bind:this={tabsPill} class="t-tabs-pill" aria-hidden="true"></span>
769
+ {#each tabs as label, i (label)}
770
+ <button
771
+ type="button"
772
+ class="t-tab"
773
+ role="tab"
774
+ aria-selected={i === activeTab}
775
+ onclick={() => selectTab(i)}
776
+ >
777
+ {label}
778
+ </button>
779
+ {/each}
780
+ </div>
781
+ </ShowcaseStage>
782
+
783
+ <ShowcaseStage
784
+ title="Tooltip"
785
+ note="Delayed fade-in, instant out"
786
+ importPath={"import '@heyramzi/ui/animations/tooltip.css';"}
787
+ >
788
+ <span class="t-tt-wrap tt-demo">
789
+ <button type="button" class="t-tt-trigger tt-trigger" aria-describedby="tt-anim">
790
+ <Info class="size-5" />
791
+ </button>
792
+ <span class="t-tt tt-bubble" id="tt-anim" role="tooltip">Keyboard shortcuts</span>
793
+ </span>
794
+ </ShowcaseStage>
795
+
796
+ <ShowcaseStage
797
+ title="Texts reveal"
798
+ note="Staggered blurred rise"
799
+ importPath={"import '@heyramzi/ui/animations/texts-reveal.css';"}
800
+ actionLabel="Replay"
801
+ onaction={replayStagger}
802
+ >
803
+ <div bind:this={staggerEl} class="t-stagger stagger-demo is-shown">
804
+ <strong class="t-stagger-line t-stagger-line--1 stagger-head">Ship with rhythm</strong>
805
+ <span class="t-stagger-line t-stagger-line--2 stagger-sub"
806
+ >Headline first, the rest follows.</span
807
+ >
808
+ </div>
809
+ </ShowcaseStage>
810
+
811
+ <ShowcaseStage
812
+ title="Accordion"
813
+ note="Grid-row expand, no measured height"
814
+ importPath={"import '@heyramzi/ui/animations/accordion.css';"}
815
+ >
816
+ <div class="t-acc acc-demo" data-open={accOpen ? "true" : "false"}>
817
+ <button
818
+ type="button"
819
+ class="t-acc-head acc-head"
820
+ aria-expanded={accOpen}
821
+ onclick={() => (accOpen = !accOpen)}
822
+ >
823
+ Shipping details
824
+ <span class="t-acc-chevron">
825
+ {@html chevronDown}
826
+ </span>
827
+ </button>
828
+ <div class="t-acc-panel">
829
+ <div class="t-acc-panel-inner">
830
+ <p class="acc-body">
831
+ Standard delivery takes three to five days. Express arrives the next morning, tracked
832
+ end to end.
833
+ </p>
834
+ </div>
835
+ </div>
836
+ </div>
837
+ </ShowcaseStage>
838
+
839
+ <ShowcaseStage
840
+ title="Card tilt"
841
+ note="Pointer-tracked 3D tilt with a glare"
842
+ importPath={"import '@heyramzi/ui/animations/card-tilt.css';"}
843
+ >
844
+ <div bind:this={tiltEl} class="t-tilt" onpointermove={tiltMove} onpointerleave={tiltLeave}>
845
+ <div bind:this={tiltCard} class="t-tilt-card tilt-card">
846
+ <strong>Pro</strong>
847
+ <span class="tilt-price">39 EUR</span>
848
+ <span class="tilt-note">Move the pointer across the card.</span>
849
+ <div class="t-tilt-glare"></div>
850
+ </div>
851
+ </div>
852
+ </ShowcaseStage>
853
+
854
+ <ShowcaseStage
855
+ title="Learn more hover"
856
+ note="Chevron shifts, its arms open"
857
+ importPath={"import '@heyramzi/ui/animations/learn-more-hover.css';"}
858
+ >
859
+ <button type="button" class="t-learn learn-demo">
860
+ Learn more
861
+ <span class="t-learn-chevron">
862
+ {@html chevronArms}
863
+ </span>
864
+ </button>
865
+ </ShowcaseStage>
866
+
867
+ <ShowcaseStage
868
+ title="Like button"
869
+ note="Heart fills, particles spray"
870
+ importPath={"import '@heyramzi/ui/animations/like-button.css';"}
871
+ >
872
+ <button
873
+ type="button"
874
+ class="t-like like-demo"
875
+ class:is-bursting={bursting}
876
+ data-liked={liked ? "true" : "false"}
877
+ aria-pressed={liked}
878
+ onclick={toggleLike}
879
+ >
880
+ <span class="t-like-icon">
881
+ {@html heart}
882
+ </span>
883
+ <span class="t-like-particles" aria-hidden="true">
884
+ {#each { length: 8 } as _, i (i)}
885
+ <i></i>
886
+ {/each}
887
+ </span>
888
+ Like
889
+ </button>
890
+ </ShowcaseStage>
891
+
892
+ <ShowcaseStage
893
+ title="Plus menu morph"
894
+ note="The button becomes the surface"
895
+ importPath={"import '@heyramzi/ui/animations/plus-menu-morph.css';"}
896
+ >
897
+ <div class="morph-anchor">
898
+ <div class="t-morph morph-demo" data-open={morphOpen ? "true" : "false"}>
899
+ <div class="t-morph-menu morph-menu">
900
+ <span>Duplicate</span>
901
+ <span>Move to...</span>
902
+ <span>Archive</span>
903
+ </div>
904
+ <button
905
+ type="button"
906
+ class="t-morph-plus morph-plus"
907
+ aria-expanded={morphOpen}
908
+ aria-label={morphOpen ? "Close menu" : "Open menu"}
909
+ onclick={() => (morphOpen = !morphOpen)}
910
+ >
911
+ {@html plus}
912
+ </button>
913
+ </div>
914
+ </div>
915
+ </ShowcaseStage>
916
+
917
+ <ShowcaseStage
918
+ title="Spinning counter"
919
+ note="One reel per digit, staggered landing"
920
+ importPath={"import '@heyramzi/ui/animations/spinning-counter.css';"}
921
+ onaction={() => spinReel(String(100 + Math.floor(Math.random() * 900)))}
922
+ >
923
+ <div bind:this={reelEl} class="t-reel reel-demo"></div>
924
+ </ShowcaseStage>
925
+
926
+ <ShowcaseStage
927
+ title="Streaming text"
928
+ note="Word by word, opacity and blur"
929
+ importPath={"import '@heyramzi/ui/animations/streaming-text.css';"}
930
+ onaction={replayStream}
931
+ >
932
+ <p bind:this={streamEl} class="stream-demo">
933
+ {#each STREAM_TEXT.split(" ") as word, i (i)}
934
+ <span class="t-stream-w">{word}&nbsp;</span>
935
+ {/each}
936
+ </p>
937
+ </ShowcaseStage>
938
+
939
+ <ShowcaseStage
940
+ title="Reasoning stream"
941
+ note="A transcript stepping under a mask"
942
+ importPath={"import '@heyramzi/ui/animations/reasoning-stream.css';"}
943
+ >
944
+ <div class="t-reason reason-demo">
945
+ <div class="t-reason-viewport">
946
+ <div bind:this={reasonScroll} class="t-reason-scroll">
947
+ {#each [...REASON_LINES, ...REASON_LINES] as line, i (i)}
948
+ <p class="reason-line">{line}</p>
949
+ {/each}
950
+ </div>
951
+ </div>
952
+ </div>
953
+ </ShowcaseStage>
954
+
955
+ <ShowcaseStage
956
+ title="Thinking states"
957
+ note="Shimmering line, swapped on a hold"
958
+ importPath={"import '@heyramzi/ui/animations/thinking-states.css';"}
959
+ >
960
+ <span class="t-think think-demo" role="status">
961
+ <span class="t-think-sizer" aria-hidden="true">Reading the repository...</span>
962
+ <span bind:this={thinkEl} class="t-think-text" data-text="Thinking...">Thinking...</span>
963
+ </span>
964
+ </ShowcaseStage>
965
+ </div>
966
+
967
+ <!-- ========================== -->
968
+ <!-- STYLE -->
969
+ <!-- ========================== -->
970
+ <style>
971
+ /* One demo per row, the rule ShowcaseSection states for `.sc-stack`. An
972
+ animation is read by watching it run, and a third-width stage clips it. */
973
+ .grid {
974
+ display: grid;
975
+ grid-template-columns: minmax(0, 1fr);
976
+ gap: 1rem;
977
+
978
+ /* transitions.dev demo material mapped onto host tokens. Nothing defined
979
+ the names, so eleven of eighteen drew transparent until 10 Sep 2026.
980
+ Every value reads the app palette. */
981
+ --td-material-bg: var(--color-card, var(--card));
982
+ --td-material-shadow:
983
+ 0 0 0 1px color-mix(in oklab, var(--color-border, var(--border)) 80%, transparent),
984
+ 0 6px 18px -8px
985
+ color-mix(in oklab, var(--color-foreground, var(--foreground)) 22%, transparent);
986
+ --td-skeleton: color-mix(
987
+ in oklab,
988
+ var(--color-muted-foreground, var(--muted-foreground)) 22%,
989
+ transparent
990
+ );
991
+ --td-stage-bg: var(--color-background, var(--background));
992
+ --td-text: var(--color-foreground, var(--foreground));
993
+ --td-text-subtle: var(--color-muted-foreground, var(--muted-foreground));
994
+ --td-icon-color: var(--color-foreground, var(--foreground));
995
+ --td-icon-color-muted: var(--color-muted-foreground, var(--muted-foreground));
996
+ --td-copy-bg: color-mix(in oklab, var(--color-muted, var(--muted)) 80%, transparent);
997
+ --td-copy-bg-hover: var(--color-muted, var(--muted));
998
+ }
999
+
1000
+ .sk {
1001
+ background: var(--td-skeleton);
1002
+ border-radius: 4px;
1003
+ }
1004
+
1005
+ .phrase {
1006
+ font-size: 1.0625rem;
1007
+ font-weight: 500;
1008
+ color: var(--td-text, var(--foreground));
1009
+ --text-swap-dur: 240ms;
1010
+ }
1011
+
1012
+ .digit-display {
1013
+ font-size: 2.25rem;
1014
+ font-weight: 600;
1015
+ font-family: ui-monospace, SFMono-Regular, monospace;
1016
+ color: var(--td-text, var(--foreground));
1017
+ font-feature-settings: "tnum";
1018
+ letter-spacing: -0.02em;
1019
+ }
1020
+
1021
+ .sk-card {
1022
+ position: relative;
1023
+ width: 12.5rem;
1024
+ height: 8.75rem;
1025
+ background: var(--td-material-bg);
1026
+ box-shadow: var(--td-material-shadow);
1027
+ border-radius: 12px;
1028
+ /* WHY: clip the skeleton lines so they don't spill past the card edge as it shrinks */
1029
+ overflow: hidden;
1030
+ }
1031
+ .sk-card.is-small {
1032
+ width: 9rem;
1033
+ height: 6rem;
1034
+ }
1035
+ .sk-card .sk {
1036
+ position: absolute;
1037
+ left: 14px;
1038
+ right: 14px;
1039
+ }
1040
+ .sk-card .sk-1 {
1041
+ top: 16px;
1042
+ height: 10px;
1043
+ right: auto;
1044
+ width: 56%;
1045
+ }
1046
+ .sk-card .sk-2 {
1047
+ top: 32px;
1048
+ height: 6px;
1049
+ }
1050
+ .sk-card .sk-3 {
1051
+ top: 44px;
1052
+ height: 6px;
1053
+ }
1054
+ .sk-card .sk-4 {
1055
+ top: 56px;
1056
+ height: 6px;
1057
+ right: auto;
1058
+ width: 70%;
1059
+ }
1060
+ .sk-card .sk-5 {
1061
+ top: 84px;
1062
+ height: 6px;
1063
+ }
1064
+ .sk-card .sk-6 {
1065
+ top: 96px;
1066
+ height: 6px;
1067
+ }
1068
+
1069
+ .bell-trigger {
1070
+ position: relative;
1071
+ display: inline-flex;
1072
+ align-items: center;
1073
+ justify-content: center;
1074
+ width: 3rem;
1075
+ height: 3rem;
1076
+ border-radius: 12px;
1077
+ border: 0;
1078
+ background: var(--td-material-bg);
1079
+ box-shadow: var(--td-material-shadow);
1080
+ color: var(--td-icon-color, var(--foreground));
1081
+ cursor: pointer;
1082
+ }
1083
+ .bell-trigger:hover {
1084
+ filter: brightness(1.05);
1085
+ }
1086
+ :global(.bell-trigger .t-badge-dot) {
1087
+ display: inline-flex;
1088
+ align-items: center;
1089
+ justify-content: center;
1090
+ min-width: 1.125rem;
1091
+ height: 1.125rem;
1092
+ padding: 0 0.3125rem;
1093
+ font-size: 0.6875rem;
1094
+ font-weight: 600;
1095
+ color: var(--primary-foreground);
1096
+ background: var(--primary);
1097
+ border-radius: 999px;
1098
+ line-height: 1;
1099
+ }
1100
+
1101
+ .sk-modal {
1102
+ position: relative;
1103
+ width: 16rem;
1104
+ height: 10rem;
1105
+ background: var(--td-material-bg);
1106
+ box-shadow: var(--td-material-shadow);
1107
+ border: 0;
1108
+ border-radius: 12px;
1109
+ padding: 1rem;
1110
+ display: flex;
1111
+ flex-direction: column;
1112
+ gap: 0.4375rem;
1113
+ }
1114
+ .sk-modal .sk-mtitle {
1115
+ width: 60%;
1116
+ height: 12px;
1117
+ }
1118
+ .sk-modal .sk-mclose {
1119
+ position: absolute;
1120
+ top: 0.875rem;
1121
+ right: 0.875rem;
1122
+ width: 14px;
1123
+ height: 14px;
1124
+ border-radius: 50%;
1125
+ }
1126
+ .sk-modal .sk-line {
1127
+ height: 8px;
1128
+ }
1129
+ .sk-modal .sk-line.full {
1130
+ width: 100%;
1131
+ }
1132
+ .sk-modal .sk-line.three-q {
1133
+ width: 75%;
1134
+ }
1135
+ .sk-modal .sk-pills {
1136
+ margin-top: auto;
1137
+ display: flex;
1138
+ gap: 0.5rem;
1139
+ }
1140
+ .sk-modal .sk-pill {
1141
+ width: 4.25rem;
1142
+ height: 1.375rem;
1143
+ border-radius: 999px;
1144
+ }
1145
+
1146
+ .dropdown-stack {
1147
+ position: relative;
1148
+ display: flex;
1149
+ flex-direction: column;
1150
+ align-items: center;
1151
+ gap: 0.5rem;
1152
+ }
1153
+ .sk-trigger {
1154
+ width: 7rem;
1155
+ height: 2rem;
1156
+ background: var(--td-material-bg);
1157
+ box-shadow: var(--td-material-shadow);
1158
+ border-radius: 8px;
1159
+ }
1160
+ .sk-dropdown {
1161
+ width: 11rem;
1162
+ padding: 0.625rem;
1163
+ background: var(--td-material-bg);
1164
+ box-shadow: var(--td-material-shadow);
1165
+ border: 0;
1166
+ border-radius: 10px;
1167
+ display: flex;
1168
+ flex-direction: column;
1169
+ gap: 0.4375rem;
1170
+ }
1171
+ .sk-dropdown .sk-row {
1172
+ height: 9px;
1173
+ }
1174
+ .sk-dropdown .sk-row.full {
1175
+ width: 100%;
1176
+ }
1177
+ .sk-dropdown .sk-row.three-q {
1178
+ width: 75%;
1179
+ }
1180
+ .sk-dropdown .sk-row.half {
1181
+ width: 50%;
1182
+ }
1183
+
1184
+ .panel-clip {
1185
+ width: 100%;
1186
+ max-width: 16rem;
1187
+ height: 9rem;
1188
+ overflow: hidden;
1189
+ border-radius: 12px;
1190
+ background: var(--td-material-bg);
1191
+ box-shadow: var(--td-material-shadow);
1192
+ }
1193
+ .sk-panel {
1194
+ padding: 0.875rem;
1195
+ display: flex;
1196
+ flex-direction: column;
1197
+ gap: 0.625rem;
1198
+ }
1199
+ .sk-panel .sk-line {
1200
+ height: 9px;
1201
+ }
1202
+ .sk-panel .sk-line.full {
1203
+ width: 100%;
1204
+ }
1205
+ .sk-panel .sk-line.three-q {
1206
+ width: 75%;
1207
+ }
1208
+ .sk-panel .sk-tiles {
1209
+ display: grid;
1210
+ grid-template-columns: repeat(2, 1fr);
1211
+ gap: 0.5rem;
1212
+ margin-top: 0.25rem;
1213
+ }
1214
+ .sk-panel .sk-tile {
1215
+ height: 2.25rem;
1216
+ }
1217
+
1218
+ .sk-page-stage {
1219
+ position: relative;
1220
+ width: 16rem;
1221
+ height: 10rem;
1222
+ background: var(--td-material-bg);
1223
+ box-shadow: var(--td-material-shadow);
1224
+ border-radius: 12px;
1225
+ overflow: hidden;
1226
+ }
1227
+ .sk-page {
1228
+ padding: 1rem;
1229
+ display: flex;
1230
+ flex-direction: column;
1231
+ gap: 0.5rem;
1232
+ }
1233
+ .sk-page .sk-row {
1234
+ height: 10px;
1235
+ }
1236
+ .sk-page .sk-row.full {
1237
+ width: 100%;
1238
+ }
1239
+ .sk-page .sk-row.three-q {
1240
+ width: 75%;
1241
+ }
1242
+ .sk-page .sk-row.half {
1243
+ width: 50%;
1244
+ }
1245
+ .sk-page-2 {
1246
+ align-items: center;
1247
+ justify-content: center;
1248
+ gap: 0.625rem;
1249
+ }
1250
+ .sk-amount {
1251
+ font-size: 2rem;
1252
+ font-weight: 600;
1253
+ color: var(--td-text, var(--foreground));
1254
+ font-family: ui-monospace, SFMono-Regular, monospace;
1255
+ }
1256
+ .sk-pill-row {
1257
+ display: flex;
1258
+ gap: 0.375rem;
1259
+ }
1260
+ .sk-mini-pill {
1261
+ width: 2.5rem;
1262
+ height: 1.25rem;
1263
+ border-radius: 999px;
1264
+ }
1265
+
1266
+ .icon-stack {
1267
+ display: inline-grid;
1268
+ place-items: center;
1269
+ width: 3.5rem;
1270
+ height: 3.5rem;
1271
+ border-radius: 12px;
1272
+ background: var(--td-material-bg);
1273
+ box-shadow: var(--td-material-shadow);
1274
+ color: var(--td-icon-color, var(--foreground));
1275
+ --icon-swap-dur: 220ms;
1276
+ }
1277
+ .icon-stack :global(.t-icon) {
1278
+ display: inline-flex;
1279
+ align-items: center;
1280
+ justify-content: center;
1281
+ }
1282
+
1283
+ .check-badge {
1284
+ display: inline-flex;
1285
+ align-items: center;
1286
+ justify-content: center;
1287
+ width: 4rem;
1288
+ height: 4rem;
1289
+ border-radius: 50%;
1290
+ background: oklch(0.66 0.16 155);
1291
+ color: #fff;
1292
+ }
1293
+ .check-badge :global(.t-success-check svg) {
1294
+ width: 2.25rem;
1295
+ height: 2.25rem;
1296
+ }
1297
+
1298
+ .avatar-row {
1299
+ display: inline-flex;
1300
+ }
1301
+ .avatar-chip {
1302
+ display: inline-flex;
1303
+ align-items: center;
1304
+ justify-content: center;
1305
+ width: 2.75rem;
1306
+ height: 2.75rem;
1307
+ margin-left: -0.625rem;
1308
+ border-radius: 50%;
1309
+ background: var(--td-material-bg);
1310
+ box-shadow: var(--td-material-shadow);
1311
+ border: 2px solid var(--td-stage-bg);
1312
+ color: var(--td-text);
1313
+ font-size: 0.875rem;
1314
+ font-weight: 600;
1315
+ cursor: default;
1316
+ }
1317
+ .avatar-chip:first-child {
1318
+ margin-left: 0;
1319
+ }
1320
+
1321
+ .shake-wrap {
1322
+ display: flex;
1323
+ flex-direction: column;
1324
+ gap: 0.5rem;
1325
+ width: 13rem;
1326
+ }
1327
+ .shake-input {
1328
+ display: flex;
1329
+ align-items: center;
1330
+ height: 2.5rem;
1331
+ padding: 0 0.75rem;
1332
+ border: 1.5px solid var(--border);
1333
+ border-radius: 8px;
1334
+ background: var(--td-material-bg);
1335
+ color: var(--td-text-subtle);
1336
+ font-size: 0.875rem;
1337
+ }
1338
+ .shake-input.is-error {
1339
+ border-color: var(--destructive);
1340
+ }
1341
+ .shake-msg {
1342
+ margin: 0;
1343
+ font-size: 0.75rem;
1344
+ color: var(--destructive);
1345
+ }
1346
+
1347
+ .clear-field {
1348
+ width: 14rem;
1349
+ height: 2.75rem;
1350
+ border-radius: 10px;
1351
+ background: var(--td-material-bg);
1352
+ box-shadow: var(--td-material-shadow);
1353
+ }
1354
+ .clear-input {
1355
+ width: 100%;
1356
+ height: 100%;
1357
+ padding: 0 2.25rem 0 0.75rem;
1358
+ border: 0;
1359
+ background: transparent;
1360
+ outline: none;
1361
+ font: inherit;
1362
+ font-size: 0.9375rem;
1363
+ color: var(--td-text);
1364
+ }
1365
+ .clear-text {
1366
+ padding-left: 0.75rem;
1367
+ font-size: 0.9375rem;
1368
+ color: var(--td-text);
1369
+ }
1370
+ .clear-ph {
1371
+ color: var(--td-text-subtle);
1372
+ }
1373
+ .clear-x {
1374
+ position: absolute;
1375
+ top: 50%;
1376
+ right: 0.5rem;
1377
+ transform: translateY(-50%);
1378
+ z-index: 4;
1379
+ display: inline-flex;
1380
+ align-items: center;
1381
+ justify-content: center;
1382
+ width: 1.5rem;
1383
+ height: 1.5rem;
1384
+ border: 0;
1385
+ border-radius: 50%;
1386
+ background: var(--td-copy-bg);
1387
+ color: var(--td-icon-color-muted);
1388
+ cursor: pointer;
1389
+ }
1390
+ .clear-x:hover {
1391
+ background: var(--td-copy-bg-hover);
1392
+ color: var(--td-icon-color);
1393
+ }
1394
+
1395
+ .skel-card {
1396
+ width: 14rem;
1397
+ height: 4.5rem;
1398
+ background: var(--td-material-bg);
1399
+ box-shadow: var(--td-material-shadow);
1400
+ border-radius: 12px;
1401
+ }
1402
+ .skel-layer {
1403
+ display: flex;
1404
+ align-items: center;
1405
+ gap: 0.75rem;
1406
+ padding: 0 1rem;
1407
+ }
1408
+ .skel-avatar {
1409
+ flex: none;
1410
+ width: 2.5rem;
1411
+ height: 2.5rem;
1412
+ border-radius: 50%;
1413
+ }
1414
+ .skel-bars {
1415
+ display: flex;
1416
+ flex-direction: column;
1417
+ gap: 0.5rem;
1418
+ }
1419
+ .skel-l1 {
1420
+ width: 6rem;
1421
+ height: 9px;
1422
+ }
1423
+ .skel-l2 {
1424
+ width: 4rem;
1425
+ height: 9px;
1426
+ }
1427
+ .skel-avatar-real {
1428
+ flex: none;
1429
+ display: inline-flex;
1430
+ align-items: center;
1431
+ justify-content: center;
1432
+ width: 2.5rem;
1433
+ height: 2.5rem;
1434
+ border-radius: 50%;
1435
+ background: var(--primary);
1436
+ color: var(--primary-foreground);
1437
+ font-size: 0.875rem;
1438
+ font-weight: 600;
1439
+ }
1440
+ .skel-lines {
1441
+ display: flex;
1442
+ flex-direction: column;
1443
+ gap: 0.125rem;
1444
+ }
1445
+ .skel-name {
1446
+ font-size: 0.875rem;
1447
+ font-weight: 600;
1448
+ color: var(--td-text);
1449
+ }
1450
+ .skel-sub {
1451
+ font-size: 0.75rem;
1452
+ color: var(--td-text-subtle);
1453
+ }
1454
+
1455
+ .shimmer-demo {
1456
+ font-size: 1.125rem;
1457
+ font-weight: 500;
1458
+ --shimmer-base: var(--td-text-subtle);
1459
+ --shimmer-highlight: var(--td-text);
1460
+ }
1461
+
1462
+ .tabs-demo {
1463
+ font-size: 0.8125rem;
1464
+ font-weight: 500;
1465
+ --tabs-bar-bg: color-mix(in srgb, var(--td-text) 8%, transparent);
1466
+ --tabs-pill-bg: var(--td-material-bg);
1467
+ --tabs-text-muted: var(--td-text-subtle);
1468
+ --tabs-text-active: var(--td-text);
1469
+ }
1470
+ .tabs-demo :global(.t-tabs-pill) {
1471
+ box-shadow: var(--td-material-shadow);
1472
+ }
1473
+
1474
+ .tt-trigger {
1475
+ display: inline-flex;
1476
+ align-items: center;
1477
+ justify-content: center;
1478
+ width: 2.75rem;
1479
+ height: 2.75rem;
1480
+ border: 0;
1481
+ border-radius: 10px;
1482
+ background: var(--td-material-bg);
1483
+ box-shadow: var(--td-material-shadow);
1484
+ color: var(--td-icon-color);
1485
+ cursor: pointer;
1486
+ }
1487
+ .tt-bubble {
1488
+ font-size: 0.8125rem;
1489
+ font-weight: 500;
1490
+ --tt-bg: var(--td-material-bg);
1491
+ --tt-fg: var(--td-text);
1492
+ }
1493
+
1494
+ .stagger-demo {
1495
+ display: flex;
1496
+ flex-direction: column;
1497
+ gap: 0.375rem;
1498
+ max-width: 14rem;
1499
+ text-align: center;
1500
+ }
1501
+ .stagger-head {
1502
+ font-size: 1.25rem;
1503
+ font-weight: 600;
1504
+ color: var(--td-text);
1505
+ letter-spacing: -0.01em;
1506
+ }
1507
+ .stagger-sub {
1508
+ font-size: 0.875rem;
1509
+ color: var(--td-text-subtle);
1510
+ }
1511
+ /* ---- the nine added 14 Sep 2026 ---- */
1512
+ .acc-demo {
1513
+ width: min(24rem, 100%);
1514
+ background: var(--td-material-bg);
1515
+ box-shadow: var(--td-material-shadow);
1516
+ border-radius: 10px;
1517
+ }
1518
+
1519
+ .acc-head {
1520
+ display: flex;
1521
+ align-items: center;
1522
+ justify-content: space-between;
1523
+ gap: 1rem;
1524
+ width: 100%;
1525
+ padding: 0.75rem 0.875rem;
1526
+ font-size: 0.875rem;
1527
+ font-weight: 500;
1528
+ color: var(--td-text);
1529
+ background: none;
1530
+ border: 0;
1531
+ cursor: pointer;
1532
+ }
1533
+
1534
+ .acc-body {
1535
+ margin: 0;
1536
+ padding: 0 0.875rem 0.875rem;
1537
+ font-size: 0.8125rem;
1538
+ line-height: 1.55;
1539
+ color: var(--td-text-subtle);
1540
+ }
1541
+
1542
+ .tilt-card {
1543
+ display: flex;
1544
+ flex-direction: column;
1545
+ gap: 0.25rem;
1546
+ width: 13rem;
1547
+ padding: 1.125rem;
1548
+ background: var(--td-material-bg);
1549
+ box-shadow: var(--td-material-shadow);
1550
+ color: var(--td-text);
1551
+ font-size: 0.8125rem;
1552
+ }
1553
+
1554
+ .tilt-price {
1555
+ font-size: 1.5rem;
1556
+ font-weight: 600;
1557
+ letter-spacing: -0.02em;
1558
+ }
1559
+
1560
+ .tilt-note {
1561
+ color: var(--td-text-subtle);
1562
+ }
1563
+
1564
+ .learn-demo,
1565
+ .like-demo {
1566
+ display: inline-flex;
1567
+ align-items: center;
1568
+ gap: 0.4375rem;
1569
+ padding: 0.5rem 0.875rem;
1570
+ font-size: 0.875rem;
1571
+ font-weight: 500;
1572
+ color: var(--td-text);
1573
+ background: var(--td-copy-bg);
1574
+ border: 0;
1575
+ border-radius: 8px;
1576
+ cursor: pointer;
1577
+ }
1578
+
1579
+ .like-demo {
1580
+ position: relative;
1581
+ }
1582
+
1583
+ /* The anchor is sized to the open footprint, the way the usage note asks:
1584
+ without it the morph grows the stage and every demo under it jumps. */
1585
+ .morph-anchor {
1586
+ position: relative;
1587
+ width: 11rem;
1588
+ height: 7.5rem;
1589
+ }
1590
+
1591
+ .morph-demo {
1592
+ position: absolute;
1593
+ inset-block-start: 0;
1594
+ inset-inline-start: 0;
1595
+ background: var(--td-material-bg);
1596
+ box-shadow: var(--td-material-shadow);
1597
+ }
1598
+
1599
+ .morph-menu {
1600
+ display: flex;
1601
+ flex-direction: column;
1602
+ gap: 0.5rem;
1603
+ padding: 0.75rem 0.875rem;
1604
+ font-size: 0.8125rem;
1605
+ color: var(--td-text);
1606
+ }
1607
+
1608
+ .morph-plus {
1609
+ display: inline-flex;
1610
+ align-items: center;
1611
+ justify-content: center;
1612
+ color: var(--td-text);
1613
+ background: none;
1614
+ border: 0;
1615
+ cursor: pointer;
1616
+ }
1617
+
1618
+ .reel-demo {
1619
+ font-size: 2rem;
1620
+ font-weight: 600;
1621
+ font-family: ui-monospace, SFMono-Regular, monospace;
1622
+ color: var(--td-text);
1623
+ }
1624
+
1625
+ .stream-demo {
1626
+ margin: 0;
1627
+ max-width: 32rem;
1628
+ font-size: 0.9375rem;
1629
+ line-height: 1.6;
1630
+ color: var(--td-text);
1631
+ }
1632
+
1633
+ .reason-demo {
1634
+ width: min(26rem, 100%);
1635
+ height: 7rem;
1636
+ padding: 0.875rem 1rem;
1637
+ background: var(--td-material-bg);
1638
+ box-shadow: var(--td-material-shadow);
1639
+ border-radius: 10px;
1640
+ --reason-line: 1.5rem;
1641
+ }
1642
+
1643
+ .reason-line {
1644
+ margin: 0;
1645
+ height: 1.5rem;
1646
+ font-size: 0.8125rem;
1647
+ line-height: 1.5rem;
1648
+ color: var(--td-text-subtle);
1649
+ white-space: nowrap;
1650
+ overflow: hidden;
1651
+ text-overflow: ellipsis;
1652
+ }
1653
+
1654
+ .think-demo {
1655
+ font-size: 0.9375rem;
1656
+ color: var(--td-text-subtle);
1657
+ }
1658
+ </style>