@freqhole/playlistz 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/.changeset/config.json +11 -0
  2. package/.changeset/nice-wolves-thank.md +5 -0
  3. package/.freqhole-versions.json +4 -0
  4. package/.github/copilot-instructions.md +201 -0
  5. package/.github/workflows/changesets.yml +50 -0
  6. package/.github/workflows/npm-publish.yml +124 -0
  7. package/.github/workflows/pr-checks.yml +103 -0
  8. package/README.md +30 -0
  9. package/build-component.js +141 -0
  10. package/build-zip-bundle-lib.js +44 -0
  11. package/config/playwright.config.ts +47 -0
  12. package/config/vite.config.ts +44 -0
  13. package/config/vitest.config.ts +39 -0
  14. package/dist/assets/automerge_wasm_bg-Cik4BF9l.wasm +0 -0
  15. package/dist/assets/index-CbOXzGiA.js +216 -0
  16. package/dist/assets/index-CbOXzGiA.js.map +1 -0
  17. package/dist/assets/index-TvJ6RFpy.css +1 -0
  18. package/dist/assets/midden-DceCrT_L.js +2 -0
  19. package/dist/assets/midden-DceCrT_L.js.map +1 -0
  20. package/dist/assets/midden_bg-BLhfGIU-.wasm +0 -0
  21. package/dist/index.html +55 -0
  22. package/dist/sw.js +134 -0
  23. package/docs/AUTOMERGE_P2P_PLAN.md +233 -0
  24. package/docs/COLLABORATIVE_SHARING_PLAN.md +188 -0
  25. package/docs/E2E_TESTID_PLAN.md +234 -0
  26. package/docs/IROH_P2P_PLAN.md +302 -0
  27. package/docs/ROADMAP.md +695 -0
  28. package/docs/TODO.md +167 -0
  29. package/docs/bundle-embedding-plan.md +134 -0
  30. package/docs/standalone-refactor.md +184 -0
  31. package/e2e/all-playlists.spec.ts +220 -0
  32. package/e2e/audio-player.spec.ts +226 -0
  33. package/e2e/collaborative-features.spec.ts +229 -0
  34. package/e2e/contexts.ts +238 -0
  35. package/e2e/edit-panel.spec.ts +87 -0
  36. package/e2e/fixtures/bare-glitch-1s.m4a +0 -0
  37. package/e2e/fixtures/bare-glitch-1s.mp3 +0 -0
  38. package/e2e/fixtures/bare-glitch-1s.ogg +0 -0
  39. package/e2e/fixtures/chord-stack-3s.wav +0 -0
  40. package/e2e/fixtures/cover-anim.gif +0 -0
  41. package/e2e/fixtures/cover-blue.png +0 -0
  42. package/e2e/fixtures/cover-checkers.png +0 -0
  43. package/e2e/fixtures/cover-gradient.jpg +0 -0
  44. package/e2e/fixtures/cover-mono.gif +0 -0
  45. package/e2e/fixtures/cover-noise.png +0 -0
  46. package/e2e/fixtures/cover-plasma.webp +0 -0
  47. package/e2e/fixtures/cover-portrait.jpg +0 -0
  48. package/e2e/fixtures/cover-red.png +0 -0
  49. package/e2e/fixtures/cover-thumb.jpg +0 -0
  50. package/e2e/fixtures/cover-wide.webp +0 -0
  51. package/e2e/fixtures/generate.mjs +257 -0
  52. package/e2e/fixtures/long-drone-90s.mp3 +0 -0
  53. package/e2e/fixtures/noisy-binaural-8s.mp3 +0 -0
  54. package/e2e/fixtures/tagged-a3-4s.m4a +0 -0
  55. package/e2e/fixtures/tagged-a3-4s.mp3 +0 -0
  56. package/e2e/fixtures/tagged-a3-4s.ogg +0 -0
  57. package/e2e/fixtures/tagged-c5-3s.m4a +0 -0
  58. package/e2e/fixtures/tagged-c5-3s.mp3 +0 -0
  59. package/e2e/fixtures/tagged-c5-3s.ogg +0 -0
  60. package/e2e/fixtures/tagged-f4-6s.m4a +0 -0
  61. package/e2e/fixtures/tagged-f4-6s.mp3 +0 -0
  62. package/e2e/fixtures/tagged-f4-6s.ogg +0 -0
  63. package/e2e/fixtures/tone-220hz-10s.wav +0 -0
  64. package/e2e/fixtures/tone-440hz-2s.wav +0 -0
  65. package/e2e/fixtures/tone-880hz-5s.wav +0 -0
  66. package/e2e/fixtures/tone-stereo-3s.wav +0 -0
  67. package/e2e/fixtures/user-provided/README.md +1 -0
  68. package/e2e/helpers/app.ts +143 -0
  69. package/e2e/helpers/hooks.ts +133 -0
  70. package/e2e/helpers/index.ts +12 -0
  71. package/e2e/helpers/media.ts +125 -0
  72. package/e2e/helpers.ts +10 -0
  73. package/e2e/p2p-collaboration.spec.ts +356 -0
  74. package/e2e/p2p-multi-peer.spec.ts +723 -0
  75. package/e2e/p2p-states.spec.ts +302 -0
  76. package/e2e/playback.spec.ts +56 -0
  77. package/e2e/playlist-crud.spec.ts +126 -0
  78. package/e2e/share-link-autoplay.spec.ts +129 -0
  79. package/e2e/sharing-access.spec.ts +205 -0
  80. package/e2e/sharing.spec.ts +195 -0
  81. package/e2e/song-cache-state.spec.ts +202 -0
  82. package/e2e/zip-bundle.spec.ts +855 -0
  83. package/eslint.config.js +114 -0
  84. package/index.html +54 -0
  85. package/package.json +119 -0
  86. package/public/sw.js +134 -0
  87. package/scripts/use-local.mjs +37 -0
  88. package/scripts/use-published.mjs +37 -0
  89. package/src/App.tsx +9 -0
  90. package/src/cli/check.ts +164 -0
  91. package/src/cli/generate.ts +184 -0
  92. package/src/cli/http.ts +88 -0
  93. package/src/cli/index.ts +65 -0
  94. package/src/cli/init.ts +18 -0
  95. package/src/components/AllPlaylistsPanel.tsx +713 -0
  96. package/src/components/AudioPlayer.tsx +122 -0
  97. package/src/components/MarqueeText.tsx +101 -0
  98. package/src/components/PlaylistCoverModal.tsx +519 -0
  99. package/src/components/PlaylistEditPanel.tsx +803 -0
  100. package/src/components/PlaylistSharePanel.tsx +1020 -0
  101. package/src/components/ShareLinkKnockPanel.tsx +144 -0
  102. package/src/components/SharePanel.tsx +584 -0
  103. package/src/components/SongEditModal.tsx +453 -0
  104. package/src/components/SongEditPanel.tsx +578 -0
  105. package/src/components/SongRow.tsx +689 -0
  106. package/src/components/index.tsx +494 -0
  107. package/src/components/playlist/index.tsx +1203 -0
  108. package/src/context/PlaylistzContext.tsx +74 -0
  109. package/src/dev-hooks.ts +35 -0
  110. package/src/hooks/createDocIndexQuery.ts +53 -0
  111. package/src/hooks/createDocStore.test.ts +303 -0
  112. package/src/hooks/createDocStore.ts +90 -0
  113. package/src/hooks/useDragAndDrop.test.ts +474 -0
  114. package/src/hooks/useDragAndDrop.ts +400 -0
  115. package/src/hooks/useImageModal.test.ts +174 -0
  116. package/src/hooks/useImageModal.ts +201 -0
  117. package/src/hooks/usePlaylistManager.test.ts +453 -0
  118. package/src/hooks/usePlaylistManager.ts +685 -0
  119. package/src/hooks/usePlaylistsQuery.test.tsx +120 -0
  120. package/src/hooks/usePlaylistsQuery.ts +44 -0
  121. package/src/hooks/useSongState.test.ts +236 -0
  122. package/src/hooks/useSongState.ts +114 -0
  123. package/src/hooks/useUIState.ts +71 -0
  124. package/src/index.tsx +18 -0
  125. package/src/services/audioService.dev.ts +22 -0
  126. package/src/services/audioService.test.ts +1226 -0
  127. package/src/services/audioService.ts +1395 -0
  128. package/src/services/automergeRepo.test.ts +269 -0
  129. package/src/services/automergeRepo.ts +226 -0
  130. package/src/services/blobTransferService.dev.ts +119 -0
  131. package/src/services/blobTransferService.test.ts +441 -0
  132. package/src/services/blobTransferService.ts +702 -0
  133. package/src/services/docIndexService.test.ts +179 -0
  134. package/src/services/docIndexService.ts +118 -0
  135. package/src/services/fileProcessingService.test.ts +554 -0
  136. package/src/services/fileProcessingService.ts +239 -0
  137. package/src/services/imageService.test.ts +701 -0
  138. package/src/services/imageService.ts +365 -0
  139. package/src/services/indexedDBService.integration.test.ts +104 -0
  140. package/src/services/indexedDBService.test.ts +202 -0
  141. package/src/services/indexedDBService.ts +436 -0
  142. package/src/services/offlineService.test.ts +661 -0
  143. package/src/services/offlineService.ts +382 -0
  144. package/src/services/p2pService.test.ts +305 -0
  145. package/src/services/p2pService.ts +344 -0
  146. package/src/services/playlistDocService.test.ts +448 -0
  147. package/src/services/playlistDocService.ts +707 -0
  148. package/src/services/playlistDownloadService.test.ts +674 -0
  149. package/src/services/playlistDownloadService.ts +389 -0
  150. package/src/services/sharingService.test.ts +812 -0
  151. package/src/services/sharingService.ts +1073 -0
  152. package/src/services/sharingState.ts +161 -0
  153. package/src/services/songReactivity.test.ts +620 -0
  154. package/src/services/songReactivity.ts +145 -0
  155. package/src/services/standaloneService.test.ts +1025 -0
  156. package/src/services/standaloneService.ts +588 -0
  157. package/src/services/streamingAudioService.test.ts +275 -0
  158. package/src/services/streamingAudioService.ts +166 -0
  159. package/src/styles.css +428 -0
  160. package/src/test-setup.ts +547 -0
  161. package/src/types/global.d.ts +40 -0
  162. package/src/types/playlist.ts +99 -0
  163. package/src/utils/hashUtils.ts +41 -0
  164. package/src/utils/log.ts +97 -0
  165. package/src/utils/m3u.test.ts +172 -0
  166. package/src/utils/m3u.ts +136 -0
  167. package/src/utils/mockData.ts +166 -0
  168. package/src/utils/standaloneTemplates.test.ts +175 -0
  169. package/src/utils/standaloneTemplates.ts +83 -0
  170. package/src/utils/swTemplate.ts +84 -0
  171. package/src/utils/timeUtils.ts +166 -0
  172. package/src/utils/typeGuards.ts +171 -0
  173. package/src/web-component.tsx +98 -0
  174. package/src/zip-bundle/index.ts +7 -0
  175. package/src/zip-bundle/m3u.ts +45 -0
  176. package/src/zip-bundle/types.ts +50 -0
  177. package/src/zip-bundle/utils.ts +33 -0
  178. package/src/zip-bundle/zipBuilder.ts +309 -0
  179. package/tailwind.config.js +55 -0
  180. package/tsconfig.json +43 -0
package/src/styles.css ADDED
@@ -0,0 +1,428 @@
1
+ @import "tailwindcss";
2
+
3
+ @theme {
4
+ /* Custom color palette - black, white, magenta */
5
+ --color-magenta-50: #fdf4ff;
6
+ --color-magenta-100: #fae8ff;
7
+ --color-magenta-200: #f5d0fe;
8
+ --color-magenta-300: #f0abfc;
9
+ --color-magenta-400: #e879f9;
10
+ --color-magenta-500: #d946ef;
11
+ --color-magenta-600: #c026d3;
12
+ --color-magenta-700: #a21caf;
13
+ --color-magenta-800: #86198f;
14
+ --color-magenta-900: #701a75;
15
+ --color-magenta-950: #4a044e;
16
+
17
+ /* Dark theme grays */
18
+ --color-dark-100: #1a1a1a;
19
+ --color-dark-200: #2a2a2a;
20
+ --color-dark-300: #3a3a3a;
21
+ --color-dark-400: #4a4a4a;
22
+ --color-dark-500: #5a5a5a;
23
+ --color-dark-600: #6a6a6a;
24
+ --color-dark-700: #7a7a7a;
25
+ --color-dark-800: #0a0a0a;
26
+ --color-dark-900: #000000;
27
+ }
28
+
29
+ @layer base {
30
+ * {
31
+ box-sizing: border-box;
32
+ }
33
+
34
+ /* buttons and interactive labels always show the pointer cursor */
35
+ button:not([disabled]),
36
+ label[for],
37
+ label:has(input),
38
+ input[type="checkbox"]:not([disabled]),
39
+ input[type="radio"]:not([disabled]),
40
+ input[type="range"]:not([disabled]),
41
+ select:not([disabled]) {
42
+ cursor: pointer;
43
+ }
44
+
45
+ /* disabled buttons should show the not-allowed cursor */
46
+ button[disabled] {
47
+ cursor: not-allowed;
48
+ }
49
+
50
+ body {
51
+ background-color: black;
52
+ color: white;
53
+ font-family:
54
+ system-ui,
55
+ -apple-system,
56
+ sans-serif;
57
+ margin: 0;
58
+ padding: 0;
59
+ }
60
+
61
+ /* Custom scrollbar styling */
62
+ ::-webkit-scrollbar {
63
+ width: 8px;
64
+ height: 8px;
65
+ }
66
+
67
+ ::-webkit-scrollbar-track {
68
+ background-color: #2a2a2a;
69
+ }
70
+
71
+ ::-webkit-scrollbar-thumb {
72
+ background-color: #4a4a4a;
73
+ border-radius: 4px;
74
+ }
75
+
76
+ ::-webkit-scrollbar-thumb:hover {
77
+ background-color: #d946ef;
78
+ }
79
+
80
+ /* Firefox scrollbar styling */
81
+ * {
82
+ scrollbar-width: thin;
83
+ scrollbar-color: #4a4a4a #2a2a2a;
84
+ }
85
+ }
86
+
87
+ @layer components {
88
+ /* Playlist button hover effects */
89
+ .playlist-button-hover {
90
+ position: relative;
91
+ overflow: hidden;
92
+ transition: all 0.2s ease-out;
93
+ }
94
+
95
+ .playlist-button-hover:hover {
96
+ transform: scale(1.02);
97
+ box-shadow: 0 4px 12px rgba(217, 70, 239, 0.3);
98
+ }
99
+
100
+ /* Playlist item hover effects */
101
+ .playlist-item-hover:hover {
102
+ transform: translateX(2px);
103
+ box-shadow: -2px 0 8px rgba(217, 70, 239, 0.4);
104
+ }
105
+
106
+ /* Glass morphism effects */
107
+ .glass {
108
+ backdrop-filter: blur(16px) saturate(180%);
109
+ -webkit-backdrop-filter: blur(16px) saturate(180%);
110
+ background-color: rgba(26, 26, 26, 0.8);
111
+ border: 1px solid rgba(255, 255, 255, 0.125);
112
+ }
113
+ /* slide-down animation for inline edit panels */
114
+ @keyframes slideDown {
115
+ from {
116
+ opacity: 0;
117
+ transform: translateY(-16px);
118
+ }
119
+ to {
120
+ opacity: 1;
121
+ transform: translateY(0);
122
+ }
123
+ }
124
+
125
+ /* song row exit animations - small translate + opacity so they stay visible within scroll containers */
126
+ @keyframes rowFlyDown {
127
+ from {
128
+ transform: translateY(0);
129
+ opacity: 1;
130
+ }
131
+ to {
132
+ transform: translateY(56px);
133
+ opacity: 0;
134
+ }
135
+ }
136
+
137
+ @keyframes rowFlyUp {
138
+ from {
139
+ transform: translateY(0);
140
+ opacity: 1;
141
+ }
142
+ to {
143
+ transform: translateY(-56px);
144
+ opacity: 0;
145
+ }
146
+ }
147
+
148
+ /* song row enter animation */
149
+ @keyframes rowFlyIn {
150
+ from {
151
+ transform: translateY(20px);
152
+ opacity: 0;
153
+ }
154
+ to {
155
+ transform: translateY(0);
156
+ opacity: 1;
157
+ }
158
+ }
159
+
160
+ /* comet-border: a rotating gradient that appears as a moving "comet tail"
161
+ border around a button. wrap the button in a div.comet-border element.
162
+ the div needs overflow:hidden and padding:1px (the visible border width).
163
+ the button inside needs a solid bg (e.g. bg-black) to mask the gradient
164
+ except at the 1px edge. */
165
+ @keyframes comet-border-spin {
166
+ from { transform: rotate(0deg); }
167
+ to { transform: rotate(360deg); }
168
+ }
169
+
170
+ .comet-border {
171
+ position: relative;
172
+ overflow: hidden;
173
+ padding: 1px;
174
+ }
175
+
176
+ .comet-border > * {
177
+ position: relative;
178
+ z-index: 1;
179
+ }
180
+
181
+ .comet-border::before {
182
+ content: '';
183
+ position: absolute;
184
+ /* oversized square centered on the element so the conic gradient
185
+ fully covers all four edges as it rotates */
186
+ inset: -50%;
187
+ width: 200%;
188
+ height: 200%;
189
+ background: conic-gradient(
190
+ from 0deg,
191
+ transparent 40%,
192
+ #d946ef 55%,
193
+ transparent 70%
194
+ );
195
+ animation: comet-border-spin 2s linear infinite;
196
+ z-index: 0;
197
+ pointer-events: none;
198
+ }
199
+ }
200
+
201
+ @layer utilities {
202
+ /* Text selection */
203
+ .no-select {
204
+ -webkit-user-select: none;
205
+ -moz-user-select: none;
206
+ -ms-user-select: none;
207
+ user-select: none;
208
+ }
209
+
210
+ /* Focus styles */
211
+ .focus-outline:focus {
212
+ outline: none;
213
+ box-shadow: 0 0 0 2px rgba(217, 70, 239, 0.5);
214
+ }
215
+ }
216
+
217
+ /* Loading shimmer animation */
218
+ .loading-shimmer {
219
+ background: linear-gradient(90deg, #1a1a1a 25%, #2a2a2a 50%, #1a1a1a 75%);
220
+ background-size: 200% 100%;
221
+ animation: shimmer 1.5s infinite;
222
+ }
223
+
224
+ @keyframes shimmer {
225
+ 0% {
226
+ background-position: -200% 0;
227
+ }
228
+ 100% {
229
+ background-position: 200% 0;
230
+ }
231
+ }
232
+
233
+ /* Mobile responsive breakpoints */
234
+ @media (max-width: 900px) {
235
+ .mobile-full-width {
236
+ width: 100% !important;
237
+ }
238
+
239
+ .mobile-hidden {
240
+ display: none !important;
241
+ }
242
+
243
+ .mobile-flex-col {
244
+ flex-direction: column !important;
245
+ }
246
+
247
+ .mobile-text-center {
248
+ text-align: center !important;
249
+ }
250
+
251
+ .mobile-gap-2 {
252
+ gap: 0.5rem !important;
253
+ }
254
+
255
+ .mobile-p-4 {
256
+ padding: 1rem !important;
257
+ }
258
+ }
259
+
260
+ /* Dynamic background effects */
261
+ .dynamic-background {
262
+ background-attachment: fixed;
263
+ background-size: cover;
264
+ background-position: center;
265
+ background-repeat: no-repeat;
266
+ transition: all 1000ms cubic-bezier(0.4, 0, 0.2, 1);
267
+ will-change: background-image, filter;
268
+ }
269
+
270
+ .dynamic-background::before {
271
+ content: "";
272
+ position: absolute;
273
+ top: -20px;
274
+ left: -20px;
275
+ right: -20px;
276
+ bottom: -20px;
277
+ filter: blur(12px) saturate(1.2);
278
+ z-index: -1;
279
+ }
280
+
281
+ /* Sidebar collapse animations */
282
+ .sidebar-collapse-enter {
283
+ animation: slideInLeft 300ms cubic-bezier(0.4, 0, 0.2, 1);
284
+ }
285
+
286
+ .sidebar-collapse-exit {
287
+ animation: slideOutLeft 300ms cubic-bezier(0.4, 0, 0.2, 1);
288
+ }
289
+
290
+ @keyframes slideInLeft {
291
+ from {
292
+ transform: translateX(-100%);
293
+ opacity: 0;
294
+ }
295
+ to {
296
+ transform: translateX(0);
297
+ opacity: 1;
298
+ }
299
+ }
300
+
301
+ @keyframes slideOutLeft {
302
+ from {
303
+ transform: translateX(0);
304
+ opacity: 1;
305
+ }
306
+ to {
307
+ transform: translateX(-100%);
308
+ opacity: 0;
309
+ }
310
+ }
311
+
312
+ /* Background fade transitions */
313
+ .bg-fade-enter {
314
+ animation: fadeIn 1000ms ease-out;
315
+ }
316
+
317
+ .bg-fade-exit {
318
+ animation: fadeOut 500ms ease-out;
319
+ }
320
+
321
+ @keyframes fadeIn {
322
+ from {
323
+ opacity: 0;
324
+ filter: blur(20px) brightness(0.1);
325
+ }
326
+ to {
327
+ opacity: 0.2;
328
+ filter: blur(8px) brightness(0.3);
329
+ }
330
+ }
331
+
332
+ @keyframes fadeOut {
333
+ from {
334
+ opacity: 0.2;
335
+ filter: blur(8px) brightness(0.3);
336
+ }
337
+ to {
338
+ opacity: 0;
339
+ filter: blur(20px) brightness(0.1);
340
+ }
341
+ }
342
+
343
+ /* Touch-friendly button sizes on mobile */
344
+ @media (max-width: 900px) {
345
+ .touch-target {
346
+ min-height: 44px !important;
347
+ min-width: 44px !important;
348
+ }
349
+
350
+ /* Larger text on mobile for readability */
351
+ .mobile-text-lg {
352
+ font-size: 1.125rem !important;
353
+ }
354
+
355
+ .mobile-text-base {
356
+ font-size: 1rem !important;
357
+ }
358
+
359
+ /* Better spacing on mobile */
360
+ .mobile-p-6 {
361
+ padding: 1.5rem !important;
362
+ }
363
+
364
+ .mobile-px-4 {
365
+ padding-left: 1rem !important;
366
+ padding-right: 1rem !important;
367
+ }
368
+
369
+ /* Overlay button improvements */
370
+ .mobile-overlay-buttons {
371
+ background: rgba(0, 0, 0, 0.9) !important;
372
+ backdrop-filter: blur(8px) !important;
373
+ border-radius: 12px !important;
374
+ padding: 8px !important;
375
+ }
376
+ }
377
+
378
+ /* Seek slider styling */
379
+ .seek-slider::-webkit-slider-thumb {
380
+ -webkit-appearance: none;
381
+ width: 20px;
382
+ height: 20px;
383
+ border-radius: 3px;
384
+ background-color: #000000;
385
+ background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 500 500' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M250 405L125 155L375 155L303.611 340.714L250 405Z' fill='%23ec4899'/%3E%3C/svg%3E");
386
+ background-size: contain;
387
+ background-repeat: no-repeat;
388
+ background-position: center;
389
+ cursor: pointer;
390
+ border: none;
391
+ outline: none;
392
+ }
393
+
394
+ .seek-slider::-webkit-slider-thumb:hover {
395
+ background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 500 500' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M250 405L125 155L375 155L303.611 340.714L250 405Z' fill='%23f472b6'/%3E%3C/svg%3E");
396
+ transform: scale(1.1);
397
+ }
398
+
399
+ .seek-slider::-moz-range-thumb {
400
+ width: 20px;
401
+ height: 20px;
402
+ border-radius: 3px;
403
+ background-color: #000000;
404
+ background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 500 500' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M250 405L125 155L375 155L303.611 340.714L250 405Z' fill='%23ec4899'/%3E%3C/svg%3E");
405
+ background-size: contain;
406
+ background-repeat: no-repeat;
407
+ background-position: center;
408
+ cursor: pointer;
409
+ border: none;
410
+ outline: none;
411
+ }
412
+
413
+ .seek-slider::-moz-range-thumb:hover {
414
+ background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 500 500' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M250 405L125 155L375 155L303.611 340.714L250 405Z' fill='%23f472b6'/%3E%3C/svg%3E");
415
+ transform: scale(1.1);
416
+ }
417
+
418
+ .seek-slider:focus {
419
+ outline: none;
420
+ }
421
+
422
+ .seek-slider:focus::-webkit-slider-thumb {
423
+ outline: none;
424
+ }
425
+
426
+ .seek-slider:focus::-moz-range-thumb {
427
+ outline: none;
428
+ }