@joewinke/jatui 0.1.31 → 0.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 (239) hide show
  1. package/CLAUDE.md +22 -0
  2. package/dist/actions/attention.d.ts +24 -0
  3. package/dist/actions/attention.js +94 -0
  4. package/dist/actions/collapse.js +29 -15
  5. package/dist/actions/floating.d.ts +53 -0
  6. package/dist/actions/floating.js +158 -0
  7. package/dist/actions/listNav.js +137 -108
  8. package/dist/actions/railNav.js +89 -72
  9. package/dist/actions/staggerEntrance.d.ts +28 -0
  10. package/dist/actions/staggerEntrance.js +71 -0
  11. package/dist/actions/tooltip.d.ts +28 -0
  12. package/dist/actions/tooltip.js +186 -0
  13. package/dist/assets/sounds/README.md +47 -0
  14. package/dist/assets/sounds/error.d.ts +1 -0
  15. package/dist/assets/sounds/error.js +4 -0
  16. package/dist/assets/sounds/notify.d.ts +1 -0
  17. package/dist/assets/sounds/notify.js +4 -0
  18. package/dist/assets/sounds/pop.d.ts +1 -0
  19. package/dist/assets/sounds/pop.js +4 -0
  20. package/dist/assets/sounds/send.d.ts +1 -0
  21. package/dist/assets/sounds/send.js +4 -0
  22. package/dist/assets/sounds/success.d.ts +1 -0
  23. package/dist/assets/sounds/success.js +4 -0
  24. package/dist/assets/sounds/toggle.d.ts +1 -0
  25. package/dist/assets/sounds/toggle.js +4 -0
  26. package/dist/components/AnimatedNumber.svelte +112 -0
  27. package/dist/components/AnimatedNumber.svelte.d.ts +8 -0
  28. package/dist/components/Badge.svelte +75 -4
  29. package/dist/components/Badge.svelte.d.ts +6 -1
  30. package/dist/components/Button.svelte +196 -21
  31. package/dist/components/Button.svelte.d.ts +10 -1
  32. package/dist/components/Carousel.svelte +265 -0
  33. package/dist/components/Carousel.svelte.d.ts +21 -0
  34. package/dist/components/ChipInput.svelte +63 -3
  35. package/dist/components/Collapse.svelte +70 -14
  36. package/dist/components/Collapse.svelte.d.ts +11 -0
  37. package/dist/components/ColorSelector.svelte +21 -24
  38. package/dist/components/CommandPalette.svelte +475 -0
  39. package/dist/components/CommandPalette.svelte.d.ts +3 -0
  40. package/dist/components/ContextMenu.svelte +9 -73
  41. package/dist/components/CopyButton.svelte +156 -0
  42. package/dist/components/CopyButton.svelte.d.ts +12 -0
  43. package/dist/components/HoldToConfirm.svelte +183 -0
  44. package/dist/components/HoldToConfirm.svelte.d.ts +11 -0
  45. package/dist/components/KeyboardShortcutsOverlay.svelte +54 -8
  46. package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +3 -0
  47. package/dist/components/PasswordMeter.svelte +87 -0
  48. package/dist/components/PasswordMeter.svelte.d.ts +8 -0
  49. package/dist/components/PinInput.svelte +186 -0
  50. package/dist/components/PinInput.svelte.d.ts +13 -0
  51. package/dist/components/QuantityStepper.svelte +185 -0
  52. package/dist/components/QuantityStepper.svelte.d.ts +12 -0
  53. package/dist/components/Skeleton.svelte +123 -0
  54. package/dist/components/Skeleton.svelte.d.ts +12 -0
  55. package/dist/components/SpeechForm.svelte +37 -0
  56. package/dist/components/StatusBadge.svelte +31 -3
  57. package/dist/components/StatusBadge.svelte.d.ts +0 -5
  58. package/dist/components/Tabs.svelte +270 -0
  59. package/dist/components/Tabs.svelte.d.ts +15 -0
  60. package/dist/components/TextInput.svelte +138 -38
  61. package/dist/components/TextInput.svelte.d.ts +9 -1
  62. package/dist/components/VoicePlayer.svelte +51 -0
  63. package/dist/components/basic/Alert.svelte +36 -0
  64. package/dist/components/basic/Alert.svelte.d.ts +9 -0
  65. package/dist/components/basic/Breadcrumb.svelte +27 -0
  66. package/dist/components/basic/Breadcrumb.svelte.d.ts +11 -0
  67. package/dist/components/basic/ButtonGroup.svelte +15 -0
  68. package/dist/components/basic/ButtonGroup.svelte.d.ts +8 -0
  69. package/dist/components/basic/Checkbox.svelte +85 -0
  70. package/dist/components/basic/Checkbox.svelte.d.ts +15 -0
  71. package/dist/components/basic/Empty.svelte +17 -0
  72. package/dist/components/basic/Empty.svelte.d.ts +8 -0
  73. package/dist/components/basic/Kbd.svelte +16 -0
  74. package/dist/components/basic/Kbd.svelte.d.ts +8 -0
  75. package/dist/components/basic/Pagination.svelte +104 -0
  76. package/dist/components/basic/Pagination.svelte.d.ts +12 -0
  77. package/dist/components/basic/RadioGroup.svelte +71 -0
  78. package/dist/components/basic/RadioGroup.svelte.d.ts +18 -0
  79. package/dist/components/basic/Separator.svelte +19 -0
  80. package/dist/components/basic/Separator.svelte.d.ts +8 -0
  81. package/dist/components/basic/Slider.svelte +72 -0
  82. package/dist/components/basic/Slider.svelte.d.ts +17 -0
  83. package/dist/components/basic/Switch.svelte +88 -0
  84. package/dist/components/basic/Switch.svelte.d.ts +14 -0
  85. package/dist/components/basic/Toggle.svelte +43 -0
  86. package/dist/components/basic/Toggle.svelte.d.ts +14 -0
  87. package/dist/components/graph/GraphCanvas.svelte +103 -0
  88. package/dist/components/graph/GraphCanvas.svelte.d.ts +22 -0
  89. package/dist/components/graph/JatuiNode.svelte +128 -0
  90. package/dist/components/graph/JatuiNode.svelte.d.ts +14 -0
  91. package/dist/components/graph/theme.d.ts +27 -0
  92. package/dist/components/graph/theme.js +136 -0
  93. package/dist/components/markup.js +62 -59
  94. package/dist/components/messaging/MessageItem.svelte +92 -0
  95. package/dist/components/messaging/MessageItem.svelte.d.ts +5 -0
  96. package/dist/components/messaging/TypingIndicator.svelte +63 -0
  97. package/dist/components/messaging/TypingIndicator.svelte.d.ts +7 -0
  98. package/dist/components/pipeline/PipelineColumn.svelte +44 -3
  99. package/dist/components/progress/ProgressBar.svelte +189 -0
  100. package/dist/components/progress/ProgressBar.svelte.d.ts +17 -0
  101. package/dist/components/progress/ProgressRing.svelte +138 -0
  102. package/dist/components/progress/ProgressRing.svelte.d.ts +12 -0
  103. package/dist/components/progress/Steps.svelte +195 -0
  104. package/dist/components/progress/Steps.svelte.d.ts +14 -0
  105. package/dist/components/session-nav/transcriptModel.js +66 -49
  106. package/dist/components/shell/NavigationMenu.svelte +422 -0
  107. package/dist/components/shell/NavigationMenu.svelte.d.ts +43 -0
  108. package/dist/components/shell/Sidebar.svelte +276 -0
  109. package/dist/components/shell/Sidebar.svelte.d.ts +32 -0
  110. package/dist/components/shell/SidebarGroup.svelte +180 -0
  111. package/dist/components/shell/SidebarGroup.svelte.d.ts +19 -0
  112. package/dist/components/shell/SidebarItem.svelte +170 -0
  113. package/dist/components/shell/SidebarItem.svelte.d.ts +24 -0
  114. package/dist/components/shell/shell.d.ts +30 -0
  115. package/dist/components/shell/shell.js +65 -0
  116. package/dist/components/table/DataTable.svelte +364 -0
  117. package/dist/components/table/DataTable.svelte.d.ts +4 -0
  118. package/dist/components/table/flexRender.d.ts +31 -0
  119. package/dist/components/table/flexRender.js +32 -0
  120. package/dist/components/table/types.d.ts +28 -0
  121. package/dist/components/table/types.js +1 -0
  122. package/dist/components/toast/ToastHost.svelte +21 -0
  123. package/dist/components/toast/ToastHost.svelte.d.ts +3 -0
  124. package/dist/components/toast/ToastItem.svelte +287 -0
  125. package/dist/components/toast/ToastItem.svelte.d.ts +9 -0
  126. package/dist/data/emojis.js +4 -4
  127. package/dist/dnd/autoScroll.js +12 -10
  128. package/dist/dnd/createDndBoard.svelte.js +110 -76
  129. package/dist/dnd/createDndBoard.test.js +161 -85
  130. package/dist/dnd/draggable.js +23 -15
  131. package/dist/dnd/dropTarget.js +29 -15
  132. package/dist/dnd/index.d.ts +0 -1
  133. package/dist/dnd/index.js +0 -1
  134. package/dist/dnd/types.d.ts +0 -9
  135. package/dist/dnd/types.js +14 -2
  136. package/dist/index.d.ts +60 -6
  137. package/dist/index.js +73 -6
  138. package/dist/showcase/AnimatedBeam.svelte +183 -0
  139. package/dist/showcase/AnimatedBeam.svelte.d.ts +26 -0
  140. package/dist/showcase/AuroraDrift.svelte +74 -0
  141. package/dist/showcase/AuroraDrift.svelte.d.ts +9 -0
  142. package/dist/showcase/BentoCard.svelte +50 -0
  143. package/dist/showcase/BentoCard.svelte.d.ts +14 -0
  144. package/dist/showcase/BentoGrid.svelte +43 -0
  145. package/dist/showcase/BentoGrid.svelte.d.ts +12 -0
  146. package/dist/showcase/BorderBeam.svelte +79 -0
  147. package/dist/showcase/BorderBeam.svelte.d.ts +12 -0
  148. package/dist/showcase/ClipWipe.svelte +82 -0
  149. package/dist/showcase/ClipWipe.svelte.d.ts +12 -0
  150. package/dist/showcase/Confetti.svelte +71 -0
  151. package/dist/showcase/Confetti.svelte.d.ts +10 -0
  152. package/dist/showcase/CursorSpotlight.svelte +85 -0
  153. package/dist/showcase/CursorSpotlight.svelte.d.ts +9 -0
  154. package/dist/showcase/DeviceMock.svelte +186 -0
  155. package/dist/showcase/DeviceMock.svelte.d.ts +11 -0
  156. package/dist/showcase/Dock.svelte +123 -0
  157. package/dist/showcase/Dock.svelte.d.ts +17 -0
  158. package/dist/showcase/FlipCard.svelte +103 -0
  159. package/dist/showcase/FlipCard.svelte.d.ts +10 -0
  160. package/dist/showcase/FocusReveal.svelte +83 -0
  161. package/dist/showcase/FocusReveal.svelte.d.ts +11 -0
  162. package/dist/showcase/Globe.svelte +202 -0
  163. package/dist/showcase/Globe.svelte.d.ts +16 -0
  164. package/dist/showcase/KenBurns.svelte +105 -0
  165. package/dist/showcase/KenBurns.svelte.d.ts +13 -0
  166. package/dist/showcase/Marquee.svelte +89 -0
  167. package/dist/showcase/Marquee.svelte.d.ts +9 -0
  168. package/dist/showcase/ParallaxTilt.svelte +98 -0
  169. package/dist/showcase/ParallaxTilt.svelte.d.ts +10 -0
  170. package/dist/showcase/ScrambleText.svelte +98 -0
  171. package/dist/showcase/ScrambleText.svelte.d.ts +11 -0
  172. package/dist/showcase/ShineSweep.svelte +81 -0
  173. package/dist/showcase/ShineSweep.svelte.d.ts +9 -0
  174. package/dist/showcase/Terminal.svelte +230 -0
  175. package/dist/showcase/Terminal.svelte.d.ts +18 -0
  176. package/dist/showcase/TextSplitReveal.svelte +146 -0
  177. package/dist/showcase/TextSplitReveal.svelte.d.ts +13 -0
  178. package/dist/showcase/TextWave.svelte +55 -0
  179. package/dist/showcase/TextWave.svelte.d.ts +8 -0
  180. package/dist/showcase/TypewriterText.svelte +130 -0
  181. package/dist/showcase/TypewriterText.svelte.d.ts +9 -0
  182. package/dist/showcase/backdrop/GrainGradient.svelte +126 -0
  183. package/dist/showcase/backdrop/GrainGradient.svelte.d.ts +23 -0
  184. package/dist/showcase/backdrop/MeshGradient.svelte +104 -0
  185. package/dist/showcase/backdrop/MeshGradient.svelte.d.ts +20 -0
  186. package/dist/showcase/backdrop/Metaballs.svelte +116 -0
  187. package/dist/showcase/backdrop/Metaballs.svelte.d.ts +18 -0
  188. package/dist/showcase/backdrop/NeuroNoise.svelte +115 -0
  189. package/dist/showcase/backdrop/NeuroNoise.svelte.d.ts +20 -0
  190. package/dist/showcase/backdrop/ShowcaseBackdrop.svelte +48 -0
  191. package/dist/showcase/backdrop/ShowcaseBackdrop.svelte.d.ts +12 -0
  192. package/dist/showcase/generative/GenerativeBackdrop.svelte +234 -0
  193. package/dist/showcase/generative/GenerativeBackdrop.svelte.d.ts +9 -0
  194. package/dist/showcase/generative/intent.d.ts +7 -0
  195. package/dist/showcase/generative/intent.js +67 -0
  196. package/dist/showcase/generative/manifest.d.ts +9 -0
  197. package/dist/showcase/generative/manifest.js +97 -0
  198. package/dist/showcase/generative/types.d.ts +48 -0
  199. package/dist/showcase/generative/types.js +8 -0
  200. package/dist/showcase/index.d.ts +36 -0
  201. package/dist/showcase/index.js +46 -0
  202. package/dist/showcase/scroll/SmoothScroll.svelte +49 -0
  203. package/dist/showcase/scroll/SmoothScroll.svelte.d.ts +12 -0
  204. package/dist/showcase/scroll/scrollProgress.d.ts +24 -0
  205. package/dist/showcase/scroll/scrollProgress.js +65 -0
  206. package/dist/showcase/scroll/scrollReveal.d.ts +30 -0
  207. package/dist/showcase/scroll/scrollReveal.js +70 -0
  208. package/dist/stores/commandPalette.svelte.d.ts +24 -0
  209. package/dist/stores/commandPalette.svelte.js +82 -0
  210. package/dist/stores/confirmDialog.svelte.js +5 -5
  211. package/dist/stores/inputDialog.svelte.js +5 -5
  212. package/dist/stores/toast.svelte.d.ts +28 -0
  213. package/dist/stores/toast.svelte.js +33 -0
  214. package/dist/styles/motion.css +46 -0
  215. package/dist/styles/tokens.css +31 -0
  216. package/dist/transitions/glide.d.ts +31 -0
  217. package/dist/transitions/glide.js +58 -0
  218. package/dist/types/booking.js +4 -4
  219. package/dist/types/comments.js +2 -2
  220. package/dist/types/messaging.js +3 -3
  221. package/dist/types/pipeline.js +2 -2
  222. package/dist/utils/currency.js +4 -2
  223. package/dist/utils/daisyuiColors.js +27 -25
  224. package/dist/utils/dateFormatters.d.ts +20 -0
  225. package/dist/utils/dateFormatters.js +65 -44
  226. package/dist/utils/googleMapsLoader.js +100 -46
  227. package/dist/utils/mentionParser.js +30 -30
  228. package/dist/utils/phone.js +27 -21
  229. package/dist/utils/phoneFormat.js +9 -9
  230. package/dist/utils/sound.d.ts +6 -0
  231. package/dist/utils/sound.js +113 -0
  232. package/dist/utils/splitText.d.ts +25 -0
  233. package/dist/utils/splitText.js +94 -0
  234. package/dist/utils/taskUtils.js +1 -1
  235. package/dist/utils/themeWipe.d.ts +21 -0
  236. package/dist/utils/themeWipe.js +94 -0
  237. package/dist/utils/viewTransition.d.ts +23 -0
  238. package/dist/utils/viewTransition.js +75 -0
  239. package/package.json +56 -4
@@ -2,19 +2,14 @@
2
2
  /**
3
3
  * Collapse — batteries-included tall-content collapser.
4
4
  *
5
- * Wraps children in a region that caps at `threshold` px with a fade-out
6
- * gradient and renders a "Show more / Show less" toggle that self-hides when
7
- * the content is shorter than the threshold. Uses the `collapse` action for
8
- * measurement (ResizeObserver-backed, so streaming / {@html} content works).
5
+ * Animates via grid-template-rows 0fr↔1fr with var(--motion-glide) — no
6
+ * overshoot, no layout-property animation. The toggle self-hides when content
7
+ * is shorter than the threshold (ResizeObserver-backed measurement).
9
8
  *
10
9
  * <Collapse>
11
10
  * {@html renderedMarkdown}
12
11
  * </Collapse>
13
- *
14
- * For existing elements you don't want to wrap (a bare `<p>` inside an
15
- * `{#each}`, a `<pre>`), use the `collapse` action directly instead.
16
12
  */
17
- import { collapse } from '../actions/collapse';
18
13
 
19
14
  interface Props {
20
15
  /** Max collapsed height in px. Default 120. */
@@ -43,18 +38,39 @@
43
38
  }: Props = $props();
44
39
 
45
40
  let collapsible = $state(false);
41
+ let innerEl = $state<HTMLDivElement | null>(null);
46
42
  const instanceId = $props.id();
47
43
  const bodyId = `jatui-collapse-${instanceId}`;
44
+
45
+ // ResizeObserver to detect whether content is tall enough to collapse
46
+ $effect(() => {
47
+ if (!innerEl) return;
48
+ const ro = new ResizeObserver(() => {
49
+ if (!innerEl) return;
50
+ const naturalHeight = innerEl.scrollHeight;
51
+ collapsible = naturalHeight > threshold + 4;
52
+ });
53
+ ro.observe(innerEl);
54
+ return () => ro.disconnect();
55
+ });
56
+
57
+ const gradient = $derived(
58
+ `linear-gradient(to bottom, black ${fadeStart}%, transparent 100%)`
59
+ );
48
60
  </script>
49
61
 
50
62
  <div
51
63
  id={bodyId}
52
- class={`jatui-collapse-body ${className}`.trim()}
53
- use:collapse={{ threshold, fadeStart, expanded, onCollapsible: (c) => (collapsible = c) }}
64
+ class={`jatui-collapse-outer ${className}`.trim()}
65
+ class:jatui-collapse-outer-closed={collapsible && !expanded}
66
+ style="--collapse-threshold: {threshold}px; --collapse-gradient: {gradient};"
67
+ aria-expanded={expanded || !collapsible}
54
68
  >
55
- {#if children}
56
- {@render children()}
57
- {/if}
69
+ <div bind:this={innerEl} class="jatui-collapse-inner">
70
+ {#if children}
71
+ {@render children()}
72
+ {/if}
73
+ </div>
58
74
  </div>
59
75
  {#if collapsible}
60
76
  <button
@@ -69,9 +85,43 @@
69
85
  {/if}
70
86
 
71
87
  <style>
72
- .jatui-collapse-body {
88
+ /*
89
+ * Grid-template-rows trick: outer wraps inner with overflow:hidden.
90
+ * Closed → 0fr (inner pinned to 0 height). Open → 1fr (natural height).
91
+ * grid-template-rows is a discrete property in older engines but modern
92
+ * browsers interpolate it as a length when rows go 0fr↔1fr.
93
+ * No layout-property width change; height is the only transition.
94
+ */
95
+ .jatui-collapse-outer {
96
+ display: grid;
97
+ grid-template-rows: 1fr;
98
+ transition: grid-template-rows var(--motion-enter) var(--motion-glide);
99
+ overflow: hidden;
73
100
  position: relative;
74
101
  }
102
+
103
+ .jatui-collapse-outer-closed {
104
+ grid-template-rows: 0fr;
105
+ /* Fade gradient masks the bottom edge when collapsed */
106
+ -webkit-mask-image: var(--collapse-gradient);
107
+ mask-image: var(--collapse-gradient);
108
+ /* Cap visible area at threshold */
109
+ max-height: var(--collapse-threshold);
110
+ }
111
+
112
+ /* When open, remove the mask and height cap */
113
+ .jatui-collapse-outer:not(.jatui-collapse-outer-closed) {
114
+ max-height: none;
115
+ -webkit-mask-image: none;
116
+ mask-image: none;
117
+ }
118
+
119
+ .jatui-collapse-inner {
120
+ /* Required for grid 0fr to clamp to zero */
121
+ min-height: 0;
122
+ overflow: hidden;
123
+ }
124
+
75
125
  .jatui-collapse-toggle {
76
126
  display: block;
77
127
  margin-top: 4px;
@@ -88,4 +138,10 @@
88
138
  opacity: 1;
89
139
  text-decoration: underline;
90
140
  }
141
+
142
+ @media (prefers-reduced-motion: reduce) {
143
+ .jatui-collapse-outer {
144
+ transition: none;
145
+ }
146
+ }
91
147
  </style>
@@ -1,3 +1,14 @@
1
+ /**
2
+ * Collapse — batteries-included tall-content collapser.
3
+ *
4
+ * Animates via grid-template-rows 0fr↔1fr with var(--motion-glide) — no
5
+ * overshoot, no layout-property animation. The toggle self-hides when content
6
+ * is shorter than the threshold (ResizeObserver-backed measurement).
7
+ *
8
+ * <Collapse>
9
+ * {@html renderedMarkdown}
10
+ * </Collapse>
11
+ */
1
12
  interface Props {
2
13
  /** Max collapsed height in px. Default 120. */
3
14
  threshold?: number;
@@ -16,7 +16,7 @@
16
16
  let showSelector = $state(false)
17
17
  // svelte-ignore state_referenced_locally
18
18
  let lastSelectedColor = $state(selectedColor)
19
- let selectionAnimating = $state(false)
19
+ let poppingColor = $state<string | null>(null)
20
20
 
21
21
  const colorOptions = [
22
22
  { name: "Primary", value: "primary", bgClass: "bg-primary", textClass: "text-primary-content" },
@@ -37,15 +37,15 @@
37
37
  function handleColorSelect(colorValue: string) {
38
38
  if (colorValue !== selectedColor) {
39
39
  lastSelectedColor = colorValue
40
- selectionAnimating = true
40
+ poppingColor = colorValue
41
41
  onSelect(colorValue)
42
42
 
43
43
  setTimeout(() => {
44
- selectionAnimating = false
44
+ poppingColor = null
45
45
  if (compact) {
46
- setTimeout(() => { showSelector = false }, 800)
46
+ setTimeout(() => { showSelector = false }, 400)
47
47
  }
48
- }, 500)
48
+ }, 200)
49
49
  } else {
50
50
  onSelect(colorValue)
51
51
  }
@@ -79,13 +79,13 @@
79
79
  type="button"
80
80
  class="tooltip tooltip-top color-btn {option.bgClass} border-2 border-base-300
81
81
  {isSelected(option.value) ? 'selected' : ''}
82
- {selectionAnimating && lastSelectedColor === option.value ? 'selecting' : ''}"
82
+ {poppingColor === option.value ? 'popping' : ''}"
83
83
  data-tip={option.name}
84
84
  onclick={() => handleColorSelect(option.value)}
85
85
  aria-label="Select {option.name} color"
86
86
  >
87
- {#if isSelected(option.value) || (selectionAnimating && lastSelectedColor === option.value)}
88
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="{option.textClass} {selectionAnimating && lastSelectedColor === option.value ? 'animate-checkmark' : ''}">
87
+ {#if isSelected(option.value)}
88
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="{option.textClass} checkmark">
89
89
  <polyline points="20 6 9 17 4 12"></polyline>
90
90
  </svg>
91
91
  {/if}
@@ -117,7 +117,7 @@
117
117
  display: flex;
118
118
  align-items: center;
119
119
  justify-content: center;
120
- transition: transform 0.15s cubic-bezier(0.25, 0.46, 0.45, 0.94);
120
+ transition: transform var(--motion-fast) var(--motion-glide);
121
121
  cursor: pointer;
122
122
  }
123
123
 
@@ -130,17 +130,16 @@
130
130
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-base-content) 25%, transparent);
131
131
  }
132
132
 
133
- .color-btn.selecting {
134
- transform: scale(1.12);
135
- border-color: color-mix(in oklch, var(--color-base-100) 90%, transparent);
136
- box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-base-content) 35%, transparent);
137
- animation: pulse 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
133
+ /* Spring pop on selection — <=200ms, single overshoot */
134
+ .color-btn.popping {
135
+ transform: scale(1.2);
136
+ transition: transform var(--motion-enter) var(--motion-spring);
138
137
  }
139
138
 
140
139
  @media (prefers-reduced-motion: reduce) {
141
140
  .color-btn { transition: none; }
142
141
  .color-btn:hover { transform: none; }
143
- .color-btn.selecting { transform: none; animation: none; }
142
+ .color-btn.popping { transform: scale(1.1); transition: none; }
144
143
  }
145
144
 
146
145
  .color-preview {
@@ -150,18 +149,16 @@
150
149
  border: 1px solid color-mix(in oklch, var(--color-base-content) 20%, transparent);
151
150
  }
152
151
 
153
- @keyframes pulse {
154
- 0% { transform: scale(1); }
155
- 50% { transform: scale(1.15); }
156
- 100% { transform: scale(1.1); }
152
+ .checkmark {
153
+ animation: checkmark-pop var(--motion-enter) var(--motion-spring);
157
154
  }
158
155
 
159
- .animate-checkmark {
160
- animation: zoom-in 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
156
+ @keyframes checkmark-pop {
157
+ from { transform: scale(0); opacity: 0; }
158
+ to { transform: scale(1); opacity: 1; }
161
159
  }
162
160
 
163
- @keyframes zoom-in {
164
- 0% { transform: scale(0); opacity: 0; }
165
- 100% { transform: scale(1); opacity: 1; }
161
+ @media (prefers-reduced-motion: reduce) {
162
+ .checkmark { animation: none; }
166
163
  }
167
164
  </style>