blanchon commited on
Commit
8899818
·
1 Parent(s): 6ecbce1

Add eslint with eslint-plugin-better-tailwindcss

Browse files

- Replace prettier-plugin-tailwindcss with eslint-plugin-better-tailwindcss
(the two disagreed on ordering — keep one source of truth for class order)
- ESLint flat config with svelte-eslint-parser + @typescript-eslint/parser,
scoped to non-shadcn source. Tailwind v4 entrypoint = src/routes/layout.css
- Disable no-unknown-classes (custom Svelte <style> classes like vs-beam) and
enforce-canonical-classes (h-full w-full ≠ size-full when parent is asymmetric)
- Auto-fix sorts every Tailwind class list and removes a few duplicates
- New scripts: bun run lint (prettier + eslint check), bun run lint:fix

.prettierrc CHANGED
@@ -3,7 +3,7 @@
3
  "singleQuote": true,
4
  "trailingComma": "none",
5
  "printWidth": 100,
6
- "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
7
  "overrides": [
8
  {
9
  "files": "*.svelte",
 
3
  "singleQuote": true,
4
  "trailingComma": "none",
5
  "printWidth": 100,
6
+ "plugins": ["prettier-plugin-svelte"],
7
  "overrides": [
8
  {
9
  "files": "*.svelte",
bun.lock CHANGED
@@ -17,22 +17,26 @@
17
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
18
  "@tailwindcss/vite": "^4.2.2",
19
  "@tanstack/table-core": "^8.21.3",
 
20
  "bits-ui": "^2.18.0",
21
  "clsx": "^2.1.1",
 
 
22
  "mode-watcher": "^1.1.0",
23
  "phosphor-svelte": "^3.1.0",
24
  "prettier": "^3.8.3",
25
  "prettier-plugin-svelte": "^3.5.1",
26
- "prettier-plugin-tailwindcss": "^0.8.0",
27
  "shadcn-svelte": "^1.2.7",
28
  "svelte": "^5.55.2",
29
  "svelte-check": "^4.4.6",
 
30
  "svelte-sonner": "^1.1.1",
31
  "tailwind-merge": "^3.5.0",
32
  "tailwind-variants": "^3.2.2",
33
  "tailwindcss": "^4.2.2",
34
  "tw-animate-css": "^1.4.0",
35
  "typescript": "^6.0.2",
 
36
  "vite": "^8.0.7",
37
  },
38
  },
@@ -44,6 +48,22 @@
44
 
45
  "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="],
48
 
49
  "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "1.7.5", "@floating-ui/utils": "0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="],
@@ -54,6 +74,16 @@
54
 
55
  "@fontsource-variable/roboto-slab": ["@fontsource-variable/roboto-slab@5.2.8", "", {}, "sha512-cdvOSwocP50xS01gXqnGxw7uFcCZQgn1IDlqiAmNuZP4uEVScYAKMDC+aWsbP1grn9QdMJ2frhcuVBNXniBVGA=="],
56
 
 
 
 
 
 
 
 
 
 
 
57
  "@internationalized/date": ["@internationalized/date@3.12.1", "", { "dependencies": { "@swc/helpers": "0.5.21" } }, "sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ=="],
58
 
59
  "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
@@ -70,6 +100,8 @@
70
 
71
  "@oxc-project/types": ["@oxc-project/types@0.127.0", "", {}, "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ=="],
72
 
 
 
73
  "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
74
 
75
  "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.17", "", { "os": "android", "cpu": "arm64" }, "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ=="],
@@ -156,28 +188,78 @@
156
 
157
  "@types/dom-webcodecs": ["@types/dom-webcodecs@0.1.13", "", {}, "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ=="],
158
 
 
 
159
  "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
160
 
 
 
161
  "@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
162
 
163
  "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
166
 
 
 
 
 
 
 
167
  "aria-query": ["aria-query@5.3.1", "", {}, "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g=="],
168
 
169
  "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
170
 
 
 
171
  "bits-ui": ["bits-ui@2.18.0", "", { "dependencies": { "@floating-ui/core": "1.7.5", "@floating-ui/dom": "1.7.6", "esm-env": "1.2.2", "runed": "0.35.1", "svelte-toolbelt": "0.10.6", "tabbable": "6.4.0" }, "peerDependencies": { "@internationalized/date": "3.12.1", "svelte": "5.55.5" } }, "sha512-GLOBZRVy3hxNHIQ2MpD/+5aK9KcBFZRhUJtZ1UDABXdlVR4K6zFpgt4T+Rwuhf2sQzlc6yK1q/DprHPjwT4Pjw=="],
172
 
 
 
 
 
173
  "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "4.1.2" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
174
 
175
  "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
176
 
 
 
 
 
177
  "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],
178
 
179
  "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="],
180
 
 
 
 
 
 
 
 
 
181
  "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
182
 
183
  "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
@@ -188,34 +270,94 @@
188
 
189
  "enhanced-resolve": ["enhanced-resolve@5.21.0", "", { "dependencies": { "graceful-fs": "4.2.11", "tapable": "2.3.3" } }, "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA=="],
190
 
 
 
 
 
 
 
 
 
 
 
191
  "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
192
 
 
 
 
 
193
  "esrap": ["esrap@2.2.5", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-/yLB1538mag+dn0wsePTe8C0rDIjUOaJpMs2McodSzmM2msWcZsBSdRtg6HOBt0A/r82BN+Md3pgwSc/uWt2Ig=="],
194
 
 
 
 
 
195
  "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "1.0.8" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
196
 
 
 
 
 
 
 
 
 
197
  "fdir": ["fdir@6.5.0", "", { "optionalDependencies": { "picomatch": "4.0.4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
198
 
 
 
 
 
 
 
 
 
199
  "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
200
 
201
  "fzstd": ["fzstd@0.1.1", "", {}, "sha512-dkuVSOKKwh3eas5VkJy1AW1vFpet8TA/fGmVA5krThl8YcOVE/8ZIoEA1+U1vEn5ckxxhLirSdY837azmbaNHA=="],
202
 
 
 
203
  "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
204
 
 
 
205
  "hyparquet": ["hyparquet@1.25.6", "", {}, "sha512-Q9W5IjkVch3ZMnYd4qFv2q8suu5Jc36yt7J+zUNM9grwnP1S189icp0jdEQKM5HJvQkTVy8NMiQ8n/dM5QAt1A=="],
206
 
207
  "hyparquet-compressors": ["hyparquet-compressors@1.1.1", "", { "dependencies": { "fzstd": "0.1.1", "hysnappy": "1.0.0" } }, "sha512-yx7aA3Rhj0YycbdV71+XznQSLAefa4cT0urpgNXy4aM6eSeCknaVDNne8y45Uz74Fb15yyXUzOStlceOJBan7A=="],
208
 
209
  "hysnappy": ["hysnappy@1.0.0", "", {}, "sha512-MNrC4NfwDGPb889O6gIfEtbvEZCSWUsSEhsz4Oq2FRcpGtXHfeVz3KciSPp5Pnnz1NjFMgDQNfxdJozymJEDDA=="],
210
 
 
 
 
 
211
  "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="],
212
 
 
 
 
 
213
  "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "1.0.8" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
214
 
 
 
215
  "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
216
 
 
 
 
 
 
 
 
 
 
 
217
  "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
218
 
 
 
219
  "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "2.1.2" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
220
 
221
  "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
@@ -242,24 +384,46 @@
242
 
243
  "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
244
 
 
 
245
  "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="],
246
 
247
  "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
248
 
 
 
249
  "mediabunny": ["mediabunny@1.42.0", "", { "dependencies": { "@types/dom-mediacapture-transform": "0.1.11", "@types/dom-webcodecs": "0.1.13" } }, "sha512-s9ypTqLi6kbh95gC+YaJlG0PkLvMxu37Q/wO/pFZx0fUCA5Ym5mp+2dWoa83mKQ3Uo18aNlgev5iJ5ESZqWwgQ=="],
250
 
 
 
 
 
251
  "mode-watcher": ["mode-watcher@1.1.0", "", { "dependencies": { "runed": "0.25.0", "svelte-toolbelt": "0.7.1" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-mUT9RRGPDYenk59qJauN1rhsIMKBmWA3xMF+uRwE8MW/tjhaDSCCARqkSuDTq8vr4/2KcAxIGVjACxTjdk5C3g=="],
252
 
253
  "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
254
 
255
  "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
256
 
 
 
257
  "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
258
 
 
 
259
  "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
260
 
261
  "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="],
262
 
 
 
 
 
 
 
 
 
 
 
263
  "phosphor-svelte": ["phosphor-svelte@3.1.0", "", { "dependencies": { "estree-walker": "3.0.3", "magic-string": "0.30.21" }, "optionalDependencies": { "vite": "8.0.10" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-nldtxx+XCgNREvrb7O5xgDsefytXpSkPTx8Rnu3f2qQCUZLDV1rLxYSd2Jcwckuo9lZB1qKMqGR17P4UDC0PrA=="],
264
 
265
  "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
@@ -268,11 +432,17 @@
268
 
269
  "postcss": ["postcss@8.5.12", "", { "dependencies": { "nanoid": "3.3.11", "picocolors": "1.1.1", "source-map-js": "1.2.1" } }, "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA=="],
270
 
 
 
 
 
 
 
271
  "prettier": ["prettier@3.8.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw=="],
272
 
273
  "prettier-plugin-svelte": ["prettier-plugin-svelte@3.5.1", "", { "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" } }, "sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg=="],
274
 
275
- "prettier-plugin-tailwindcss": ["prettier-plugin-tailwindcss@0.8.0", "", { "peerDependencies": { "@ianvs/prettier-plugin-sort-imports": "*", "@prettier/plugin-hermes": "*", "@prettier/plugin-oxc": "*", "@prettier/plugin-pug": "*", "@shopify/prettier-plugin-liquid": "*", "@trivago/prettier-plugin-sort-imports": "*", "@zackad/prettier-plugin-twig": "*", "prettier": "^3.0", "prettier-plugin-astro": "*", "prettier-plugin-css-order": "*", "prettier-plugin-jsdoc": "*", "prettier-plugin-marko": "*", "prettier-plugin-multiline-arrays": "*", "prettier-plugin-organize-attributes": "*", "prettier-plugin-organize-imports": "*", "prettier-plugin-sort-imports": "*", "prettier-plugin-svelte": "*" }, "optionalPeers": ["@ianvs/prettier-plugin-sort-imports", "@prettier/plugin-hermes", "@prettier/plugin-oxc", "@prettier/plugin-pug", "@shopify/prettier-plugin-liquid", "@trivago/prettier-plugin-sort-imports", "@zackad/prettier-plugin-twig", "prettier-plugin-astro", "prettier-plugin-css-order", "prettier-plugin-jsdoc", "prettier-plugin-marko", "prettier-plugin-multiline-arrays", "prettier-plugin-organize-attributes", "prettier-plugin-organize-imports", "prettier-plugin-sort-imports", "prettier-plugin-svelte"] }, "sha512-V8ITGH87yuBDF6JpEZTOVlUz/saAwqb8f3HRgUj8Lh+tGCcrmorhsLpYqzygwFwK0PE2Ib6Mv3M7T/uE2tZV1g=="],
276
 
277
  "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
278
 
@@ -282,26 +452,42 @@
282
 
283
  "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "1.2.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
284
 
 
 
285
  "set-cookie-parser": ["set-cookie-parser@3.1.0", "", {}, "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw=="],
286
 
287
  "shadcn-svelte": ["shadcn-svelte@1.2.7", "", { "dependencies": { "commander": "14.0.3", "node-fetch-native": "1.6.7", "postcss": "8.5.12", "tailwind-merge": "3.5.0" }, "peerDependencies": { "svelte": "5.55.5" }, "bin": { "shadcn-svelte": "dist/index.mjs" } }, "sha512-mWuQk4H4gtV+J2wJQ7nEPKNnB/v86AALFryZU0SSM7ChHmJJMZ1kH+qIuxYKrXm9vOOOcSWHRsWzPDB71DnjYA=="],
288
 
 
 
 
 
289
  "sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "1.0.0-next.29", "mrmime": "2.0.1", "totalist": "3.0.1" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="],
290
 
291
  "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
292
 
 
 
293
  "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="],
294
 
 
 
295
  "svelte": ["svelte@5.55.5", "", { "dependencies": { "@jridgewell/remapping": "2.3.5", "@jridgewell/sourcemap-codec": "1.5.5", "@sveltejs/acorn-typescript": "1.0.9", "@types/estree": "1.0.8", "@types/trusted-types": "2.0.7", "acorn": "8.16.0", "aria-query": "5.3.1", "axobject-query": "4.1.0", "clsx": "2.1.1", "devalue": "5.7.1", "esm-env": "1.2.2", "esrap": "2.2.5", "is-reference": "3.0.3", "locate-character": "3.0.0", "magic-string": "0.30.21", "zimmerframe": "1.1.4" } }, "sha512-2uCs/LZ9us+AktdzYJM8OcxQ8qnPS1kpaO7syGT/MgO+6Qr1Ybl+TqPq+97u7PHqmmMlye5ZkoyXONy5mjjAbw=="],
296
 
297
  "svelte-check": ["svelte-check@4.4.6", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.31", "chokidar": "4.0.3", "fdir": "6.5.0", "picocolors": "1.1.1", "sade": "1.8.1" }, "peerDependencies": { "svelte": "5.55.5", "typescript": "6.0.3" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-kP1zG81EWaFe9ZyTv4ZXv44Csi6Pkdpb7S3oj6m+K2ec/IcDg/a8LsFsnVLqm2nxtkSwsd5xPj/qFkTBgXHXjg=="],
298
 
 
 
299
  "svelte-sonner": ["svelte-sonner@1.1.1", "", { "dependencies": { "runed": "0.28.0" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-5cd3p7wa4cq0NsqslMwdlPb7x1JglEZ/GKrLePWNr5bCxR1nagAVrY01FRFrXfUGs41miLt3C327+8XJo5BzZw=="],
300
 
301
  "svelte-toolbelt": ["svelte-toolbelt@0.10.6", "", { "dependencies": { "clsx": "2.1.1", "runed": "0.35.1", "style-to-object": "1.0.14" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ=="],
302
 
 
 
303
  "tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="],
304
 
 
 
305
  "tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="],
306
 
307
  "tailwind-variants": ["tailwind-variants@3.2.2", "", { "optionalDependencies": { "tailwind-merge": "3.5.0" }, "peerDependencies": { "tailwindcss": "4.2.4" } }, "sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg=="],
@@ -314,24 +500,56 @@
314
 
315
  "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
316
 
 
 
 
 
 
 
317
  "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
318
 
319
  "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
320
 
 
 
321
  "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
322
 
 
 
323
  "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
324
 
 
 
 
 
 
 
325
  "vite": ["vite@8.0.10", "", { "dependencies": { "lightningcss": "1.32.0", "picomatch": "4.0.4", "postcss": "8.5.12", "rolldown": "1.0.0-rc.17", "tinyglobby": "0.2.16" }, "optionalDependencies": { "@types/node": "24.12.2", "fsevents": "2.3.3", "jiti": "2.6.1" }, "bin": { "vite": "bin/vite.js" } }, "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw=="],
326
 
327
  "vitefu": ["vitefu@1.1.3", "", { "optionalDependencies": { "vite": "8.0.10" } }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="],
328
 
 
 
 
 
 
 
329
  "zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="],
330
 
 
 
 
 
331
  "mode-watcher/runed": ["runed@0.25.0", "", { "dependencies": { "esm-env": "1.2.2" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-7+ma4AG9FT2sWQEA0Egf6mb7PBT2vHyuHail1ie8ropfSjvZGtEAx8YTmUjv/APCsdRRxEVvArNjALk9zFSOrg=="],
332
 
333
  "mode-watcher/svelte-toolbelt": ["svelte-toolbelt@0.7.1", "", { "dependencies": { "clsx": "2.1.1", "runed": "0.23.4", "style-to-object": "1.0.14" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ=="],
334
 
 
 
 
 
 
 
335
  "svelte-sonner/runed": ["runed@0.28.0", "", { "dependencies": { "esm-env": "1.2.2" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-k2xx7RuO9hWcdd9f+8JoBeqWtYrm5CALfgpkg2YDB80ds/QE4w0qqu34A7fqiAwiBBSBQOid7TLxwxVC27ymWQ=="],
336
 
337
  "mode-watcher/svelte-toolbelt/runed": ["runed@0.23.4", "", { "dependencies": { "esm-env": "1.2.2" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA=="],
 
17
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
18
  "@tailwindcss/vite": "^4.2.2",
19
  "@tanstack/table-core": "^8.21.3",
20
+ "@typescript-eslint/parser": "^8.59.1",
21
  "bits-ui": "^2.18.0",
22
  "clsx": "^2.1.1",
23
+ "eslint": "^10.2.1",
24
+ "eslint-plugin-better-tailwindcss": "^4.5.0",
25
  "mode-watcher": "^1.1.0",
26
  "phosphor-svelte": "^3.1.0",
27
  "prettier": "^3.8.3",
28
  "prettier-plugin-svelte": "^3.5.1",
 
29
  "shadcn-svelte": "^1.2.7",
30
  "svelte": "^5.55.2",
31
  "svelte-check": "^4.4.6",
32
+ "svelte-eslint-parser": "^1.6.0",
33
  "svelte-sonner": "^1.1.1",
34
  "tailwind-merge": "^3.5.0",
35
  "tailwind-variants": "^3.2.2",
36
  "tailwindcss": "^4.2.2",
37
  "tw-animate-css": "^1.4.0",
38
  "typescript": "^6.0.2",
39
+ "typescript-eslint": "^8.59.1",
40
  "vite": "^8.0.7",
41
  },
42
  },
 
48
 
49
  "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
50
 
51
+ "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
52
+
53
+ "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
54
+
55
+ "@eslint/config-array": ["@eslint/config-array@0.23.5", "", { "dependencies": { "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", "minimatch": "^10.2.4" } }, "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA=="],
56
+
57
+ "@eslint/config-helpers": ["@eslint/config-helpers@0.5.5", "", { "dependencies": { "@eslint/core": "^1.2.1" } }, "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w=="],
58
+
59
+ "@eslint/core": ["@eslint/core@1.2.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ=="],
60
+
61
+ "@eslint/css-tree": ["@eslint/css-tree@4.0.2", "", { "dependencies": { "mdn-data": "2.27.1", "source-map-js": "^1.2.1" } }, "sha512-eqSkC3mka2tiqOuPZKqvxNJoRzpxMss3Np3Yqi4sW7nTTRCpTKB2hzrY4JRsi0ZP3QbVfp23sgEm7VCoOjesmw=="],
62
+
63
+ "@eslint/object-schema": ["@eslint/object-schema@3.0.5", "", {}, "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw=="],
64
+
65
+ "@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.1", "", { "dependencies": { "@eslint/core": "^1.2.1", "levn": "^0.4.1" } }, "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ=="],
66
+
67
  "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="],
68
 
69
  "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "1.7.5", "@floating-ui/utils": "0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="],
 
74
 
75
  "@fontsource-variable/roboto-slab": ["@fontsource-variable/roboto-slab@5.2.8", "", {}, "sha512-cdvOSwocP50xS01gXqnGxw7uFcCZQgn1IDlqiAmNuZP4uEVScYAKMDC+aWsbP1grn9QdMJ2frhcuVBNXniBVGA=="],
76
 
77
+ "@humanfs/core": ["@humanfs/core@0.19.2", "", { "dependencies": { "@humanfs/types": "^0.15.0" } }, "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA=="],
78
+
79
+ "@humanfs/node": ["@humanfs/node@0.16.8", "", { "dependencies": { "@humanfs/core": "^0.19.2", "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ=="],
80
+
81
+ "@humanfs/types": ["@humanfs/types@0.15.0", "", {}, "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q=="],
82
+
83
+ "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
84
+
85
+ "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
86
+
87
  "@internationalized/date": ["@internationalized/date@3.12.1", "", { "dependencies": { "@swc/helpers": "0.5.21" } }, "sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ=="],
88
 
89
  "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
 
100
 
101
  "@oxc-project/types": ["@oxc-project/types@0.127.0", "", {}, "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ=="],
102
 
103
+ "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="],
104
+
105
  "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
106
 
107
  "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.17", "", { "os": "android", "cpu": "arm64" }, "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ=="],
 
188
 
189
  "@types/dom-webcodecs": ["@types/dom-webcodecs@0.1.13", "", {}, "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ=="],
190
 
191
+ "@types/esrecurse": ["@types/esrecurse@4.3.1", "", {}, "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw=="],
192
+
193
  "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
194
 
195
+ "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
196
+
197
  "@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
198
 
199
  "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
200
 
201
+ "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.59.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.59.1", "@typescript-eslint/type-utils": "8.59.1", "@typescript-eslint/utils": "8.59.1", "@typescript-eslint/visitor-keys": "8.59.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.59.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-BOziFIfE+6osHO9FoJG4zjoHUcvI7fTNBSpdAwrNH0/TLvzjsk2oo8XSSOT2HhqUyhZPfHv4UOffoJ9oEEQ7Ag=="],
202
+
203
+ "@typescript-eslint/parser": ["@typescript-eslint/parser@8.59.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.59.1", "@typescript-eslint/types": "8.59.1", "@typescript-eslint/typescript-estree": "8.59.1", "@typescript-eslint/visitor-keys": "8.59.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA=="],
204
+
205
+ "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.59.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.59.1", "@typescript-eslint/types": "^8.59.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-+MuHQlHiEr00Of/IQbE/MmEoi44znZHbR/Pz7Opq4HryUOlRi+/44dro9Ycy8Fyo+/024IWtw8m4JUMCGTYxDg=="],
206
+
207
+ "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.59.1", "", { "dependencies": { "@typescript-eslint/types": "8.59.1", "@typescript-eslint/visitor-keys": "8.59.1" } }, "sha512-LwuHQI4pDOYVKvmH2dkaJo6YZCSgouVgnS/z7yBPKBMvgtBvyLqiLy9Z6b7+m/TRcX1NFYUqZetI5Y+aT4GEfg=="],
208
+
209
+ "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.59.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-/0nEyPbX7gRsk0Uwfe4ALwwgxuA66d/l2mhRDNlAvaj4U3juhUtJNq0DsY8M2AYwwb9rEq2hrC3IcIcEt++iJA=="],
210
+
211
+ "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.59.1", "", { "dependencies": { "@typescript-eslint/types": "8.59.1", "@typescript-eslint/typescript-estree": "8.59.1", "@typescript-eslint/utils": "8.59.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-klWPBR2ciQHS3f++ug/mVnWKPjBUo7icEL3FAO1lhAR1Z1i5NQYZ1EannMSRYcq5qCv5wNALlXr6fksRHyYl7w=="],
212
+
213
+ "@typescript-eslint/types": ["@typescript-eslint/types@8.59.1", "", {}, "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A=="],
214
+
215
+ "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.59.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.59.1", "@typescript-eslint/tsconfig-utils": "8.59.1", "@typescript-eslint/types": "8.59.1", "@typescript-eslint/visitor-keys": "8.59.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-OUd+vJS05sSkOip+BkZ/2NS8RMxrAAJemsC6vU3kmfLyeaJT0TftHkV9mcx2107MmsBVXXexhVu4F0TZXyMl4g=="],
216
+
217
+ "@typescript-eslint/utils": ["@typescript-eslint/utils@8.59.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.59.1", "@typescript-eslint/types": "8.59.1", "@typescript-eslint/typescript-estree": "8.59.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-3pIeoXhCeYH9FSCBI8P3iNwJlGuzPlYKkTlen2O9T1DSeeg8UG8jstq6BLk+Mda0qup7mgk4z4XL4OzRaxZ8LA=="],
218
+
219
+ "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.59.1", "", { "dependencies": { "@typescript-eslint/types": "8.59.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-LdDNl6C5iJExcM0Yh0PwAIBb9PrSiCsWamF/JyEZawm3kFDnRoaq3LGE4bpyRao/fWeGKKyw7icx0YxrLFC5Cg=="],
220
+
221
+ "@valibot/to-json-schema": ["@valibot/to-json-schema@1.6.0", "", { "peerDependencies": { "valibot": "^1.3.0" } }, "sha512-d6rYyK5KVa2XdqamWgZ4/Nr+cXhxjy7lmpe6Iajw15J/jmU+gyxl2IEd1Otg1d7Rl3gOQL5reulnSypzBtYy1A=="],
222
+
223
  "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
224
 
225
+ "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
226
+
227
+ "ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="],
228
+
229
+ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
230
+
231
  "aria-query": ["aria-query@5.3.1", "", {}, "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g=="],
232
 
233
  "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
234
 
235
+ "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
236
+
237
  "bits-ui": ["bits-ui@2.18.0", "", { "dependencies": { "@floating-ui/core": "1.7.5", "@floating-ui/dom": "1.7.6", "esm-env": "1.2.2", "runed": "0.35.1", "svelte-toolbelt": "0.10.6", "tabbable": "6.4.0" }, "peerDependencies": { "@internationalized/date": "3.12.1", "svelte": "5.55.5" } }, "sha512-GLOBZRVy3hxNHIQ2MpD/+5aK9KcBFZRhUJtZ1UDABXdlVR4K6zFpgt4T+Rwuhf2sQzlc6yK1q/DprHPjwT4Pjw=="],
238
 
239
+ "brace-expansion": ["brace-expansion@5.0.5", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="],
240
+
241
+ "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
242
+
243
  "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "4.1.2" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
244
 
245
  "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
246
 
247
+ "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
248
+
249
+ "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
250
+
251
  "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],
252
 
253
  "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="],
254
 
255
+ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
256
+
257
+ "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
258
+
259
+ "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
260
+
261
+ "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
262
+
263
  "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
264
 
265
  "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
 
270
 
271
  "enhanced-resolve": ["enhanced-resolve@5.21.0", "", { "dependencies": { "graceful-fs": "4.2.11", "tapable": "2.3.3" } }, "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA=="],
272
 
273
+ "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
274
+
275
+ "eslint": ["eslint@10.2.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.5.5", "@eslint/core": "^1.2.1", "@eslint/plugin-kit": "^0.7.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q=="],
276
+
277
+ "eslint-plugin-better-tailwindcss": ["eslint-plugin-better-tailwindcss@4.5.0", "", { "dependencies": { "@eslint/css-tree": "^4.0.1", "@valibot/to-json-schema": "^1.6.0", "enhanced-resolve": "^5.20.1", "jiti": "^2.6.1", "synckit": "^0.11.12", "tailwind-csstree": "^0.3.0", "tsconfig-paths-webpack-plugin": "^4.2.0", "valibot": "^1.3.1" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", "oxlint": "^1.35.0", "tailwindcss": "^3.3.0 || ^4.1.17" }, "optionalPeers": ["eslint", "oxlint"] }, "sha512-EBNTx6OJYaWv7uUxHWTy1fhiNz2rZVkoeOHZzAJFwWaEPideBf04CMshrJ7YntG0KQzadlbRhHKYr32q5aBX4w=="],
278
+
279
+ "eslint-scope": ["eslint-scope@9.1.2", "", { "dependencies": { "@types/esrecurse": "^4.3.1", "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ=="],
280
+
281
+ "eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
282
+
283
  "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
284
 
285
+ "espree": ["espree@11.2.0", "", { "dependencies": { "acorn": "^8.16.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^5.0.1" } }, "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw=="],
286
+
287
+ "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="],
288
+
289
  "esrap": ["esrap@2.2.5", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-/yLB1538mag+dn0wsePTe8C0rDIjUOaJpMs2McodSzmM2msWcZsBSdRtg6HOBt0A/r82BN+Md3pgwSc/uWt2Ig=="],
290
 
291
+ "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
292
+
293
+ "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
294
+
295
  "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "1.0.8" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
296
 
297
+ "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
298
+
299
+ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
300
+
301
+ "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
302
+
303
+ "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
304
+
305
  "fdir": ["fdir@6.5.0", "", { "optionalDependencies": { "picomatch": "4.0.4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
306
 
307
+ "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
308
+
309
+ "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
310
+
311
+ "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
312
+
313
+ "flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="],
314
+
315
  "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
316
 
317
  "fzstd": ["fzstd@0.1.1", "", {}, "sha512-dkuVSOKKwh3eas5VkJy1AW1vFpet8TA/fGmVA5krThl8YcOVE/8ZIoEA1+U1vEn5ckxxhLirSdY837azmbaNHA=="],
318
 
319
+ "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
320
+
321
  "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
322
 
323
+ "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
324
+
325
  "hyparquet": ["hyparquet@1.25.6", "", {}, "sha512-Q9W5IjkVch3ZMnYd4qFv2q8suu5Jc36yt7J+zUNM9grwnP1S189icp0jdEQKM5HJvQkTVy8NMiQ8n/dM5QAt1A=="],
326
 
327
  "hyparquet-compressors": ["hyparquet-compressors@1.1.1", "", { "dependencies": { "fzstd": "0.1.1", "hysnappy": "1.0.0" } }, "sha512-yx7aA3Rhj0YycbdV71+XznQSLAefa4cT0urpgNXy4aM6eSeCknaVDNne8y45Uz74Fb15yyXUzOStlceOJBan7A=="],
328
 
329
  "hysnappy": ["hysnappy@1.0.0", "", {}, "sha512-MNrC4NfwDGPb889O6gIfEtbvEZCSWUsSEhsz4Oq2FRcpGtXHfeVz3KciSPp5Pnnz1NjFMgDQNfxdJozymJEDDA=="],
330
 
331
+ "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
332
+
333
+ "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
334
+
335
  "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="],
336
 
337
+ "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
338
+
339
+ "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
340
+
341
  "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "1.0.8" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
342
 
343
+ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
344
+
345
  "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
346
 
347
+ "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
348
+
349
+ "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
350
+
351
+ "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
352
+
353
+ "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
354
+
355
+ "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
356
+
357
  "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
358
 
359
+ "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
360
+
361
  "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "2.1.2" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
362
 
363
  "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
 
384
 
385
  "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
386
 
387
+ "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
388
+
389
  "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="],
390
 
391
  "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
392
 
393
+ "mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="],
394
+
395
  "mediabunny": ["mediabunny@1.42.0", "", { "dependencies": { "@types/dom-mediacapture-transform": "0.1.11", "@types/dom-webcodecs": "0.1.13" } }, "sha512-s9ypTqLi6kbh95gC+YaJlG0PkLvMxu37Q/wO/pFZx0fUCA5Ym5mp+2dWoa83mKQ3Uo18aNlgev5iJ5ESZqWwgQ=="],
396
 
397
+ "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
398
+
399
+ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
400
+
401
  "mode-watcher": ["mode-watcher@1.1.0", "", { "dependencies": { "runed": "0.25.0", "svelte-toolbelt": "0.7.1" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-mUT9RRGPDYenk59qJauN1rhsIMKBmWA3xMF+uRwE8MW/tjhaDSCCARqkSuDTq8vr4/2KcAxIGVjACxTjdk5C3g=="],
402
 
403
  "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
404
 
405
  "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
406
 
407
+ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
408
+
409
  "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
410
 
411
+ "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
412
+
413
  "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
414
 
415
  "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="],
416
 
417
+ "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
418
+
419
+ "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
420
+
421
+ "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
422
+
423
+ "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
424
+
425
+ "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
426
+
427
  "phosphor-svelte": ["phosphor-svelte@3.1.0", "", { "dependencies": { "estree-walker": "3.0.3", "magic-string": "0.30.21" }, "optionalDependencies": { "vite": "8.0.10" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-nldtxx+XCgNREvrb7O5xgDsefytXpSkPTx8Rnu3f2qQCUZLDV1rLxYSd2Jcwckuo9lZB1qKMqGR17P4UDC0PrA=="],
428
 
429
  "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
 
432
 
433
  "postcss": ["postcss@8.5.12", "", { "dependencies": { "nanoid": "3.3.11", "picocolors": "1.1.1", "source-map-js": "1.2.1" } }, "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA=="],
434
 
435
+ "postcss-scss": ["postcss-scss@4.0.9", "", { "peerDependencies": { "postcss": "^8.4.29" } }, "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A=="],
436
+
437
+ "postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
438
+
439
+ "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
440
+
441
  "prettier": ["prettier@3.8.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw=="],
442
 
443
  "prettier-plugin-svelte": ["prettier-plugin-svelte@3.5.1", "", { "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" } }, "sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg=="],
444
 
445
+ "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
446
 
447
  "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
448
 
 
452
 
453
  "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "1.2.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
454
 
455
+ "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
456
+
457
  "set-cookie-parser": ["set-cookie-parser@3.1.0", "", {}, "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw=="],
458
 
459
  "shadcn-svelte": ["shadcn-svelte@1.2.7", "", { "dependencies": { "commander": "14.0.3", "node-fetch-native": "1.6.7", "postcss": "8.5.12", "tailwind-merge": "3.5.0" }, "peerDependencies": { "svelte": "5.55.5" }, "bin": { "shadcn-svelte": "dist/index.mjs" } }, "sha512-mWuQk4H4gtV+J2wJQ7nEPKNnB/v86AALFryZU0SSM7ChHmJJMZ1kH+qIuxYKrXm9vOOOcSWHRsWzPDB71DnjYA=="],
460
 
461
+ "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
462
+
463
+ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
464
+
465
  "sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "1.0.0-next.29", "mrmime": "2.0.1", "totalist": "3.0.1" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="],
466
 
467
  "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
468
 
469
+ "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
470
+
471
  "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="],
472
 
473
+ "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
474
+
475
  "svelte": ["svelte@5.55.5", "", { "dependencies": { "@jridgewell/remapping": "2.3.5", "@jridgewell/sourcemap-codec": "1.5.5", "@sveltejs/acorn-typescript": "1.0.9", "@types/estree": "1.0.8", "@types/trusted-types": "2.0.7", "acorn": "8.16.0", "aria-query": "5.3.1", "axobject-query": "4.1.0", "clsx": "2.1.1", "devalue": "5.7.1", "esm-env": "1.2.2", "esrap": "2.2.5", "is-reference": "3.0.3", "locate-character": "3.0.0", "magic-string": "0.30.21", "zimmerframe": "1.1.4" } }, "sha512-2uCs/LZ9us+AktdzYJM8OcxQ8qnPS1kpaO7syGT/MgO+6Qr1Ybl+TqPq+97u7PHqmmMlye5ZkoyXONy5mjjAbw=="],
476
 
477
  "svelte-check": ["svelte-check@4.4.6", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.31", "chokidar": "4.0.3", "fdir": "6.5.0", "picocolors": "1.1.1", "sade": "1.8.1" }, "peerDependencies": { "svelte": "5.55.5", "typescript": "6.0.3" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-kP1zG81EWaFe9ZyTv4ZXv44Csi6Pkdpb7S3oj6m+K2ec/IcDg/a8LsFsnVLqm2nxtkSwsd5xPj/qFkTBgXHXjg=="],
478
 
479
+ "svelte-eslint-parser": ["svelte-eslint-parser@1.6.0", "", { "dependencies": { "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.0.0", "espree": "^10.0.0", "postcss": "^8.4.49", "postcss-scss": "^4.0.9", "postcss-selector-parser": "^7.0.0", "semver": "^7.7.2" }, "peerDependencies": { "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-qoB1ehychT6OxEtQAqc/guSqLS20SlA53Uijl7x375s8nlUT0lb9ol/gzraEEatQwsyPTJo87s2CmKL9Xab+Uw=="],
480
+
481
  "svelte-sonner": ["svelte-sonner@1.1.1", "", { "dependencies": { "runed": "0.28.0" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-5cd3p7wa4cq0NsqslMwdlPb7x1JglEZ/GKrLePWNr5bCxR1nagAVrY01FRFrXfUGs41miLt3C327+8XJo5BzZw=="],
482
 
483
  "svelte-toolbelt": ["svelte-toolbelt@0.10.6", "", { "dependencies": { "clsx": "2.1.1", "runed": "0.35.1", "style-to-object": "1.0.14" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ=="],
484
 
485
+ "synckit": ["synckit@0.11.12", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ=="],
486
+
487
  "tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="],
488
 
489
+ "tailwind-csstree": ["tailwind-csstree@0.3.1", "", { "peerDependencies": { "@eslint/css": ">=1.0.0" }, "optionalPeers": ["@eslint/css"] }, "sha512-v147gLOR+E+9H4dNaP9rBeS/S/CTQJMRItlX9jLOXjdBGfSRauLwiz7LBCViaQmn6URXIlOdN6iMzSzOaeoUUw=="],
490
+
491
  "tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="],
492
 
493
  "tailwind-variants": ["tailwind-variants@3.2.2", "", { "optionalDependencies": { "tailwind-merge": "3.5.0" }, "peerDependencies": { "tailwindcss": "4.2.4" } }, "sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg=="],
 
500
 
501
  "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
502
 
503
+ "ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="],
504
+
505
+ "tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="],
506
+
507
+ "tsconfig-paths-webpack-plugin": ["tsconfig-paths-webpack-plugin@4.2.0", "", { "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.7.0", "tapable": "^2.2.1", "tsconfig-paths": "^4.1.2" } }, "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA=="],
508
+
509
  "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
510
 
511
  "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
512
 
513
+ "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
514
+
515
  "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
516
 
517
+ "typescript-eslint": ["typescript-eslint@8.59.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.1", "@typescript-eslint/parser": "8.59.1", "@typescript-eslint/typescript-estree": "8.59.1", "@typescript-eslint/utils": "8.59.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-xqDcFVBmlrltH64lklOVp1wYxgJr6LVdg3NamBgH2OOQDLFdTKfIZXF5PfghrnXQKXZGTQs8tr1vL7fJvq8CTQ=="],
518
+
519
  "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
520
 
521
+ "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
522
+
523
+ "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
524
+
525
+ "valibot": ["valibot@1.3.1", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-sfdRir/QFM0JaF22hqTroPc5xy4DimuGQVKFrzF1YfGwaS1nJot3Y8VqMdLO2Lg27fMzat2yD3pY5PbAYO39Gg=="],
526
+
527
  "vite": ["vite@8.0.10", "", { "dependencies": { "lightningcss": "1.32.0", "picomatch": "4.0.4", "postcss": "8.5.12", "rolldown": "1.0.0-rc.17", "tinyglobby": "0.2.16" }, "optionalDependencies": { "@types/node": "24.12.2", "fsevents": "2.3.3", "jiti": "2.6.1" }, "bin": { "vite": "bin/vite.js" } }, "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw=="],
528
 
529
  "vitefu": ["vitefu@1.1.3", "", { "optionalDependencies": { "vite": "8.0.10" } }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="],
530
 
531
+ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
532
+
533
+ "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
534
+
535
+ "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
536
+
537
  "zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="],
538
 
539
+ "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
540
+
541
+ "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
542
+
543
  "mode-watcher/runed": ["runed@0.25.0", "", { "dependencies": { "esm-env": "1.2.2" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-7+ma4AG9FT2sWQEA0Egf6mb7PBT2vHyuHail1ie8ropfSjvZGtEAx8YTmUjv/APCsdRRxEVvArNjALk9zFSOrg=="],
544
 
545
  "mode-watcher/svelte-toolbelt": ["svelte-toolbelt@0.7.1", "", { "dependencies": { "clsx": "2.1.1", "runed": "0.23.4", "style-to-object": "1.0.14" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ=="],
546
 
547
+ "svelte-eslint-parser/eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
548
+
549
+ "svelte-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
550
+
551
+ "svelte-eslint-parser/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
552
+
553
  "svelte-sonner/runed": ["runed@0.28.0", "", { "dependencies": { "esm-env": "1.2.2" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-k2xx7RuO9hWcdd9f+8JoBeqWtYrm5CALfgpkg2YDB80ds/QE4w0qqu34A7fqiAwiBBSBQOid7TLxwxVC27ymWQ=="],
554
 
555
  "mode-watcher/svelte-toolbelt/runed": ["runed@0.23.4", "", { "dependencies": { "esm-env": "1.2.2" }, "peerDependencies": { "svelte": "5.55.5" } }, "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA=="],
eslint.config.js ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import eslintPluginBetterTailwindcss from 'eslint-plugin-better-tailwindcss';
2
+ import tsParser from '@typescript-eslint/parser';
3
+ import svelteParser from 'svelte-eslint-parser';
4
+
5
+ const tailwindSettings = {
6
+ 'better-tailwindcss': {
7
+ entryPoint: 'src/routes/layout.css'
8
+ }
9
+ };
10
+
11
+ const tailwindRules = {
12
+ ...eslintPluginBetterTailwindcss.configs.recommended.rules,
13
+ // Prettier handles physical line wrapping
14
+ 'better-tailwindcss/enforce-consistent-line-wrapping': 'off',
15
+ // Custom CSS classes in Svelte <style> blocks (vs-beam, mp-marker, vp-freeze, ...)
16
+ // trip this rule even though they're real classes
17
+ 'better-tailwindcss/no-unknown-classes': 'off',
18
+ // `h-full w-full` ≠ `size-full` semantically when a parent is asymmetric
19
+ 'better-tailwindcss/enforce-canonical-classes': 'off'
20
+ };
21
+
22
+ export default [
23
+ {
24
+ ignores: [
25
+ 'node_modules/**',
26
+ '.svelte-kit/**',
27
+ 'dist/**',
28
+ 'build/**',
29
+ 'static/**',
30
+ 'src/lib/components/ui/**'
31
+ ]
32
+ },
33
+ {
34
+ files: ['**/*.svelte'],
35
+ languageOptions: {
36
+ parser: svelteParser,
37
+ parserOptions: { parser: tsParser, extraFileExtensions: ['.svelte'] }
38
+ },
39
+ plugins: { 'better-tailwindcss': eslintPluginBetterTailwindcss },
40
+ settings: tailwindSettings,
41
+ rules: tailwindRules
42
+ },
43
+ {
44
+ files: ['**/*.{ts,js}'],
45
+ languageOptions: { parser: tsParser },
46
+ plugins: { 'better-tailwindcss': eslintPluginBetterTailwindcss },
47
+ settings: tailwindSettings,
48
+ rules: tailwindRules
49
+ }
50
+ ];
package.json CHANGED
@@ -15,7 +15,8 @@
15
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
16
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
17
  "format": "prettier --write .",
18
- "lint": "prettier --check ."
 
19
  },
20
  "devDependencies": {
21
  "@fontsource-variable/oxanium": "^5.2.8",
@@ -25,22 +26,26 @@
25
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
26
  "@tailwindcss/vite": "^4.2.2",
27
  "@tanstack/table-core": "^8.21.3",
 
28
  "bits-ui": "^2.18.0",
29
  "clsx": "^2.1.1",
 
 
30
  "mode-watcher": "^1.1.0",
31
  "phosphor-svelte": "^3.1.0",
32
  "prettier": "^3.8.3",
33
  "prettier-plugin-svelte": "^3.5.1",
34
- "prettier-plugin-tailwindcss": "^0.8.0",
35
  "shadcn-svelte": "^1.2.7",
36
  "svelte": "^5.55.2",
37
  "svelte-check": "^4.4.6",
 
38
  "svelte-sonner": "^1.1.1",
39
  "tailwind-merge": "^3.5.0",
40
  "tailwind-variants": "^3.2.2",
41
  "tailwindcss": "^4.2.2",
42
  "tw-animate-css": "^1.4.0",
43
  "typescript": "^6.0.2",
 
44
  "vite": "^8.0.7"
45
  },
46
  "dependencies": {
 
15
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
16
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
17
  "format": "prettier --write .",
18
+ "lint": "prettier --check . && eslint .",
19
+ "lint:fix": "eslint --fix ."
20
  },
21
  "devDependencies": {
22
  "@fontsource-variable/oxanium": "^5.2.8",
 
26
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
27
  "@tailwindcss/vite": "^4.2.2",
28
  "@tanstack/table-core": "^8.21.3",
29
+ "@typescript-eslint/parser": "^8.59.1",
30
  "bits-ui": "^2.18.0",
31
  "clsx": "^2.1.1",
32
+ "eslint": "^10.2.1",
33
+ "eslint-plugin-better-tailwindcss": "^4.5.0",
34
  "mode-watcher": "^1.1.0",
35
  "phosphor-svelte": "^3.1.0",
36
  "prettier": "^3.8.3",
37
  "prettier-plugin-svelte": "^3.5.1",
 
38
  "shadcn-svelte": "^1.2.7",
39
  "svelte": "^5.55.2",
40
  "svelte-check": "^4.4.6",
41
+ "svelte-eslint-parser": "^1.6.0",
42
  "svelte-sonner": "^1.1.1",
43
  "tailwind-merge": "^3.5.0",
44
  "tailwind-variants": "^3.2.2",
45
  "tailwindcss": "^4.2.2",
46
  "tw-animate-css": "^1.4.0",
47
  "typescript": "^6.0.2",
48
+ "typescript-eslint": "^8.59.1",
49
  "vite": "^8.0.7"
50
  },
51
  "dependencies": {
src/lib/components/grid-tile.svelte CHANGED
@@ -143,7 +143,7 @@
143
  aria-disabled={!available}
144
  class={cn(
145
  'group relative aspect-video cursor-pointer overflow-hidden rounded-md border bg-black transition',
146
- 'data-[current=false]:border-border data-[current=false]:hover:border-foreground/40 aria-disabled:opacity-60',
147
  'data-[current=true]:ring-2 data-[side=CT]:data-[current=true]:border-sky-500 data-[side=CT]:data-[current=true]:ring-sky-500/40',
148
  'data-[side=T]:data-[current=true]:border-amber-500 data-[side=T]:data-[current=true]:ring-amber-500/40'
149
  )}
@@ -181,7 +181,7 @@
181
 
182
  {#if isLeader}
183
  <div
184
- class="absolute top-1.5 right-1.5 grid h-5 w-5 place-items-center rounded bg-emerald-500/85 text-white shadow ring-1 ring-black/20"
185
  aria-label="Audio source"
186
  title="Audio source"
187
  >
@@ -191,7 +191,7 @@
191
 
192
  {#if !available}
193
  <div
194
- class="absolute right-1.5 bottom-1.5 grid h-5 w-5 place-items-center rounded bg-rose-500/85 text-white shadow ring-1 ring-black/20"
195
  aria-label="Player is dead"
196
  title="Player is dead"
197
  >
 
143
  aria-disabled={!available}
144
  class={cn(
145
  'group relative aspect-video cursor-pointer overflow-hidden rounded-md border bg-black transition',
146
+ 'aria-disabled:opacity-60 data-[current=false]:border-border data-[current=false]:hover:border-foreground/40',
147
  'data-[current=true]:ring-2 data-[side=CT]:data-[current=true]:border-sky-500 data-[side=CT]:data-[current=true]:ring-sky-500/40',
148
  'data-[side=T]:data-[current=true]:border-amber-500 data-[side=T]:data-[current=true]:ring-amber-500/40'
149
  )}
 
181
 
182
  {#if isLeader}
183
  <div
184
+ class="absolute top-1.5 right-1.5 grid h-5 w-5 place-items-center rounded-sm bg-emerald-500/85 text-white shadow-sm ring-1 ring-black/20"
185
  aria-label="Audio source"
186
  title="Audio source"
187
  >
 
191
 
192
  {#if !available}
193
  <div
194
+ class="absolute right-1.5 bottom-1.5 grid h-5 w-5 place-items-center rounded-sm bg-rose-500/85 text-white shadow-sm ring-1 ring-black/20"
195
  aria-label="Player is dead"
196
  title="Player is dead"
197
  >
src/lib/components/header.svelte CHANGED
@@ -9,11 +9,11 @@
9
  import { site } from '$lib/site';
10
  </script>
11
 
12
- <header class="border-border/60 border-b">
13
  <div class="mx-auto flex h-12 w-full max-w-[1600px] items-center gap-3 px-4">
14
  <a
15
  href="/"
16
- class="text-muted-foreground hover:text-foreground inline-flex items-center gap-1.5 text-xs font-medium transition"
17
  aria-label="Back to dataset home"
18
  >
19
  <CaretLeftIcon size={12} weight="bold" />
 
9
  import { site } from '$lib/site';
10
  </script>
11
 
12
+ <header class="border-b border-border/60">
13
  <div class="mx-auto flex h-12 w-full max-w-[1600px] items-center gap-3 px-4">
14
  <a
15
  href="/"
16
+ class="inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground transition hover:text-foreground"
17
  aria-label="Back to dataset home"
18
  >
19
  <CaretLeftIcon size={12} weight="bold" />
src/lib/components/match-info.svelte CHANGED
@@ -23,19 +23,19 @@
23
 
24
  <div class="space-y-3">
25
  <div>
26
- <div class="text-muted-foreground text-xs tracking-wide uppercase">Event</div>
27
- <div class="font-heading mt-0.5 text-sm font-semibold">{match.event}</div>
28
  </div>
29
 
30
  <div class="border-y py-3">
31
  <div class="grid grid-cols-[1fr_auto_1fr] items-center gap-3">
32
  <div
33
  data-winning={team1Wins}
34
- class="data-[winning=false]:text-muted-foreground text-right text-sm font-medium"
35
  >
36
  {match.team1}
37
  </div>
38
- <div class="font-heading flex items-center gap-1 text-xl font-bold tabular-nums">
39
  <span data-winning={team1Wins} class="data-[winning=true]:text-primary">{match.score1}</span
40
  >
41
  <span class="text-muted-foreground/40">:</span>
@@ -45,7 +45,7 @@
45
  </div>
46
  <div
47
  data-winning={!team1Wins}
48
- class="data-[winning=false]:text-muted-foreground text-left text-sm font-medium"
49
  >
50
  {match.team2}
51
  </div>
@@ -53,7 +53,7 @@
53
  </div>
54
 
55
  <dl class="grid grid-cols-2 gap-x-3 gap-y-2 text-xs">
56
- <dt class="text-muted-foreground inline-flex items-center gap-1">
57
  <MapPinIcon size={12} weight="duotone" /> Map
58
  </dt>
59
  <dd class="text-right">
@@ -62,18 +62,18 @@
62
  </Badge>
63
  </dd>
64
 
65
- <dt class="text-muted-foreground inline-flex items-center gap-1">
66
  <FilmSlateIcon size={12} weight="duotone" /> Format
67
  </dt>
68
  <dd class="text-right font-medium uppercase">{match.format}</dd>
69
 
70
- <dt class="text-muted-foreground inline-flex items-center gap-1">
71
  <CalendarIcon size={12} weight="duotone" /> Played
72
  </dt>
73
  <dd class="text-right font-medium">{formatDateTime(match.match_date)}</dd>
74
 
75
  {#if winnerSide === 'ct' || winnerSide === 't'}
76
- <dt class="text-muted-foreground inline-flex items-center gap-1">
77
  {#if winnerSide === 'ct'}
78
  <ShieldIcon size={12} weight="duotone" />
79
  {:else}
@@ -98,7 +98,7 @@
98
  </dd>
99
  {/if}
100
 
101
- <dt class="text-muted-foreground inline-flex items-center gap-1">
102
  <HashIcon size={12} weight="duotone" /> Rounds
103
  </dt>
104
  <dd class="text-right font-medium tabular-nums">{match.rounds_played}</dd>
@@ -106,7 +106,7 @@
106
 
107
  {#if match.match_url}
108
  <a
109
- class="text-muted-foreground hover:text-foreground inline-flex items-center gap-1 text-xs underline-offset-2 hover:underline"
110
  href={match.match_url}
111
  target="_blank"
112
  rel="noreferrer noopener"
 
23
 
24
  <div class="space-y-3">
25
  <div>
26
+ <div class="text-xs tracking-wide text-muted-foreground uppercase">Event</div>
27
+ <div class="mt-0.5 font-heading text-sm font-semibold">{match.event}</div>
28
  </div>
29
 
30
  <div class="border-y py-3">
31
  <div class="grid grid-cols-[1fr_auto_1fr] items-center gap-3">
32
  <div
33
  data-winning={team1Wins}
34
+ class="text-right text-sm font-medium data-[winning=false]:text-muted-foreground"
35
  >
36
  {match.team1}
37
  </div>
38
+ <div class="flex items-center gap-1 font-heading text-xl font-bold tabular-nums">
39
  <span data-winning={team1Wins} class="data-[winning=true]:text-primary">{match.score1}</span
40
  >
41
  <span class="text-muted-foreground/40">:</span>
 
45
  </div>
46
  <div
47
  data-winning={!team1Wins}
48
+ class="text-left text-sm font-medium data-[winning=false]:text-muted-foreground"
49
  >
50
  {match.team2}
51
  </div>
 
53
  </div>
54
 
55
  <dl class="grid grid-cols-2 gap-x-3 gap-y-2 text-xs">
56
+ <dt class="inline-flex items-center gap-1 text-muted-foreground">
57
  <MapPinIcon size={12} weight="duotone" /> Map
58
  </dt>
59
  <dd class="text-right">
 
62
  </Badge>
63
  </dd>
64
 
65
+ <dt class="inline-flex items-center gap-1 text-muted-foreground">
66
  <FilmSlateIcon size={12} weight="duotone" /> Format
67
  </dt>
68
  <dd class="text-right font-medium uppercase">{match.format}</dd>
69
 
70
+ <dt class="inline-flex items-center gap-1 text-muted-foreground">
71
  <CalendarIcon size={12} weight="duotone" /> Played
72
  </dt>
73
  <dd class="text-right font-medium">{formatDateTime(match.match_date)}</dd>
74
 
75
  {#if winnerSide === 'ct' || winnerSide === 't'}
76
+ <dt class="inline-flex items-center gap-1 text-muted-foreground">
77
  {#if winnerSide === 'ct'}
78
  <ShieldIcon size={12} weight="duotone" />
79
  {:else}
 
98
  </dd>
99
  {/if}
100
 
101
+ <dt class="inline-flex items-center gap-1 text-muted-foreground">
102
  <HashIcon size={12} weight="duotone" /> Rounds
103
  </dt>
104
  <dd class="text-right font-medium tabular-nums">{match.rounds_played}</dd>
 
106
 
107
  {#if match.match_url}
108
  <a
109
+ class="inline-flex items-center gap-1 text-xs text-muted-foreground underline-offset-2 hover:text-foreground hover:underline"
110
  href={match.match_url}
111
  target="_blank"
112
  rel="noreferrer noopener"
src/lib/components/match-map.svelte CHANGED
@@ -76,7 +76,7 @@
76
  </script>
77
 
78
  {#if error}
79
- <div class="text-muted-foreground bg-muted/30 rounded-md border p-3 text-xs">
80
  Map data unavailable: {error}
81
  </div>
82
  {:else if !world}
 
76
  </script>
77
 
78
  {#if error}
79
+ <div class="rounded-md border bg-muted/30 p-3 text-xs text-muted-foreground">
80
  Map data unavailable: {error}
81
  </div>
82
  {:else if !world}
src/lib/components/match-table/cells/date-cell.svelte CHANGED
@@ -7,4 +7,4 @@
7
  let { iso }: Props = $props();
8
  </script>
9
 
10
- <span class="text-muted-foreground text-xs whitespace-nowrap">{formatDate(iso)}</span>
 
7
  let { iso }: Props = $props();
8
  </script>
9
 
10
+ <span class="text-xs whitespace-nowrap text-muted-foreground">{formatDate(iso)}</span>
src/lib/components/match-table/cells/duration-cell.svelte CHANGED
@@ -7,6 +7,6 @@
7
  let { seconds }: Props = $props();
8
  </script>
9
 
10
- <span class="text-muted-foreground font-mono text-xs tabular-nums"
11
  >{formatLongDuration(seconds)}</span
12
  >
 
7
  let { seconds }: Props = $props();
8
  </script>
9
 
10
+ <span class="font-mono text-xs text-muted-foreground tabular-nums"
11
  >{formatLongDuration(seconds)}</span
12
  >
src/lib/components/match-table/cells/event-cell.svelte CHANGED
@@ -9,6 +9,6 @@
9
  <div class="flex min-w-0 flex-col">
10
  <span class="truncate text-sm font-medium" title={event}>{event}</span>
11
  {#if format}
12
- <span class="text-muted-foreground/70 text-[0.65rem] tracking-wide uppercase">{format}</span>
13
  {/if}
14
  </div>
 
9
  <div class="flex min-w-0 flex-col">
10
  <span class="truncate text-sm font-medium" title={event}>{event}</span>
11
  {#if format}
12
+ <span class="text-[0.65rem] tracking-wide text-muted-foreground/70 uppercase">{format}</span>
13
  {/if}
14
  </div>
src/lib/components/match-table/cells/rounds-played-cell.svelte CHANGED
@@ -7,7 +7,7 @@
7
  let { rounds }: Props = $props();
8
  </script>
9
 
10
- <span class="text-muted-foreground inline-flex items-center gap-1 font-mono text-xs tabular-nums">
11
  <FilmSlateIcon size={11} weight="duotone" />
12
  {rounds}
13
  </span>
 
7
  let { rounds }: Props = $props();
8
  </script>
9
 
10
+ <span class="inline-flex items-center gap-1 font-mono text-xs text-muted-foreground tabular-nums">
11
  <FilmSlateIcon size={11} weight="duotone" />
12
  {rounds}
13
  </span>
src/lib/components/match-table/cells/score-cell.svelte CHANGED
@@ -10,14 +10,14 @@
10
  <div class="flex items-center justify-center gap-1 font-mono text-sm tabular-nums">
11
  <span
12
  data-winner={winner === 'team1'}
13
- class="text-muted-foreground data-[winner=true]:text-primary data-[winner=true]:font-semibold"
14
  >
15
  {score1}
16
  </span>
17
- <span class="text-muted-foreground/40 text-xs">:</span>
18
  <span
19
  data-winner={winner === 'team2'}
20
- class="text-muted-foreground data-[winner=true]:text-primary data-[winner=true]:font-semibold"
21
  >
22
  {score2}
23
  </span>
 
10
  <div class="flex items-center justify-center gap-1 font-mono text-sm tabular-nums">
11
  <span
12
  data-winner={winner === 'team1'}
13
+ class="text-muted-foreground data-[winner=true]:font-semibold data-[winner=true]:text-primary"
14
  >
15
  {score1}
16
  </span>
17
+ <span class="text-xs text-muted-foreground/40">:</span>
18
  <span
19
  data-winner={winner === 'team2'}
20
+ class="text-muted-foreground data-[winner=true]:font-semibold data-[winner=true]:text-primary"
21
  >
22
  {score2}
23
  </span>
src/lib/components/match-table/cells/teams-cell.svelte CHANGED
@@ -20,7 +20,7 @@
20
  >
21
  {team1}
22
  </span>
23
- <span class="text-muted-foreground/40 shrink-0">vs</span>
24
  <span
25
  data-winning={team2Wins}
26
  class={cn('truncate font-medium', 'data-[winning=false]:text-muted-foreground')}
 
20
  >
21
  {team1}
22
  </span>
23
+ <span class="shrink-0 text-muted-foreground/40">vs</span>
24
  <span
25
  data-winning={team2Wins}
26
  class={cn('truncate font-medium', 'data-[winning=false]:text-muted-foreground')}
src/lib/components/match-table/cells/winner-side-cell.svelte CHANGED
@@ -22,5 +22,5 @@
22
  <SwordIcon size={11} weight="duotone" /> T
23
  </Badge>
24
  {:else}
25
- <span class="text-muted-foreground/60 text-xs">—</span>
26
  {/if}
 
22
  <SwordIcon size={11} weight="duotone" /> T
23
  </Badge>
24
  {:else}
25
+ <span class="text-xs text-muted-foreground/60">—</span>
26
  {/if}
src/lib/components/match-table/columns.ts CHANGED
@@ -16,7 +16,6 @@ import type { MapRow, MatchRow, RoundRow } from './rows';
16
  import type { Match } from '$lib/types';
17
 
18
  declare module '@tanstack/table-core' {
19
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
20
  interface ColumnMeta<TData extends RowData, TValue> {
21
  label?: string;
22
  }
 
16
  import type { Match } from '$lib/types';
17
 
18
  declare module '@tanstack/table-core' {
 
19
  interface ColumnMeta<TData extends RowData, TValue> {
20
  label?: string;
21
  }
src/lib/components/match-table/data-table-plain-header.svelte CHANGED
@@ -12,7 +12,7 @@
12
 
13
  <span
14
  class={cn(
15
- 'text-muted-foreground inline-block px-2 text-[0.7rem] font-medium tracking-wide uppercase',
16
  align === 'end' && 'w-full text-right',
17
  className
18
  )}
 
12
 
13
  <span
14
  class={cn(
15
+ 'inline-block px-2 text-[0.7rem] font-medium tracking-wide text-muted-foreground uppercase',
16
  align === 'end' && 'w-full text-right',
17
  className
18
  )}
src/lib/components/match-table/data-table-sort-header.svelte CHANGED
@@ -29,7 +29,7 @@
29
  size="sm"
30
  onclick={() => column.toggleSorting(sort === 'asc')}
31
  class={cn(
32
- 'text-muted-foreground hover:text-foreground -ml-2 h-7 px-2 text-[0.7rem] font-medium tracking-wide uppercase',
33
  align === 'end' && '-mr-2 ml-0 w-full justify-end',
34
  className
35
  )}
 
29
  size="sm"
30
  onclick={() => column.toggleSorting(sort === 'asc')}
31
  class={cn(
32
+ '-ml-2 h-7 px-2 text-[0.7rem] font-medium tracking-wide text-muted-foreground uppercase hover:text-foreground',
33
  align === 'end' && '-mr-2 ml-0 w-full justify-end',
34
  className
35
  )}
src/lib/components/match-table/data-table-toolbar.svelte CHANGED
@@ -30,7 +30,7 @@
30
  <MagnifyingGlassIcon
31
  size={14}
32
  weight="bold"
33
- class="text-muted-foreground absolute top-1/2 left-2.5 -translate-y-1/2"
34
  />
35
  <Input
36
  placeholder={searchPlaceholder}
 
30
  <MagnifyingGlassIcon
31
  size={14}
32
  weight="bold"
33
+ class="absolute top-1/2 left-2.5 -translate-y-1/2 text-muted-foreground"
34
  />
35
  <Input
36
  placeholder={searchPlaceholder}
src/lib/components/match-table/match-table.svelte CHANGED
@@ -162,7 +162,7 @@
162
  <Table.Row>
163
  <Table.Cell
164
  colspan={columns.length}
165
- class="text-muted-foreground h-24 text-center text-sm"
166
  >
167
  {emptyMessage}
168
  </Table.Cell>
 
162
  <Table.Row>
163
  <Table.Cell
164
  colspan={columns.length}
165
+ class="h-24 text-center text-sm text-muted-foreground"
166
  >
167
  {emptyMessage}
168
  </Table.Cell>
src/lib/components/perspective-grid.svelte CHANGED
@@ -107,7 +107,7 @@
107
  }
108
  </script>
109
 
110
- <div class="bg-card max-h-[80vh] overflow-y-auto rounded-lg border shadow-sm">
111
  <div class="space-y-4 p-3">
112
  {#if ctPlayers.length}
113
  <div>
 
107
  }
108
  </script>
109
 
110
+ <div class="max-h-[80vh] overflow-y-auto rounded-lg border bg-card shadow-sm">
111
  <div class="space-y-4 p-3">
112
  {#if ctPlayers.length}
113
  <div>
src/lib/components/player-grid.svelte CHANGED
@@ -80,10 +80,10 @@
80
  disabled={!available}
81
  class={cn(
82
  'group flex h-auto min-w-0 flex-1 basis-0 items-center justify-start gap-2 rounded-md border px-2 py-1.5 text-left text-sm transition',
83
- 'data-[state=on]:bg-accent data-[state=on]:text-accent-foreground disabled:cursor-not-allowed disabled:opacity-40 data-[state=on]:border-current',
84
- 'data-[side=ct]:data-[state=on]:text-foreground data-[side=ct]:data-[state=on]:border-sky-500 data-[side=ct]:data-[state=on]:bg-sky-500/10',
85
- 'data-[side=t]:data-[state=on]:text-foreground data-[side=t]:data-[state=on]:border-amber-500 data-[side=t]:data-[state=on]:bg-amber-500/10',
86
- 'data-[ready=true]:ring-offset-background data-[ready=true]:ring-2 data-[ready=true]:ring-emerald-500/60 data-[ready=true]:ring-offset-1'
87
  )}
88
  >
89
  <span
@@ -95,7 +95,7 @@
95
  <div class="min-w-0 flex-1">
96
  <div class="truncate font-medium">Player {p.player}</div>
97
  {#if !available}
98
- <div class="text-muted-foreground text-[10px] tabular-nums">
99
  died · {formatDuration(p.duration)}
100
  </div>
101
  {/if}
@@ -110,11 +110,11 @@
110
 
111
  <div class="space-y-2">
112
  <div class="flex items-center justify-between gap-3">
113
- <div class="text-muted-foreground text-xs tracking-wide uppercase">Player perspectives</div>
114
  <div class="flex items-center gap-2">
115
  <Label
116
  for="preload-all-players"
117
- class="text-muted-foreground text-[11px] tracking-wide uppercase"
118
  >
119
  Preload all
120
  </Label>
 
80
  disabled={!available}
81
  class={cn(
82
  'group flex h-auto min-w-0 flex-1 basis-0 items-center justify-start gap-2 rounded-md border px-2 py-1.5 text-left text-sm transition',
83
+ 'disabled:cursor-not-allowed disabled:opacity-40 data-[state=on]:border-current data-[state=on]:bg-accent data-[state=on]:text-accent-foreground',
84
+ 'data-[side=ct]:data-[state=on]:border-sky-500 data-[side=ct]:data-[state=on]:bg-sky-500/10 data-[side=ct]:data-[state=on]:text-foreground',
85
+ 'data-[side=t]:data-[state=on]:border-amber-500 data-[side=t]:data-[state=on]:bg-amber-500/10 data-[side=t]:data-[state=on]:text-foreground',
86
+ 'data-[ready=true]:ring-2 data-[ready=true]:ring-emerald-500/60 data-[ready=true]:ring-offset-1 data-[ready=true]:ring-offset-background'
87
  )}
88
  >
89
  <span
 
95
  <div class="min-w-0 flex-1">
96
  <div class="truncate font-medium">Player {p.player}</div>
97
  {#if !available}
98
+ <div class="text-[10px] text-muted-foreground tabular-nums">
99
  died · {formatDuration(p.duration)}
100
  </div>
101
  {/if}
 
110
 
111
  <div class="space-y-2">
112
  <div class="flex items-center justify-between gap-3">
113
+ <div class="text-xs tracking-wide text-muted-foreground uppercase">Player perspectives</div>
114
  <div class="flex items-center gap-2">
115
  <Label
116
  for="preload-all-players"
117
+ class="text-[11px] tracking-wide text-muted-foreground uppercase"
118
  >
119
  Preload all
120
  </Label>
src/lib/components/round-list.svelte CHANGED
@@ -29,9 +29,9 @@
29
 
30
  <div class="flex h-full min-h-0 flex-col">
31
  <div
32
- class="text-muted-foreground border-b px-2 py-2 text-[10px] font-semibold tracking-wide uppercase"
33
  >
34
- Rounds <span class="text-muted-foreground/50 ml-1">({rounds.length})</span>
35
  </div>
36
  <ScrollArea class="min-h-0 flex-1">
37
  <ToggleGroup.Root
@@ -47,12 +47,12 @@
47
  {#each rounds as r, i (r.round)}
48
  {#if i > 0 && isSideSwitchBefore(r.round)}
49
  <div
50
- class="text-muted-foreground/70 my-0.5 flex items-center gap-1.5 px-1 text-[9px] font-semibold tracking-wider uppercase"
51
  aria-hidden="true"
52
  >
53
- <span class="bg-border h-px flex-1"></span>
54
  <span>{switchLabel(r.round)}</span>
55
- <span class="bg-border h-px flex-1"></span>
56
  </div>
57
  {/if}
58
  <ToggleGroup.Item
 
29
 
30
  <div class="flex h-full min-h-0 flex-col">
31
  <div
32
+ class="border-b px-2 py-2 text-[10px] font-semibold tracking-wide text-muted-foreground uppercase"
33
  >
34
+ Rounds <span class="ml-1 text-muted-foreground/50">({rounds.length})</span>
35
  </div>
36
  <ScrollArea class="min-h-0 flex-1">
37
  <ToggleGroup.Root
 
47
  {#each rounds as r, i (r.round)}
48
  {#if i > 0 && isSideSwitchBefore(r.round)}
49
  <div
50
+ class="my-0.5 flex items-center gap-1.5 px-1 text-[9px] font-semibold tracking-wider text-muted-foreground/70 uppercase"
51
  aria-hidden="true"
52
  >
53
+ <span class="h-px flex-1 bg-border"></span>
54
  <span>{switchLabel(r.round)}</span>
55
+ <span class="h-px flex-1 bg-border"></span>
56
  </div>
57
  {/if}
58
  <ToggleGroup.Item
src/lib/components/timeline-bar.svelte CHANGED
@@ -42,7 +42,7 @@
42
  data-disabled={disabled || undefined}
43
  aria-disabled={disabled}
44
  class={cn(
45
- 'bg-card flex items-center gap-3 rounded-lg border px-3 py-2 shadow-sm',
46
  'data-[disabled]:pointer-events-none data-[disabled]:opacity-60'
47
  )}
48
  >
@@ -60,7 +60,7 @@
60
  {/if}
61
  </Button>
62
 
63
- <span class="text-foreground w-12 text-right font-mono text-[11px] tabular-nums">
64
  {formatDuration(currentTime)}
65
  </span>
66
 
@@ -68,7 +68,7 @@
68
  <Playbar {currentTime} {duration} {bufferedRanges} {onSeek} {onScrubStart} {onScrubEnd} />
69
  </div>
70
 
71
- <span class="text-muted-foreground w-12 font-mono text-[11px] tabular-nums">
72
  {formatDuration(duration)}
73
  </span>
74
 
 
42
  data-disabled={disabled || undefined}
43
  aria-disabled={disabled}
44
  class={cn(
45
+ 'flex items-center gap-3 rounded-lg border bg-card px-3 py-2 shadow-sm',
46
  'data-[disabled]:pointer-events-none data-[disabled]:opacity-60'
47
  )}
48
  >
 
60
  {/if}
61
  </Button>
62
 
63
+ <span class="w-12 text-right font-mono text-[11px] text-foreground tabular-nums">
64
  {formatDuration(currentTime)}
65
  </span>
66
 
 
68
  <Playbar {currentTime} {duration} {bufferedRanges} {onSeek} {onScrubStart} {onScrubEnd} />
69
  </div>
70
 
71
+ <span class="w-12 font-mono text-[11px] text-muted-foreground tabular-nums">
72
  {formatDuration(duration)}
73
  </span>
74
 
src/lib/components/video-player/playbar.svelte CHANGED
@@ -109,26 +109,26 @@
109
  onkeydown={onKeyDown}
110
  >
111
  <div
112
- class="bg-muted absolute inset-x-0 top-1/2 h-1 -translate-y-1/2 overflow-hidden rounded-full"
113
  >
114
  {#each bufferedRanges as range, i (i)}
115
  {@const left = (Math.max(0, range.start) / safeDuration) * 100}
116
  {@const width = (Math.max(0, range.end - range.start) / safeDuration) * 100}
117
  {#if width > 0}
118
  <div
119
- class="bg-muted-foreground/40 absolute inset-y-0"
120
  style:left="{left}%"
121
  style:width="{width}%"
122
  ></div>
123
  {/if}
124
  {/each}
125
- <div class="bg-primary absolute inset-y-0 left-0" style:width="{visiblePct}%"></div>
126
  </div>
127
 
128
  <div
129
  data-dragging={isDragging}
130
  class={cn(
131
- 'bg-primary absolute top-1/2 size-3 -translate-x-1/2 -translate-y-1/2 rounded-full opacity-0 transition-opacity',
132
  'group-hover/playbar:opacity-100 data-[dragging=true]:opacity-100'
133
  )}
134
  style:left="{visiblePct}%"
@@ -136,7 +136,7 @@
136
 
137
  {#if hoverPercent != null && duration > 0}
138
  <div
139
- class="bg-foreground text-background pointer-events-none absolute -top-7 -translate-x-1/2 rounded px-1.5 py-0.5 font-mono text-[10px] tabular-nums shadow"
140
  style:left="{hoverPercent * 100}%"
141
  >
142
  {formatDuration(hoverPercent * duration)}
 
109
  onkeydown={onKeyDown}
110
  >
111
  <div
112
+ class="absolute inset-x-0 top-1/2 h-1 -translate-y-1/2 overflow-hidden rounded-full bg-muted"
113
  >
114
  {#each bufferedRanges as range, i (i)}
115
  {@const left = (Math.max(0, range.start) / safeDuration) * 100}
116
  {@const width = (Math.max(0, range.end - range.start) / safeDuration) * 100}
117
  {#if width > 0}
118
  <div
119
+ class="absolute inset-y-0 bg-muted-foreground/40"
120
  style:left="{left}%"
121
  style:width="{width}%"
122
  ></div>
123
  {/if}
124
  {/each}
125
+ <div class="absolute inset-y-0 left-0 bg-primary" style:width="{visiblePct}%"></div>
126
  </div>
127
 
128
  <div
129
  data-dragging={isDragging}
130
  class={cn(
131
+ 'absolute top-1/2 size-3 -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary opacity-0 transition-opacity',
132
  'group-hover/playbar:opacity-100 data-[dragging=true]:opacity-100'
133
  )}
134
  style:left="{visiblePct}%"
 
136
 
137
  {#if hoverPercent != null && duration > 0}
138
  <div
139
+ class="pointer-events-none absolute -top-7 -translate-x-1/2 rounded-sm bg-foreground px-1.5 py-0.5 font-mono text-[10px] text-background tabular-nums shadow-sm"
140
  style:left="{hoverPercent * 100}%"
141
  >
142
  {formatDuration(hoverPercent * duration)}
src/lib/components/video-player/video-player.svelte CHANGED
@@ -336,7 +336,7 @@
336
  aria-label="Play"
337
  onclick={togglePlay}
338
  >
339
- <span class="bg-primary text-primary-foreground rounded-full p-4 shadow-lg">
340
  <PlayIcon size={28} weight="fill" />
341
  </span>
342
  </button>
 
336
  aria-label="Play"
337
  onclick={togglePlay}
338
  >
339
+ <span class="rounded-full bg-primary p-4 text-primary-foreground shadow-lg">
340
  <PlayIcon size={28} weight="fill" />
341
  </span>
342
  </button>
src/lib/components/video-stage.svelte CHANGED
@@ -79,11 +79,11 @@
79
  });
80
  </script>
81
 
82
- <div class="bg-card overflow-hidden rounded-lg border shadow-sm">
83
  <AspectRatio ratio={16 / 9} class="bg-black">
84
  {#if loading}
85
  <Skeleton class="h-full w-full rounded-none" />
86
- <div class="text-muted-foreground absolute inset-0 flex items-center justify-center">
87
  <div class="text-center">
88
  <SpinnerIcon size={32} weight="duotone" class="mx-auto mb-2 animate-spin opacity-70" />
89
  <p class="text-sm">Loading clip…</p>
@@ -91,17 +91,17 @@
91
  </div>
92
  {:else if error}
93
  <div
94
- class="text-muted-foreground absolute inset-0 flex items-center justify-center bg-black/40"
95
  >
96
  <div class="max-w-sm px-6 text-center">
97
- <WarningCircleIcon size={32} weight="duotone" class="text-destructive mx-auto mb-2" />
98
- <p class="text-foreground text-sm font-medium">Couldn't load clip</p>
99
- <p class="text-muted-foreground mt-1 text-xs break-words">{error}</p>
100
  </div>
101
  </div>
102
  {:else if !chunks.length}
103
  <div
104
- class="text-muted-foreground absolute inset-0 flex items-center justify-center bg-black/40"
105
  >
106
  <div class="text-center">
107
  <CrosshairIcon size={32} weight="duotone" class="mx-auto mb-2 opacity-50" />
 
79
  });
80
  </script>
81
 
82
+ <div class="overflow-hidden rounded-lg border bg-card shadow-sm">
83
  <AspectRatio ratio={16 / 9} class="bg-black">
84
  {#if loading}
85
  <Skeleton class="h-full w-full rounded-none" />
86
+ <div class="absolute inset-0 flex items-center justify-center text-muted-foreground">
87
  <div class="text-center">
88
  <SpinnerIcon size={32} weight="duotone" class="mx-auto mb-2 animate-spin opacity-70" />
89
  <p class="text-sm">Loading clip…</p>
 
91
  </div>
92
  {:else if error}
93
  <div
94
+ class="absolute inset-0 flex items-center justify-center bg-black/40 text-muted-foreground"
95
  >
96
  <div class="max-w-sm px-6 text-center">
97
+ <WarningCircleIcon size={32} weight="duotone" class="mx-auto mb-2 text-destructive" />
98
+ <p class="text-sm font-medium text-foreground">Couldn't load clip</p>
99
+ <p class="mt-1 text-xs break-words text-muted-foreground">{error}</p>
100
  </div>
101
  </div>
102
  {:else if !chunks.length}
103
  <div
104
+ class="absolute inset-0 flex items-center justify-center bg-black/40 text-muted-foreground"
105
  >
106
  <div class="text-center">
107
  <CrosshairIcon size={32} weight="duotone" class="mx-auto mb-2 opacity-50" />
src/routes/+layout.svelte CHANGED
@@ -56,7 +56,7 @@
56
  <Toaster richColors position="bottom-right" />
57
 
58
  <Tooltip.Provider delayDuration={250}>
59
- <div class="bg-background text-foreground min-h-screen">
60
  {@render children()}
61
  </div>
62
  </Tooltip.Provider>
 
56
  <Toaster richColors position="bottom-right" />
57
 
58
  <Tooltip.Provider delayDuration={250}>
59
+ <div class="min-h-screen bg-background text-foreground">
60
  {@render children()}
61
  </div>
62
  </Tooltip.Provider>
src/routes/+page.svelte CHANGED
@@ -99,20 +99,20 @@
99
  <main class="mx-auto w-full max-w-[1600px] px-4 pb-16">
100
  <!-- Paper-style hero -->
101
  <section class="mx-auto max-w-3xl pt-16 pb-10 text-center md:pt-24">
102
- <div class="text-primary/70 mb-3 text-xs font-semibold tracking-[0.2em] uppercase">
103
  HLTV · CS2 · Rendered POV Dataset
104
  </div>
105
  <h1 class="font-heading text-4xl font-semibold tracking-tight text-balance md:text-5xl">
106
  Counter Strike 2 Dataset
107
  </h1>
108
- <div class="text-muted-foreground mt-5 flex items-center justify-center gap-3 text-sm">
109
- <span class="text-foreground font-medium">{site.author}</span>
110
  <a
111
  href={site.websiteUrl}
112
  target="_blank"
113
  rel="noreferrer noopener"
114
  aria-label="Personal website"
115
- class="hover:text-foreground inline-flex items-center transition"
116
  >
117
  <GlobeIcon size={16} weight="duotone" />
118
  </a>
@@ -121,7 +121,7 @@
121
  target="_blank"
122
  rel="noreferrer noopener"
123
  aria-label="X / Twitter"
124
- class="hover:text-foreground inline-flex items-center transition"
125
  >
126
  <XLogoIcon size={14} weight="fill" />
127
  </a>
@@ -151,7 +151,7 @@
151
  </Button>
152
  </div>
153
 
154
- <p class="text-muted-foreground mt-8 text-sm leading-relaxed text-pretty md:text-base">
155
  A rendered dataset of professional Counter Strike 2 matches: every round captured from all ten
156
  player POVs, frame-aligned, with spatialized audio, mouse/keyboard inputs, and per-tick world
157
  state. Built from HLTV demos, served as parquet shards, and browsable here without downloading
@@ -162,23 +162,23 @@
162
  <!-- Motivation -->
163
  <section class="mx-auto max-w-5xl border-y py-10">
164
  <h2
165
- class="font-heading text-muted-foreground text-center text-xs font-semibold tracking-[0.2em] uppercase"
166
  >
167
  Motivation
168
  </h2>
169
- <p class="text-muted-foreground mx-auto mt-3 max-w-2xl text-center text-sm leading-relaxed">
170
  Pro CS2 demos are a goldmine of expert sequential decision-making — long horizons, partial
171
  observability, dense visual signal, and 5v5 multi-agent dynamics. This dataset turns them into
172
  trainable rendered video.
173
  </p>
174
  <div class="mt-8 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-5">
175
  {#each motivations as m (m.title)}
176
- <div class="bg-card rounded-md border p-3">
177
- <m.icon size={18} weight="duotone" class="text-foreground/80 mb-2" />
178
  <div class="font-heading text-sm font-semibold tracking-tight">
179
  {m.title}
180
  </div>
181
- <p class="text-muted-foreground mt-1 text-xs leading-relaxed">
182
  {m.body}
183
  </p>
184
  </div>
@@ -189,52 +189,52 @@
189
  <!-- Recordings: what's in each chunk -->
190
  <section class="mx-auto max-w-5xl pt-10">
191
  <h2
192
- class="font-heading text-muted-foreground text-center text-xs font-semibold tracking-[0.2em] uppercase"
193
  >
194
  What's recorded
195
  </h2>
196
  <div class="mt-6 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
197
- <div class="bg-card rounded-md border p-3">
198
- <div class="text-muted-foreground text-[10px] font-semibold tracking-wider uppercase">
199
  Video
200
  </div>
201
- <div class="font-heading mt-1 text-sm font-semibold">1280×720 · 32 fps</div>
202
- <p class="text-muted-foreground mt-1 text-xs leading-relaxed">
203
  Near-lossless H.264, one stream per player POV. 10 streams per round, all tick-aligned.
204
  </p>
205
  </div>
206
- <div class="bg-card rounded-md border p-3">
207
- <div class="text-muted-foreground text-[10px] font-semibold tracking-wider uppercase">
208
  Inputs
209
  </div>
210
- <div class="font-heading mt-1 text-sm font-semibold">Keyboard + mouse</div>
211
- <p class="text-muted-foreground mt-1 text-xs leading-relaxed">
212
  Per-tick keystrokes, mouse delta, fire/jump/use, weapon switches — the actions a policy
213
  has to predict.
214
  </p>
215
  </div>
216
- <div class="bg-card rounded-md border p-3">
217
- <div class="text-muted-foreground text-[10px] font-semibold tracking-wider uppercase">
218
  World state
219
  </div>
220
- <div class="font-heading mt-1 text-sm font-semibold">Per-tick game state</div>
221
- <p class="text-muted-foreground mt-1 text-xs leading-relaxed">
222
  Positions, velocities, camera intrinsics, health, armor, ammo, weapons — for all 10
223
  players, every tick.
224
  </p>
225
  </div>
226
- <div class="bg-card rounded-md border p-3">
227
- <div class="text-muted-foreground text-[10px] font-semibold tracking-wider uppercase">
228
  G-buffers <span class="text-amber-600 dark:text-amber-400">· soon</span>
229
  </div>
230
- <div class="font-heading mt-1 text-sm font-semibold">Luminance · depth · vertex IDs</div>
231
- <p class="text-muted-foreground mt-1 text-xs leading-relaxed">
232
  Per-pixel auxiliary channels for self-supervised pretraining and dense prediction heads.
233
  </p>
234
  </div>
235
  </div>
236
  <p
237
- class="text-muted-foreground/80 mx-auto mt-4 max-w-2xl text-center text-[11px] leading-relaxed"
238
  >
239
  Every signal — video, audio, inputs, world state — is sampled on the same CS2 tick clock. No
240
  drift, no resampling artifacts.
@@ -244,31 +244,31 @@
244
  <!-- Stats -->
245
  <section class="mx-auto max-w-5xl pt-10">
246
  <div class="grid grid-cols-2 gap-3 sm:grid-cols-4">
247
- <div class="bg-card rounded-md border p-3">
248
- <div class="text-muted-foreground text-xs tracking-wide uppercase">Matches</div>
249
- <div class="font-heading mt-0.5 text-2xl tabular-nums">
250
  {totalMatches}
251
  </div>
252
  </div>
253
- <div class="bg-card rounded-md border p-3">
254
- <div class="text-muted-foreground text-xs tracking-wide uppercase">Maps rendered</div>
255
- <div class="font-heading mt-0.5 text-2xl tabular-nums">
256
- {totalMaps}<span class="text-muted-foreground/60 text-base font-medium"
257
  >/{TARGET_MAPS}</span
258
  >
259
  </div>
260
  </div>
261
- <div class="bg-card rounded-md border p-3">
262
- <div class="text-muted-foreground text-xs tracking-wide uppercase">Rounds</div>
263
- <div class="font-heading mt-0.5 text-2xl tabular-nums">
264
  {totalRounds}
265
  </div>
266
  </div>
267
- <div class="bg-card rounded-md border p-3">
268
- <div class="text-muted-foreground text-xs tracking-wide uppercase">Footage</div>
269
- <div class="font-heading mt-0.5 text-2xl tabular-nums">
270
  {totalHours < 1 ? totalHours.toFixed(1) : Math.round(totalHours)}<span
271
- class="text-muted-foreground/60 text-base font-medium">h/{TARGET_HOURS}h</span
272
  >
273
  </div>
274
  </div>
@@ -333,12 +333,12 @@
333
  <!-- Citation -->
334
  <section class="mx-auto mt-16 max-w-3xl">
335
  <h2
336
- class="font-heading text-muted-foreground text-center text-xs font-semibold tracking-[0.2em] uppercase"
337
  >
338
  BibTeX
339
  </h2>
340
  <pre
341
- class="bg-card text-foreground/90 mt-3 overflow-x-auto rounded-md border p-4 text-left font-mono text-xs leading-relaxed">{`@misc{blanchon2026cs2dataset,
342
  author = {Julien Blanchon},
343
  title = {Counter Strike 2 Dataset},
344
  year = {2026},
@@ -349,7 +349,7 @@
349
 
350
  <!-- Footer -->
351
  <footer
352
- class="text-muted-foreground mt-10 flex flex-col items-center gap-2 border-t pt-6 text-xs"
353
  >
354
  <div class="flex flex-wrap justify-center gap-4">
355
  <a
 
99
  <main class="mx-auto w-full max-w-[1600px] px-4 pb-16">
100
  <!-- Paper-style hero -->
101
  <section class="mx-auto max-w-3xl pt-16 pb-10 text-center md:pt-24">
102
+ <div class="mb-3 text-xs font-semibold tracking-[0.2em] text-primary/70 uppercase">
103
  HLTV · CS2 · Rendered POV Dataset
104
  </div>
105
  <h1 class="font-heading text-4xl font-semibold tracking-tight text-balance md:text-5xl">
106
  Counter Strike 2 Dataset
107
  </h1>
108
+ <div class="mt-5 flex items-center justify-center gap-3 text-sm text-muted-foreground">
109
+ <span class="font-medium text-foreground">{site.author}</span>
110
  <a
111
  href={site.websiteUrl}
112
  target="_blank"
113
  rel="noreferrer noopener"
114
  aria-label="Personal website"
115
+ class="inline-flex items-center transition hover:text-foreground"
116
  >
117
  <GlobeIcon size={16} weight="duotone" />
118
  </a>
 
121
  target="_blank"
122
  rel="noreferrer noopener"
123
  aria-label="X / Twitter"
124
+ class="inline-flex items-center transition hover:text-foreground"
125
  >
126
  <XLogoIcon size={14} weight="fill" />
127
  </a>
 
151
  </Button>
152
  </div>
153
 
154
+ <p class="mt-8 text-sm leading-relaxed text-pretty text-muted-foreground md:text-base">
155
  A rendered dataset of professional Counter Strike 2 matches: every round captured from all ten
156
  player POVs, frame-aligned, with spatialized audio, mouse/keyboard inputs, and per-tick world
157
  state. Built from HLTV demos, served as parquet shards, and browsable here without downloading
 
162
  <!-- Motivation -->
163
  <section class="mx-auto max-w-5xl border-y py-10">
164
  <h2
165
+ class="text-center font-heading text-xs font-semibold tracking-[0.2em] text-muted-foreground uppercase"
166
  >
167
  Motivation
168
  </h2>
169
+ <p class="mx-auto mt-3 max-w-2xl text-center text-sm leading-relaxed text-muted-foreground">
170
  Pro CS2 demos are a goldmine of expert sequential decision-making — long horizons, partial
171
  observability, dense visual signal, and 5v5 multi-agent dynamics. This dataset turns them into
172
  trainable rendered video.
173
  </p>
174
  <div class="mt-8 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-5">
175
  {#each motivations as m (m.title)}
176
+ <div class="rounded-md border bg-card p-3">
177
+ <m.icon size={18} weight="duotone" class="mb-2 text-foreground/80" />
178
  <div class="font-heading text-sm font-semibold tracking-tight">
179
  {m.title}
180
  </div>
181
+ <p class="mt-1 text-xs leading-relaxed text-muted-foreground">
182
  {m.body}
183
  </p>
184
  </div>
 
189
  <!-- Recordings: what's in each chunk -->
190
  <section class="mx-auto max-w-5xl pt-10">
191
  <h2
192
+ class="text-center font-heading text-xs font-semibold tracking-[0.2em] text-muted-foreground uppercase"
193
  >
194
  What's recorded
195
  </h2>
196
  <div class="mt-6 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
197
+ <div class="rounded-md border bg-card p-3">
198
+ <div class="text-[10px] font-semibold tracking-wider text-muted-foreground uppercase">
199
  Video
200
  </div>
201
+ <div class="mt-1 font-heading text-sm font-semibold">1280×720 · 32 fps</div>
202
+ <p class="mt-1 text-xs leading-relaxed text-muted-foreground">
203
  Near-lossless H.264, one stream per player POV. 10 streams per round, all tick-aligned.
204
  </p>
205
  </div>
206
+ <div class="rounded-md border bg-card p-3">
207
+ <div class="text-[10px] font-semibold tracking-wider text-muted-foreground uppercase">
208
  Inputs
209
  </div>
210
+ <div class="mt-1 font-heading text-sm font-semibold">Keyboard + mouse</div>
211
+ <p class="mt-1 text-xs leading-relaxed text-muted-foreground">
212
  Per-tick keystrokes, mouse delta, fire/jump/use, weapon switches — the actions a policy
213
  has to predict.
214
  </p>
215
  </div>
216
+ <div class="rounded-md border bg-card p-3">
217
+ <div class="text-[10px] font-semibold tracking-wider text-muted-foreground uppercase">
218
  World state
219
  </div>
220
+ <div class="mt-1 font-heading text-sm font-semibold">Per-tick game state</div>
221
+ <p class="mt-1 text-xs leading-relaxed text-muted-foreground">
222
  Positions, velocities, camera intrinsics, health, armor, ammo, weapons — for all 10
223
  players, every tick.
224
  </p>
225
  </div>
226
+ <div class="rounded-md border bg-card p-3">
227
+ <div class="text-[10px] font-semibold tracking-wider text-muted-foreground uppercase">
228
  G-buffers <span class="text-amber-600 dark:text-amber-400">· soon</span>
229
  </div>
230
+ <div class="mt-1 font-heading text-sm font-semibold">Luminance · depth · vertex IDs</div>
231
+ <p class="mt-1 text-xs leading-relaxed text-muted-foreground">
232
  Per-pixel auxiliary channels for self-supervised pretraining and dense prediction heads.
233
  </p>
234
  </div>
235
  </div>
236
  <p
237
+ class="mx-auto mt-4 max-w-2xl text-center text-[11px] leading-relaxed text-muted-foreground/80"
238
  >
239
  Every signal — video, audio, inputs, world state — is sampled on the same CS2 tick clock. No
240
  drift, no resampling artifacts.
 
244
  <!-- Stats -->
245
  <section class="mx-auto max-w-5xl pt-10">
246
  <div class="grid grid-cols-2 gap-3 sm:grid-cols-4">
247
+ <div class="rounded-md border bg-card p-3">
248
+ <div class="text-xs tracking-wide text-muted-foreground uppercase">Matches</div>
249
+ <div class="mt-0.5 font-heading text-2xl tabular-nums">
250
  {totalMatches}
251
  </div>
252
  </div>
253
+ <div class="rounded-md border bg-card p-3">
254
+ <div class="text-xs tracking-wide text-muted-foreground uppercase">Maps rendered</div>
255
+ <div class="mt-0.5 font-heading text-2xl tabular-nums">
256
+ {totalMaps}<span class="text-base font-medium text-muted-foreground/60"
257
  >/{TARGET_MAPS}</span
258
  >
259
  </div>
260
  </div>
261
+ <div class="rounded-md border bg-card p-3">
262
+ <div class="text-xs tracking-wide text-muted-foreground uppercase">Rounds</div>
263
+ <div class="mt-0.5 font-heading text-2xl tabular-nums">
264
  {totalRounds}
265
  </div>
266
  </div>
267
+ <div class="rounded-md border bg-card p-3">
268
+ <div class="text-xs tracking-wide text-muted-foreground uppercase">Footage</div>
269
+ <div class="mt-0.5 font-heading text-2xl tabular-nums">
270
  {totalHours < 1 ? totalHours.toFixed(1) : Math.round(totalHours)}<span
271
+ class="text-base font-medium text-muted-foreground/60">h/{TARGET_HOURS}h</span
272
  >
273
  </div>
274
  </div>
 
333
  <!-- Citation -->
334
  <section class="mx-auto mt-16 max-w-3xl">
335
  <h2
336
+ class="text-center font-heading text-xs font-semibold tracking-[0.2em] text-muted-foreground uppercase"
337
  >
338
  BibTeX
339
  </h2>
340
  <pre
341
+ class="mt-3 overflow-x-auto rounded-md border bg-card p-4 text-left font-mono text-xs leading-relaxed text-foreground/90">{`@misc{blanchon2026cs2dataset,
342
  author = {Julien Blanchon},
343
  title = {Counter Strike 2 Dataset},
344
  year = {2026},
 
349
 
350
  <!-- Footer -->
351
  <footer
352
+ class="mt-10 flex flex-col items-center gap-2 border-t pt-6 text-xs text-muted-foreground"
353
  >
354
  <div class="flex flex-wrap justify-center gap-4">
355
  <a
src/routes/match/[matchId]/[mapName]/+page.svelte CHANGED
@@ -356,13 +356,13 @@
356
  <div class="mb-5 flex flex-wrap items-end justify-between gap-3">
357
  <div>
358
  <div
359
- class="text-muted-foreground/80 mb-1 text-[11px] font-semibold tracking-[0.18em] uppercase"
360
  >
361
  {data.match.event}
362
  </div>
363
  <h1 class="font-heading text-2xl font-semibold tracking-tight md:text-3xl">
364
  {data.match.team1}
365
- <span class="text-muted-foreground/60 mx-2">vs</span>
366
  {data.match.team2}
367
  </h1>
368
  </div>
@@ -383,7 +383,7 @@
383
  {#each seriesMaps as m (m.map_name)}
384
  <Select.Item value={m.map_name} class="pe-8">
385
  <span class="capitalize">Map {m.map_index} · {prettyMap(m.map_name)}</span>
386
- <span class="text-muted-foreground ml-auto pl-3 tabular-nums"
387
  >{m.score1}-{m.score2}</span
388
  >
389
  </Select.Item>
@@ -399,7 +399,7 @@
399
  class="grid grid-cols-1 gap-4 lg:grid-cols-[80px_minmax(0,1fr)_320px] data-[view=grid]:lg:grid-cols-[80px_minmax(0,1fr)_280px]"
400
  >
401
  <aside
402
- class="bg-card flex h-[260px] flex-col rounded-lg border lg:sticky lg:top-2 lg:h-[calc(100vh-1rem)]"
403
  >
404
  <RoundList rounds={data.rounds} current={currentRoundNum} onSelect={selectRound} />
405
  </aside>
@@ -490,7 +490,7 @@
490
  {/each}
491
  </div>
492
  {:else if previews.length === 0}
493
- <p class="text-muted-foreground text-xs">No previews available for this round.</p>
494
  {:else}
495
  <PlayerGrid
496
  {previews}
@@ -511,7 +511,7 @@
511
  <aside class="flex flex-col gap-4">
512
  <Card.Root>
513
  <Card.Header class="px-3 pt-3 pb-1.5">
514
- <Card.Title class="text-muted-foreground text-sm font-semibold tracking-wide uppercase">
515
  Map
516
  </Card.Title>
517
  </Card.Header>
@@ -531,7 +531,7 @@
531
 
532
  <Card.Root>
533
  <Card.Header class="pb-2">
534
- <Card.Title class="text-muted-foreground text-sm font-semibold tracking-wide uppercase">
535
  Match
536
  </Card.Title>
537
  </Card.Header>
 
356
  <div class="mb-5 flex flex-wrap items-end justify-between gap-3">
357
  <div>
358
  <div
359
+ class="mb-1 text-[11px] font-semibold tracking-[0.18em] text-muted-foreground/80 uppercase"
360
  >
361
  {data.match.event}
362
  </div>
363
  <h1 class="font-heading text-2xl font-semibold tracking-tight md:text-3xl">
364
  {data.match.team1}
365
+ <span class="mx-2 text-muted-foreground/60">vs</span>
366
  {data.match.team2}
367
  </h1>
368
  </div>
 
383
  {#each seriesMaps as m (m.map_name)}
384
  <Select.Item value={m.map_name} class="pe-8">
385
  <span class="capitalize">Map {m.map_index} · {prettyMap(m.map_name)}</span>
386
+ <span class="ml-auto pl-3 text-muted-foreground tabular-nums"
387
  >{m.score1}-{m.score2}</span
388
  >
389
  </Select.Item>
 
399
  class="grid grid-cols-1 gap-4 lg:grid-cols-[80px_minmax(0,1fr)_320px] data-[view=grid]:lg:grid-cols-[80px_minmax(0,1fr)_280px]"
400
  >
401
  <aside
402
+ class="flex h-[260px] flex-col rounded-lg border bg-card lg:sticky lg:top-2 lg:h-[calc(100vh-1rem)]"
403
  >
404
  <RoundList rounds={data.rounds} current={currentRoundNum} onSelect={selectRound} />
405
  </aside>
 
490
  {/each}
491
  </div>
492
  {:else if previews.length === 0}
493
+ <p class="text-xs text-muted-foreground">No previews available for this round.</p>
494
  {:else}
495
  <PlayerGrid
496
  {previews}
 
511
  <aside class="flex flex-col gap-4">
512
  <Card.Root>
513
  <Card.Header class="px-3 pt-3 pb-1.5">
514
+ <Card.Title class="text-sm font-semibold tracking-wide text-muted-foreground uppercase">
515
  Map
516
  </Card.Title>
517
  </Card.Header>
 
531
 
532
  <Card.Root>
533
  <Card.Header class="pb-2">
534
+ <Card.Title class="text-sm font-semibold tracking-wide text-muted-foreground uppercase">
535
  Match
536
  </Card.Title>
537
  </Card.Header>