Quellcode durchsuchen

prepare accessible component release

Danilo Fragoso vor 2 Tagen
Ursprung
Commit
6f6a157418
40 geänderte Dateien mit 3248 neuen und 2214 gelöschten Zeilen
  1. 21 1
      README.md
  2. 2140 1784
      package-lock.json
  3. 16 11
      package.json
  4. 1 114
      src/app.css
  5. 23 8
      src/lib/components/data/DataTable.svelte
  6. 11 6
      src/lib/components/data/JsonViewer.svelte
  7. 1 0
      src/lib/components/data/KanbanCard.svelte
  8. 4 2
      src/lib/components/data/KanbanColumn.svelte
  9. 8 0
      src/lib/components/data/Table.svelte
  10. 72 9
      src/lib/components/forms/Combobox.svelte
  11. 134 43
      src/lib/components/forms/DatePicker.svelte
  12. 10 6
      src/lib/components/forms/FormField.svelte
  13. 91 7
      src/lib/components/forms/MultiSelect.svelte
  14. 29 2
      src/lib/components/layout/Tabs.svelte
  15. 40 18
      src/lib/components/navigation/CommandPalette.svelte
  16. 15 0
      src/lib/components/navigation/Navbar.svelte
  17. 15 4
      src/lib/components/navigation/Sidebar.svelte
  18. 16 11
      src/lib/components/overlay/AlertDialog.svelte
  19. 20 15
      src/lib/components/overlay/Dialog.svelte
  20. 56 8
      src/lib/components/overlay/DropdownMenu.svelte
  21. 22 3
      src/lib/components/overlay/Popover.svelte
  22. 1 1
      src/lib/components/overlay/Progress.svelte
  23. 30 21
      src/lib/components/overlay/Sheet.svelte
  24. 1 1
      src/lib/components/overlay/Skeleton.svelte
  25. 1 1
      src/lib/components/overlay/Toaster.svelte
  26. 37 18
      src/lib/components/overlay/Tooltip.svelte
  27. 35 9
      src/lib/components/primitives/Button.svelte
  28. 15 2
      src/lib/components/primitives/Input.svelte
  29. 5 1
      src/lib/components/primitives/Label.svelte
  30. 11 2
      src/lib/components/primitives/Select.svelte
  31. 15 2
      src/lib/components/primitives/Textarea.svelte
  32. 13 90
      src/lib/styles.css
  33. 108 0
      src/lib/tokens.css
  34. 7 0
      src/lib/utils/form-field.ts
  35. 143 0
      src/lib/utils/modal.ts
  36. 72 0
      src/lib/utils/popup.ts
  37. 4 3
      src/routes/+layout.svelte
  38. 1 1
      src/routes/DocBlock.svelte
  39. 1 1
      src/routes/data/+page.svelte
  40. 3 9
      tsconfig.json

+ 21 - 1
README.md

@@ -9,6 +9,24 @@ npm install
 npm run dev
 npm run dev
 ```
 ```
 
 
+## Styles
+
+Use the full Tailwind-powered component stylesheet in Svelte applications:
+
+```css
+@import "@database.pizza/olive/styles";
+```
+
+For other frameworks, import only the shared color, type, spacing, radius,
+shadow, and motion custom properties:
+
+```css
+@import "@database.pizza/olive/tokens";
+```
+
+The olive accent is the signature brand color; the mono stack provides the
+supporting technical voice for data, code, and identifiers.
+
 ## Publishing to npm
 ## Publishing to npm
 
 
 Olive uses [`@sveltejs/package`](https://kit.svelte.dev/docs/packaging) to build the library.
 Olive uses [`@sveltejs/package`](https://kit.svelte.dev/docs/packaging) to build the library.
@@ -36,7 +54,8 @@ npm install -D @sveltejs/package publint
       "types": "./dist/index.d.ts",
       "types": "./dist/index.d.ts",
       "svelte": "./dist/index.js"
       "svelte": "./dist/index.js"
     },
     },
-    "./styles": "./dist/app.css"
+    "./styles": "./dist/styles.css",
+    "./tokens": "./dist/tokens.css"
   },
   },
   "svelte": "./dist/index.js",
   "svelte": "./dist/index.js",
   "types": "./dist/index.d.ts",
   "types": "./dist/index.d.ts",
@@ -62,5 +81,6 @@ npm publish
 - `svelte-package` reads `src/lib/` and compiles everything into `dist/`
 - `svelte-package` reads `src/lib/` and compiles everything into `dist/`
 - `src/lib/index.ts` is the public API — only what's exported there is available to consumers
 - `src/lib/index.ts` is the public API — only what's exported there is available to consumers
 - Svelte files ship as source so consuming apps can tree-shake and SSR natively
 - Svelte files ship as source so consuming apps can tree-shake and SSR natively
+- `@database.pizza/olive/tokens` exposes framework-neutral CSS custom properties without Tailwind
 - TypeScript types are generated automatically alongside each file
 - TypeScript types are generated automatically alongside each file
 - `publint` validates the `package.json` exports field before you publish
 - `publint` validates the `package.json` exports field before you publish

+ 2140 - 1784
package-lock.json

@@ -1,1786 +1,2142 @@
 {
 {
-  "name": "olive",
-  "version": "0.0.1",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "name": "olive",
-      "version": "0.0.1",
-      "dependencies": {
-        "@tailwindcss/vite": "^4.2.4",
-        "tailwindcss": "^4.2.4"
-      },
-      "devDependencies": {
-        "@sveltejs/adapter-auto": "^7.0.1",
-        "@sveltejs/kit": "^2.57.0",
-        "@sveltejs/package": "^2.5.7",
-        "@sveltejs/vite-plugin-svelte": "^7.0.0",
-        "publint": "^0.3.18",
-        "svelte": "^5.55.2",
-        "svelte-check": "^4.4.6",
-        "typescript": "^6.0.2",
-        "vite": "^8.0.7"
-      }
-    },
-    "node_modules/@emnapi/core": {
-      "version": "1.9.2",
-      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz",
-      "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "@emnapi/wasi-threads": "1.2.1",
-        "tslib": "^2.4.0"
-      }
-    },
-    "node_modules/@emnapi/runtime": {
-      "version": "1.9.2",
-      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz",
-      "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "tslib": "^2.4.0"
-      }
-    },
-    "node_modules/@emnapi/wasi-threads": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
-      "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "tslib": "^2.4.0"
-      }
-    },
-    "node_modules/@jridgewell/gen-mapping": {
-      "version": "0.3.13",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
-      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/sourcemap-codec": "^1.5.0",
-        "@jridgewell/trace-mapping": "^0.3.24"
-      }
-    },
-    "node_modules/@jridgewell/remapping": {
-      "version": "2.3.5",
-      "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
-      "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/gen-mapping": "^0.3.5",
-        "@jridgewell/trace-mapping": "^0.3.24"
-      }
-    },
-    "node_modules/@jridgewell/resolve-uri": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
-      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.5.5",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
-      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
-      "license": "MIT"
-    },
-    "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.31",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
-      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/resolve-uri": "^3.1.0",
-        "@jridgewell/sourcemap-codec": "^1.4.14"
-      }
-    },
-    "node_modules/@napi-rs/wasm-runtime": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
-      "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "@tybys/wasm-util": "^0.10.1"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/Brooooooklyn"
-      },
-      "peerDependencies": {
-        "@emnapi/core": "^1.7.1",
-        "@emnapi/runtime": "^1.7.1"
-      }
-    },
-    "node_modules/@oxc-project/types": {
-      "version": "0.126.0",
-      "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.126.0.tgz",
-      "integrity": "sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==",
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/Boshen"
-      }
-    },
-    "node_modules/@polka/url": {
-      "version": "1.0.0-next.29",
-      "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
-      "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@publint/pack": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/@publint/pack/-/pack-0.1.4.tgz",
-      "integrity": "sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=18"
-      },
-      "funding": {
-        "url": "https://bjornlu.com/sponsor"
-      }
-    },
-    "node_modules/@rolldown/binding-android-arm64": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz",
-      "integrity": "sha512-rhY3k7Bsae9qQfOtph2Pm2jZEA+s8Gmjoz4hhmx70K9iMQ/ddeae+xhRQcM5IuVx5ry1+bGfkvMn7D6MJggVSA==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-darwin-arm64": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.16.tgz",
-      "integrity": "sha512-rNz0yK078yrNn3DrdgN+PKiMOW8HfQ92jQiXxwX8yW899ayV00MLVdaCNeVBhG/TbH3ouYVObo8/yrkiectkcQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-darwin-x64": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.16.tgz",
-      "integrity": "sha512-r/OmdR00HmD4i79Z//xO06uEPOq5hRXdhw7nzkxQxwSavs3PSHa1ijntdpOiZ2mzOQ3fVVu8C1M19FoNM+dMUQ==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-freebsd-x64": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.16.tgz",
-      "integrity": "sha512-KcRE5w8h0OnjUatG8pldyD14/CQ5Phs1oxfR+3pKDjboHRo9+MkqQaiIZlZRpsxC15paeXme/I127tUa9TXJ6g==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.16.tgz",
-      "integrity": "sha512-bT0guA1bpxEJ/ZhTRniQf7rNF8ybvXOuWbNIeLABaV5NGjx4EtOWBTSRGWFU9ZWVkPOZ+HNFP8RMcBokBiZ0Kg==",
-      "cpu": [
-        "arm"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-linux-arm64-gnu": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.16.tgz",
-      "integrity": "sha512-+tHktCHWV8BDQSjemUqm/Jl/TPk3QObCTIjmdDy/nlupcujZghmKK2962LYrqFpWu+ai01AN/REOH3NEpqvYQg==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-linux-arm64-musl": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.16.tgz",
-      "integrity": "sha512-3fPzdREH806oRLxpTWW1Gt4tQHs0TitZFOECB2xzCFLPKnSOy90gwA7P29cksYilFO6XVRY1kzga0cL2nRjKPg==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-linux-ppc64-gnu": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.16.tgz",
-      "integrity": "sha512-EKwI1tSrLs7YVw+JPJT/G2dJQ1jl9qlTTTEG0V2Ok/RdOenRfBw2PQdLPyjhIu58ocdBfP7vIRN/pvMsPxs/AQ==",
-      "cpu": [
-        "ppc64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-linux-s390x-gnu": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.16.tgz",
-      "integrity": "sha512-Uknladnb3Sxqu6SEcqBldQyJUpk8NleooZEc0MbRBJ4inEhRYWZX0NJu12vNf2mqAq7gsofAxHrGghiUYjhaLQ==",
-      "cpu": [
-        "s390x"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-linux-x64-gnu": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.16.tgz",
-      "integrity": "sha512-FIb8+uG49sZBtLTn+zt1AJ20TqVcqWeSIyoVt0or7uAWesgKaHbiBh6OpA/k9v0LTt+PTrb1Lao133kP4uVxkg==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-linux-x64-musl": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.16.tgz",
-      "integrity": "sha512-RuERhF9/EgWxZEXYWCOaViUWHIboceK4/ivdtQ3R0T44NjLkIIlGIAVAuCddFxsZ7vnRHtNQUrt2vR2n2slB2w==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-openharmony-arm64": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.16.tgz",
-      "integrity": "sha512-mXcXnvd9GpazCxeUCCnZ2+YF7nut+ZOEbE4GtaiPtyY6AkhZWbK70y1KK3j+RDhjVq5+U8FySkKRb/+w0EeUwA==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openharmony"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-wasm32-wasi": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.16.tgz",
-      "integrity": "sha512-3Q2KQxnC8IJOLqXmUMoYwyIPZU9hzRbnHaoV3Euz+VVnjZKcY8ktnNP8T9R4/GGQtb27C/UYKABxesKWb8lsvQ==",
-      "cpu": [
-        "wasm32"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "@emnapi/core": "1.9.2",
-        "@emnapi/runtime": "1.9.2",
-        "@napi-rs/wasm-runtime": "^1.1.4"
-      },
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-win32-arm64-msvc": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.16.tgz",
-      "integrity": "sha512-tj7XRemQcOcFwv7qhpUxMTBbI5mWMlE4c1Omhg5+h8GuLXzyj8HviYgR+bB2DMDgRqUE+jiDleqSCRjx4aYk/Q==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/binding-win32-x64-msvc": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.16.tgz",
-      "integrity": "sha512-PH5DRZT+F4f2PTXRXR8uJxnBq2po/xFtddyabTJVJs/ZYVHqXPEgNIr35IHTEa6bpa0Q8Awg+ymkTaGnKITw4g==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      }
-    },
-    "node_modules/@rolldown/pluginutils": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.16.tgz",
-      "integrity": "sha512-45+YtqxLYKDWQouLKCrpIZhke+nXxhsw+qAHVzHDVwttyBlHNBVs2K25rDXrZzhpTp9w1FlAlvweV1H++fdZoA==",
-      "license": "MIT"
-    },
-    "node_modules/@standard-schema/spec": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
-      "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@sveltejs/acorn-typescript": {
-      "version": "1.0.9",
-      "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz",
-      "integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==",
-      "dev": true,
-      "license": "MIT",
-      "peerDependencies": {
-        "acorn": "^8.9.0"
-      }
-    },
-    "node_modules/@sveltejs/adapter-auto": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-7.0.1.tgz",
-      "integrity": "sha512-dvuPm1E7M9NI/+canIQ6KKQDU2AkEefEZ2Dp7cY6uKoPq9Z/PhOXABe526UdW2mN986gjVkuSLkOYIBnS/M2LQ==",
-      "dev": true,
-      "license": "MIT",
-      "peerDependencies": {
-        "@sveltejs/kit": "^2.0.0"
-      }
-    },
-    "node_modules/@sveltejs/kit": {
-      "version": "2.57.1",
-      "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.57.1.tgz",
-      "integrity": "sha512-VRdSbB96cI1EnRh09CqmnQqP/YJvET5buj8S6k7CxaJqBJD4bw4fRKDjcarAj/eX9k2eHifQfDH8NtOh+ZxxPw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@standard-schema/spec": "^1.0.0",
-        "@sveltejs/acorn-typescript": "^1.0.5",
-        "@types/cookie": "^0.6.0",
-        "acorn": "^8.14.1",
-        "cookie": "^0.6.0",
-        "devalue": "^5.6.4",
-        "esm-env": "^1.2.2",
-        "kleur": "^4.1.5",
-        "magic-string": "^0.30.5",
-        "mrmime": "^2.0.0",
-        "set-cookie-parser": "^3.0.0",
-        "sirv": "^3.0.0"
-      },
-      "bin": {
-        "svelte-kit": "svelte-kit.js"
-      },
-      "engines": {
-        "node": ">=18.13"
-      },
-      "peerDependencies": {
-        "@opentelemetry/api": "^1.0.0",
-        "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0",
-        "svelte": "^4.0.0 || ^5.0.0-next.0",
-        "typescript": "^5.3.3 || ^6.0.0",
-        "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@opentelemetry/api": {
-          "optional": true
-        },
-        "typescript": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@sveltejs/package": {
-      "version": "2.5.7",
-      "resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-2.5.7.tgz",
-      "integrity": "sha512-qqD9xa9H7TDiGFrF6rz7AirOR8k15qDK/9i4MIE8te4vWsv5GEogPks61rrZcLy+yWph+aI6pIj2MdoK3YI8AQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "chokidar": "^5.0.0",
-        "kleur": "^4.1.5",
-        "sade": "^1.8.1",
-        "semver": "^7.5.4",
-        "svelte2tsx": "~0.7.33"
-      },
-      "bin": {
-        "svelte-package": "svelte-package.js"
-      },
-      "engines": {
-        "node": "^16.14 || >=18"
-      },
-      "peerDependencies": {
-        "svelte": "^3.44.0 || ^4.0.0 || ^5.0.0-next.1"
-      }
-    },
-    "node_modules/@sveltejs/package/node_modules/chokidar": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
-      "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "readdirp": "^5.0.0"
-      },
-      "engines": {
-        "node": ">= 20.19.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
-    "node_modules/@sveltejs/package/node_modules/readdirp": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
-      "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 20.19.0"
-      },
-      "funding": {
-        "type": "individual",
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
-    "node_modules/@sveltejs/package/node_modules/svelte2tsx": {
-      "version": "0.7.53",
-      "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.7.53.tgz",
-      "integrity": "sha512-ljVSwmnYRDHRm8+7ICP6QoAN7U7vgOFfPBLN6T745YWNYqRRSzHxlrzUVqMjYls2Un8MzJissfziy/38e6Deeg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "dedent-js": "^1.0.1",
-        "scule": "^1.3.0"
-      },
-      "peerDependencies": {
-        "svelte": "^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0",
-        "typescript": "^4.9.4 || ^5.0.0"
-      }
-    },
-    "node_modules/@sveltejs/package/node_modules/typescript": {
-      "version": "5.9.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
-      "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "peer": true,
-      "bin": {
-        "tsc": "bin/tsc",
-        "tsserver": "bin/tsserver"
-      },
-      "engines": {
-        "node": ">=14.17"
-      }
-    },
-    "node_modules/@sveltejs/vite-plugin-svelte": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-7.0.0.tgz",
-      "integrity": "sha512-ILXmxC7HAsnkK2eslgPetrqqW1BKSL7LktsFgqzNj83MaivMGZzluWq32m25j2mDOjmSKX7GGWahePhuEs7P/g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "deepmerge": "^4.3.1",
-        "magic-string": "^0.30.21",
-        "obug": "^2.1.0",
-        "vitefu": "^1.1.2"
-      },
-      "engines": {
-        "node": "^20.19 || ^22.12 || >=24"
-      },
-      "peerDependencies": {
-        "svelte": "^5.46.4",
-        "vite": "^8.0.0-beta.7 || ^8.0.0"
-      }
-    },
-    "node_modules/@tailwindcss/node": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.4.tgz",
-      "integrity": "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==",
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/remapping": "^2.3.5",
-        "enhanced-resolve": "^5.19.0",
-        "jiti": "^2.6.1",
-        "lightningcss": "1.32.0",
-        "magic-string": "^0.30.21",
-        "source-map-js": "^1.2.1",
-        "tailwindcss": "4.2.4"
-      }
-    },
-    "node_modules/@tailwindcss/oxide": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.4.tgz",
-      "integrity": "sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==",
-      "license": "MIT",
-      "engines": {
-        "node": ">= 20"
-      },
-      "optionalDependencies": {
-        "@tailwindcss/oxide-android-arm64": "4.2.4",
-        "@tailwindcss/oxide-darwin-arm64": "4.2.4",
-        "@tailwindcss/oxide-darwin-x64": "4.2.4",
-        "@tailwindcss/oxide-freebsd-x64": "4.2.4",
-        "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.4",
-        "@tailwindcss/oxide-linux-arm64-gnu": "4.2.4",
-        "@tailwindcss/oxide-linux-arm64-musl": "4.2.4",
-        "@tailwindcss/oxide-linux-x64-gnu": "4.2.4",
-        "@tailwindcss/oxide-linux-x64-musl": "4.2.4",
-        "@tailwindcss/oxide-wasm32-wasi": "4.2.4",
-        "@tailwindcss/oxide-win32-arm64-msvc": "4.2.4",
-        "@tailwindcss/oxide-win32-x64-msvc": "4.2.4"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-android-arm64": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.4.tgz",
-      "integrity": "sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-darwin-arm64": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.4.tgz",
-      "integrity": "sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-darwin-x64": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.4.tgz",
-      "integrity": "sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-freebsd-x64": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.4.tgz",
-      "integrity": "sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.4.tgz",
-      "integrity": "sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==",
-      "cpu": [
-        "arm"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.4.tgz",
-      "integrity": "sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.4.tgz",
-      "integrity": "sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.4.tgz",
-      "integrity": "sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-linux-x64-musl": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.4.tgz",
-      "integrity": "sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-wasm32-wasi": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.4.tgz",
-      "integrity": "sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==",
-      "bundleDependencies": [
-        "@napi-rs/wasm-runtime",
-        "@emnapi/core",
-        "@emnapi/runtime",
-        "@tybys/wasm-util",
-        "@emnapi/wasi-threads",
-        "tslib"
-      ],
-      "cpu": [
-        "wasm32"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "@emnapi/core": "^1.8.1",
-        "@emnapi/runtime": "^1.8.1",
-        "@emnapi/wasi-threads": "^1.1.0",
-        "@napi-rs/wasm-runtime": "^1.1.1",
-        "@tybys/wasm-util": "^0.10.1",
-        "tslib": "^2.8.1"
-      },
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.4.tgz",
-      "integrity": "sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.4.tgz",
-      "integrity": "sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 20"
-      }
-    },
-    "node_modules/@tailwindcss/vite": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.4.tgz",
-      "integrity": "sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==",
-      "license": "MIT",
-      "dependencies": {
-        "@tailwindcss/node": "4.2.4",
-        "@tailwindcss/oxide": "4.2.4",
-        "tailwindcss": "4.2.4"
-      },
-      "peerDependencies": {
-        "vite": "^5.2.0 || ^6 || ^7 || ^8"
-      }
-    },
-    "node_modules/@tybys/wasm-util": {
-      "version": "0.10.1",
-      "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
-      "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "tslib": "^2.4.0"
-      }
-    },
-    "node_modules/@types/cookie": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
-      "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@types/estree": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
-      "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@types/trusted-types": {
-      "version": "2.0.7",
-      "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
-      "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/acorn": {
-      "version": "8.16.0",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
-      "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
-      "dev": true,
-      "license": "MIT",
-      "bin": {
-        "acorn": "bin/acorn"
-      },
-      "engines": {
-        "node": ">=0.4.0"
-      }
-    },
-    "node_modules/aria-query": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz",
-      "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/axobject-query": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
-      "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/chokidar": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
-      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "readdirp": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 14.16.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
-    "node_modules/clsx": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
-      "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/cookie": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
-      "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.6"
-      }
-    },
-    "node_modules/dedent-js": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz",
-      "integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/deepmerge": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
-      "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/detect-libc": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
-      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/devalue": {
-      "version": "5.7.1",
-      "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.7.1.tgz",
-      "integrity": "sha512-MUbZ586EgQqdRnC4yDrlod3BEdyvE4TapGYHMW2CiaW+KkkFmWEFqBUaLltEZCGi0iFXCEjRF0OjF0DV2QHjOA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/enhanced-resolve": {
-      "version": "5.20.1",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz",
-      "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==",
-      "license": "MIT",
-      "dependencies": {
-        "graceful-fs": "^4.2.4",
-        "tapable": "^2.3.0"
-      },
-      "engines": {
-        "node": ">=10.13.0"
-      }
-    },
-    "node_modules/esm-env": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
-      "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/esrap": {
-      "version": "2.2.5",
-      "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.5.tgz",
-      "integrity": "sha512-/yLB1538mag+dn0wsePTe8C0rDIjUOaJpMs2McodSzmM2msWcZsBSdRtg6HOBt0A/r82BN+Md3pgwSc/uWt2Ig==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/sourcemap-codec": "^1.4.15"
-      },
-      "peerDependencies": {
-        "@typescript-eslint/types": "^8.2.0"
-      },
-      "peerDependenciesMeta": {
-        "@typescript-eslint/types": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/fdir": {
-      "version": "6.5.0",
-      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
-      "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=12.0.0"
-      },
-      "peerDependencies": {
-        "picomatch": "^3 || ^4"
-      },
-      "peerDependenciesMeta": {
-        "picomatch": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/fsevents": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
-      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
-      "hasInstallScript": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
-      }
-    },
-    "node_modules/graceful-fs": {
-      "version": "4.2.11",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
-      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
-      "license": "ISC"
-    },
-    "node_modules/is-reference": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
-      "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@types/estree": "^1.0.6"
-      }
-    },
-    "node_modules/jiti": {
-      "version": "2.6.1",
-      "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
-      "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
-      "license": "MIT",
-      "bin": {
-        "jiti": "lib/jiti-cli.mjs"
-      }
-    },
-    "node_modules/kleur": {
-      "version": "4.1.5",
-      "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
-      "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/lightningcss": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
-      "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
-      "license": "MPL-2.0",
-      "dependencies": {
-        "detect-libc": "^2.0.3"
-      },
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      },
-      "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"
-      }
-    },
-    "node_modules/lightningcss-android-arm64": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
-      "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-darwin-arm64": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
-      "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-darwin-x64": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
-      "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-freebsd-x64": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
-      "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-linux-arm-gnueabihf": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
-      "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
-      "cpu": [
-        "arm"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-linux-arm64-gnu": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
-      "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-linux-arm64-musl": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
-      "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-linux-x64-gnu": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
-      "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-linux-x64-musl": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
-      "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-win32-arm64-msvc": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
-      "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-win32-x64-msvc": {
-      "version": "1.32.0",
-      "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
-      "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/locate-character": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
-      "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/magic-string": {
-      "version": "0.30.21",
-      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
-      "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/sourcemap-codec": "^1.5.5"
-      }
-    },
-    "node_modules/mri": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
-      "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/mrmime": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
-      "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/nanoid": {
-      "version": "3.3.11",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
-      "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "bin": {
-        "nanoid": "bin/nanoid.cjs"
-      },
-      "engines": {
-        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
-      }
-    },
-    "node_modules/obug": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
-      "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
-      "dev": true,
-      "funding": [
-        "https://github.com/sponsors/sxzz",
-        "https://opencollective.com/debug"
-      ],
-      "license": "MIT"
-    },
-    "node_modules/package-manager-detector": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz",
-      "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/picocolors": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
-      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
-      "license": "ISC"
-    },
-    "node_modules/picomatch": {
-      "version": "4.0.4",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
-      "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/jonschlinkert"
-      }
-    },
-    "node_modules/postcss": {
-      "version": "8.5.10",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
-      "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/postcss/"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/postcss"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "nanoid": "^3.3.11",
-        "picocolors": "^1.1.1",
-        "source-map-js": "^1.2.1"
-      },
-      "engines": {
-        "node": "^10 || ^12 || >=14"
-      }
-    },
-    "node_modules/publint": {
-      "version": "0.3.18",
-      "resolved": "https://registry.npmjs.org/publint/-/publint-0.3.18.tgz",
-      "integrity": "sha512-JRJFeBTrfx4qLwEuGFPk+haJOJN97KnPuK01yj+4k/Wj5BgoOK5uNsivporiqBjk2JDaslg7qJOhGRnpltGeog==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@publint/pack": "^0.1.4",
-        "package-manager-detector": "^1.6.0",
-        "picocolors": "^1.1.1",
-        "sade": "^1.8.1"
-      },
-      "bin": {
-        "publint": "src/cli.js"
-      },
-      "engines": {
-        "node": ">=18"
-      },
-      "funding": {
-        "url": "https://bjornlu.com/sponsor"
-      }
-    },
-    "node_modules/readdirp": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
-      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 14.18.0"
-      },
-      "funding": {
-        "type": "individual",
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
-    "node_modules/rolldown": {
-      "version": "1.0.0-rc.16",
-      "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.16.tgz",
-      "integrity": "sha512-rzi5WqKzEZw3SooTt7cgm4eqIoujPIyGcJNGFL7iPEuajQw7vxMHUkXylu4/vhCkJGXsgRmxqMKXUpT6FEgl0g==",
-      "license": "MIT",
-      "dependencies": {
-        "@oxc-project/types": "=0.126.0",
-        "@rolldown/pluginutils": "1.0.0-rc.16"
-      },
-      "bin": {
-        "rolldown": "bin/cli.mjs"
-      },
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      },
-      "optionalDependencies": {
-        "@rolldown/binding-android-arm64": "1.0.0-rc.16",
-        "@rolldown/binding-darwin-arm64": "1.0.0-rc.16",
-        "@rolldown/binding-darwin-x64": "1.0.0-rc.16",
-        "@rolldown/binding-freebsd-x64": "1.0.0-rc.16",
-        "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.16",
-        "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.16",
-        "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.16",
-        "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.16",
-        "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.16",
-        "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.16",
-        "@rolldown/binding-linux-x64-musl": "1.0.0-rc.16",
-        "@rolldown/binding-openharmony-arm64": "1.0.0-rc.16",
-        "@rolldown/binding-wasm32-wasi": "1.0.0-rc.16",
-        "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.16",
-        "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.16"
-      }
-    },
-    "node_modules/sade": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
-      "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "mri": "^1.1.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/scule": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
-      "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/semver": {
-      "version": "7.7.4",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
-      "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
-      "dev": true,
-      "license": "ISC",
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/set-cookie-parser": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz",
-      "integrity": "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/sirv": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
-      "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@polka/url": "^1.0.0-next.24",
-        "mrmime": "^2.0.0",
-        "totalist": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/source-map-js": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
-      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
-      "license": "BSD-3-Clause",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/svelte": {
-      "version": "5.55.4",
-      "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.55.4.tgz",
-      "integrity": "sha512-q8DFohk6vUswSng95IZb9nzWJnbINZsK7OiM1snAa3qCjJBL0ZQpvMyAaVXjUukdM75J/m8UE8xwqat8Ors/zQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/remapping": "^2.3.4",
-        "@jridgewell/sourcemap-codec": "^1.5.0",
-        "@sveltejs/acorn-typescript": "^1.0.5",
-        "@types/estree": "^1.0.5",
-        "@types/trusted-types": "^2.0.7",
-        "acorn": "^8.12.1",
-        "aria-query": "5.3.1",
-        "axobject-query": "^4.1.0",
-        "clsx": "^2.1.1",
-        "devalue": "^5.6.4",
-        "esm-env": "^1.2.1",
-        "esrap": "^2.2.4",
-        "is-reference": "^3.0.3",
-        "locate-character": "^3.0.0",
-        "magic-string": "^0.30.11",
-        "zimmerframe": "^1.1.2"
-      },
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/svelte-check": {
-      "version": "4.4.6",
-      "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.4.6.tgz",
-      "integrity": "sha512-kP1zG81EWaFe9ZyTv4ZXv44Csi6Pkdpb7S3oj6m+K2ec/IcDg/a8LsFsnVLqm2nxtkSwsd5xPj/qFkTBgXHXjg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/trace-mapping": "^0.3.25",
-        "chokidar": "^4.0.1",
-        "fdir": "^6.2.0",
-        "picocolors": "^1.0.0",
-        "sade": "^1.7.4"
-      },
-      "bin": {
-        "svelte-check": "bin/svelte-check"
-      },
-      "engines": {
-        "node": ">= 18.0.0"
-      },
-      "peerDependencies": {
-        "svelte": "^4.0.0 || ^5.0.0-next.0",
-        "typescript": ">=5.0.0"
-      }
-    },
-    "node_modules/tailwindcss": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.4.tgz",
-      "integrity": "sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==",
-      "license": "MIT"
-    },
-    "node_modules/tapable": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
-      "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/webpack"
-      }
-    },
-    "node_modules/tinyglobby": {
-      "version": "0.2.16",
-      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
-      "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
-      "license": "MIT",
-      "dependencies": {
-        "fdir": "^6.5.0",
-        "picomatch": "^4.0.4"
-      },
-      "engines": {
-        "node": ">=12.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/SuperchupuDev"
-      }
-    },
-    "node_modules/totalist": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
-      "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/tslib": {
-      "version": "2.8.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
-      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
-      "license": "0BSD",
-      "optional": true
-    },
-    "node_modules/typescript": {
-      "version": "6.0.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
-      "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "bin": {
-        "tsc": "bin/tsc",
-        "tsserver": "bin/tsserver"
-      },
-      "engines": {
-        "node": ">=14.17"
-      }
-    },
-    "node_modules/vite": {
-      "version": "8.0.9",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.9.tgz",
-      "integrity": "sha512-t7g7GVRpMXjNpa67HaVWI/8BWtdVIQPCL2WoozXXA7LBGEFK4AkkKkHx2hAQf5x1GZSlcmEDPkVLSGahxnEEZw==",
-      "license": "MIT",
-      "dependencies": {
-        "lightningcss": "^1.32.0",
-        "picomatch": "^4.0.4",
-        "postcss": "^8.5.10",
-        "rolldown": "1.0.0-rc.16",
-        "tinyglobby": "^0.2.16"
-      },
-      "bin": {
-        "vite": "bin/vite.js"
-      },
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      },
-      "funding": {
-        "url": "https://github.com/vitejs/vite?sponsor=1"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.3"
-      },
-      "peerDependencies": {
-        "@types/node": "^20.19.0 || >=22.12.0",
-        "@vitejs/devtools": "^0.1.0",
-        "esbuild": "^0.27.0 || ^0.28.0",
-        "jiti": ">=1.21.0",
-        "less": "^4.0.0",
-        "sass": "^1.70.0",
-        "sass-embedded": "^1.70.0",
-        "stylus": ">=0.54.8",
-        "sugarss": "^5.0.0",
-        "terser": "^5.16.0",
-        "tsx": "^4.8.1",
-        "yaml": "^2.4.2"
-      },
-      "peerDependenciesMeta": {
-        "@types/node": {
-          "optional": true
-        },
-        "@vitejs/devtools": {
-          "optional": true
-        },
-        "esbuild": {
-          "optional": true
-        },
-        "jiti": {
-          "optional": true
-        },
-        "less": {
-          "optional": true
-        },
-        "sass": {
-          "optional": true
-        },
-        "sass-embedded": {
-          "optional": true
-        },
-        "stylus": {
-          "optional": true
-        },
-        "sugarss": {
-          "optional": true
-        },
-        "terser": {
-          "optional": true
-        },
-        "tsx": {
-          "optional": true
-        },
-        "yaml": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/vitefu": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz",
-      "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==",
-      "dev": true,
-      "license": "MIT",
-      "workspaces": [
-        "tests/deps/*",
-        "tests/projects/*",
-        "tests/projects/workspace/packages/*"
-      ],
-      "peerDependencies": {
-        "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
-      },
-      "peerDependenciesMeta": {
-        "vite": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/zimmerframe": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
-      "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
-      "dev": true,
-      "license": "MIT"
-    }
-  }
+	"name": "@database.pizza/olive",
+	"version": "0.1.0",
+	"lockfileVersion": 3,
+	"requires": true,
+	"packages": {
+		"": {
+			"name": "@database.pizza/olive",
+			"version": "0.1.0",
+			"dependencies": {
+				"tailwindcss": "^4.2.4"
+			},
+			"devDependencies": {
+				"@sveltejs/adapter-auto": "^7.0.1",
+				"@sveltejs/kit": "^2.57.0",
+				"@sveltejs/package": "^2.5.7",
+				"@sveltejs/vite-plugin-svelte": "^7.0.0",
+				"@tailwindcss/vite": "^4.2.4",
+				"publint": "^0.3.18",
+				"svelte": "^5.55.2",
+				"svelte-check": "^4.4.6",
+				"typescript": "^6.0.2",
+				"vite": "^8.0.7"
+			},
+			"peerDependencies": {
+				"@sveltejs/kit": "^2.0.0",
+				"svelte": "^5.20.0"
+			}
+		},
+		"node_modules/@emnapi/core": {
+			"version": "1.9.2",
+			"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz",
+			"integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==",
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"dependencies": {
+				"@emnapi/wasi-threads": "1.2.1",
+				"tslib": "^2.4.0"
+			}
+		},
+		"node_modules/@emnapi/runtime": {
+			"version": "1.9.2",
+			"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz",
+			"integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==",
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"dependencies": {
+				"tslib": "^2.4.0"
+			}
+		},
+		"node_modules/@emnapi/wasi-threads": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+			"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"dependencies": {
+				"tslib": "^2.4.0"
+			}
+		},
+		"node_modules/@jridgewell/gen-mapping": {
+			"version": "0.3.13",
+			"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+			"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@jridgewell/sourcemap-codec": "^1.5.0",
+				"@jridgewell/trace-mapping": "^0.3.24"
+			}
+		},
+		"node_modules/@jridgewell/remapping": {
+			"version": "2.3.5",
+			"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+			"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@jridgewell/gen-mapping": "^0.3.5",
+				"@jridgewell/trace-mapping": "^0.3.24"
+			}
+		},
+		"node_modules/@jridgewell/resolve-uri": {
+			"version": "3.1.2",
+			"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+			"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6.0.0"
+			}
+		},
+		"node_modules/@jridgewell/sourcemap-codec": {
+			"version": "1.5.5",
+			"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+			"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@jridgewell/trace-mapping": {
+			"version": "0.3.31",
+			"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+			"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@jridgewell/resolve-uri": "^3.1.0",
+				"@jridgewell/sourcemap-codec": "^1.4.14"
+			}
+		},
+		"node_modules/@napi-rs/wasm-runtime": {
+			"version": "1.1.4",
+			"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
+			"integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"dependencies": {
+				"@tybys/wasm-util": "^0.10.1"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/Brooooooklyn"
+			},
+			"peerDependencies": {
+				"@emnapi/core": "^1.7.1",
+				"@emnapi/runtime": "^1.7.1"
+			}
+		},
+		"node_modules/@oxc-project/types": {
+			"version": "0.148.0",
+			"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.148.0.tgz",
+			"integrity": "sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A==",
+			"dev": true,
+			"license": "MIT",
+			"funding": {
+				"url": "https://github.com/sponsors/oxc-project"
+			}
+		},
+		"node_modules/@polka/url": {
+			"version": "1.0.0-next.29",
+			"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
+			"integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@publint/pack": {
+			"version": "0.1.4",
+			"resolved": "https://registry.npmjs.org/@publint/pack/-/pack-0.1.4.tgz",
+			"integrity": "sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://bjornlu.com/sponsor"
+			}
+		},
+		"node_modules/@rolldown/binding-android-arm-eabi": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.7.tgz",
+			"integrity": "sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-android-arm64": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.7.tgz",
+			"integrity": "sha512-l17HE9EweWaqJZhuUuNBN/FzM62xw+DECVnJyvMsxn8vJFAGLy5QfLDoYAcronkAN8VxKZHezDpulHDPx95vFw==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-darwin-arm64": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.7.tgz",
+			"integrity": "sha512-8ED8ELFvHXc6OCETIn4gXObPiaR6bckM/ipXtbzlPVDRMBfEGjCKgO90F9YtfdpDatVx/ZQw7aZ1vUMf/+T3Mw==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-darwin-x64": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.7.tgz",
+			"integrity": "sha512-/WPripjtiAIZ2tWY7ddijORT0Ujg87wxWW/qcoFVCKAWVDPhtY0xr7Dj0M3GyNGz60jGwTElhro/mkF9dT7dDQ==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-freebsd-x64": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.7.tgz",
+			"integrity": "sha512-14DI4NcqpvbICxSnGLx3PmtDaWqRP/KGSGb6C+JLLVPeZRl6dKdHba3pGsqT3vpdTqhEYIPG0MMQ8c0xYqoJxA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"freebsd"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.7.tgz",
+			"integrity": "sha512-bxrWIRvHWQvbJwi+VIie/kDJmQxcNE6xxWwZdqF/ExVAigtHkv54WTLQPb+QsZdnFy18fg7JPfWGL0RH6vwIlQ==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-linux-arm64-gnu": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.7.tgz",
+			"integrity": "sha512-toOY2BChBZyuxU7OYX6Tn389di4IzAqPTycVcci0O7FSfBqzRB3RZn+K5Is6ANf4tmgRd/K1yZTsNTXbkXsnLg==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"libc": [
+				"glibc"
+			],
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-linux-arm64-musl": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.7.tgz",
+			"integrity": "sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"libc": [
+				"musl"
+			],
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-linux-ppc64-gnu": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.7.tgz",
+			"integrity": "sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg==",
+			"cpu": [
+				"ppc64"
+			],
+			"dev": true,
+			"libc": [
+				"glibc"
+			],
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-linux-s390x-gnu": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.7.tgz",
+			"integrity": "sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw==",
+			"cpu": [
+				"s390x"
+			],
+			"dev": true,
+			"libc": [
+				"glibc"
+			],
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-linux-x64-gnu": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.7.tgz",
+			"integrity": "sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"libc": [
+				"glibc"
+			],
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-linux-x64-musl": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.7.tgz",
+			"integrity": "sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"libc": [
+				"musl"
+			],
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-openharmony-arm64": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.7.tgz",
+			"integrity": "sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"openharmony"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-win32-arm64-msvc": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.7.tgz",
+			"integrity": "sha512-e3Gu3WxbNk/UqQhxqU7YIYO+9ZBvWNz3U+h/qRFosscMFzdRPbXYSaSWgSnklv2fz1TgzBTcti2z35c/7irsHw==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/binding-win32-x64-msvc": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.7.tgz",
+			"integrity": "sha512-W/jg5qoRSqjsEv0+dZi4e687mcHqmVuU0P4fK6qS/xjetW2Gmc1W8j//z5nAeNcC8Ttm0hV46IjcYeuVwYhuiw==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			}
+		},
+		"node_modules/@rolldown/pluginutils": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
+			"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@standard-schema/spec": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
+			"integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@sveltejs/acorn-typescript": {
+			"version": "1.0.13",
+			"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.13.tgz",
+			"integrity": "sha512-wgKggnhZVL9Bfx1OaKKTrYY9BFRk6C8UAkQNUcIv1+llzYrIqy+RZm5HPKzn0NpEBvTVhTqB4kQyllZywsRBRQ==",
+			"dev": true,
+			"license": "MIT",
+			"peerDependencies": {
+				"acorn": "^8.9.0"
+			}
+		},
+		"node_modules/@sveltejs/adapter-auto": {
+			"version": "7.0.1",
+			"resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-7.0.1.tgz",
+			"integrity": "sha512-dvuPm1E7M9NI/+canIQ6KKQDU2AkEefEZ2Dp7cY6uKoPq9Z/PhOXABe526UdW2mN986gjVkuSLkOYIBnS/M2LQ==",
+			"dev": true,
+			"license": "MIT",
+			"peerDependencies": {
+				"@sveltejs/kit": "^2.0.0"
+			}
+		},
+		"node_modules/@sveltejs/kit": {
+			"version": "2.70.3",
+			"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.70.3.tgz",
+			"integrity": "sha512-UDvEYuZqAMbfB/oXIoqKvbKcb7YczK5zYrzmsGV1zRJk03jntwp8dXiYoIJotxAndsKvcPFtx9H1GRSKFdSHgg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@standard-schema/spec": "^1.0.0",
+				"@sveltejs/acorn-typescript": "^1.0.9",
+				"@types/cookie": "^0.6.0",
+				"acorn": "^8.16.0",
+				"cookie": "^0.6.0",
+				"devalue": "^5.8.1",
+				"esm-env": "^1.2.2",
+				"kleur": "^4.1.5",
+				"magic-string": "^0.30.5",
+				"mrmime": "^2.0.0",
+				"set-cookie-parser": "^3.0.0",
+				"sirv": "^3.0.0"
+			},
+			"bin": {
+				"svelte-kit": "svelte-kit.js"
+			},
+			"engines": {
+				"node": ">=18.13"
+			},
+			"peerDependencies": {
+				"@opentelemetry/api": "^1.0.0",
+				"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0",
+				"svelte": "^4.0.0 || ^5.0.0-next.0",
+				"typescript": "^5.3.3 || ^6.0.0",
+				"vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0"
+			},
+			"peerDependenciesMeta": {
+				"@opentelemetry/api": {
+					"optional": true
+				},
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@sveltejs/package": {
+			"version": "2.5.7",
+			"resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-2.5.7.tgz",
+			"integrity": "sha512-qqD9xa9H7TDiGFrF6rz7AirOR8k15qDK/9i4MIE8te4vWsv5GEogPks61rrZcLy+yWph+aI6pIj2MdoK3YI8AQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"chokidar": "^5.0.0",
+				"kleur": "^4.1.5",
+				"sade": "^1.8.1",
+				"semver": "^7.5.4",
+				"svelte2tsx": "~0.7.33"
+			},
+			"bin": {
+				"svelte-package": "svelte-package.js"
+			},
+			"engines": {
+				"node": "^16.14 || >=18"
+			},
+			"peerDependencies": {
+				"svelte": "^3.44.0 || ^4.0.0 || ^5.0.0-next.1"
+			}
+		},
+		"node_modules/@sveltejs/package/node_modules/chokidar": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
+			"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"readdirp": "^5.0.0"
+			},
+			"engines": {
+				"node": ">= 20.19.0"
+			},
+			"funding": {
+				"url": "https://paulmillr.com/funding/"
+			}
+		},
+		"node_modules/@sveltejs/package/node_modules/readdirp": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
+			"integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 20.19.0"
+			},
+			"funding": {
+				"type": "individual",
+				"url": "https://paulmillr.com/funding/"
+			}
+		},
+		"node_modules/@sveltejs/package/node_modules/svelte2tsx": {
+			"version": "0.7.53",
+			"resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.7.53.tgz",
+			"integrity": "sha512-ljVSwmnYRDHRm8+7ICP6QoAN7U7vgOFfPBLN6T745YWNYqRRSzHxlrzUVqMjYls2Un8MzJissfziy/38e6Deeg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"dedent-js": "^1.0.1",
+				"scule": "^1.3.0"
+			},
+			"peerDependencies": {
+				"svelte": "^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0",
+				"typescript": "^4.9.4 || ^5.0.0"
+			}
+		},
+		"node_modules/@sveltejs/package/node_modules/typescript": {
+			"version": "5.9.3",
+			"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+			"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"peer": true,
+			"bin": {
+				"tsc": "bin/tsc",
+				"tsserver": "bin/tsserver"
+			},
+			"engines": {
+				"node": ">=14.17"
+			}
+		},
+		"node_modules/@sveltejs/vite-plugin-svelte": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-7.0.0.tgz",
+			"integrity": "sha512-ILXmxC7HAsnkK2eslgPetrqqW1BKSL7LktsFgqzNj83MaivMGZzluWq32m25j2mDOjmSKX7GGWahePhuEs7P/g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"deepmerge": "^4.3.1",
+				"magic-string": "^0.30.21",
+				"obug": "^2.1.0",
+				"vitefu": "^1.1.2"
+			},
+			"engines": {
+				"node": "^20.19 || ^22.12 || >=24"
+			},
+			"peerDependencies": {
+				"svelte": "^5.46.4",
+				"vite": "^8.0.0-beta.7 || ^8.0.0"
+			}
+		},
+		"node_modules/@tailwindcss/node": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.4.tgz",
+			"integrity": "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@jridgewell/remapping": "^2.3.5",
+				"enhanced-resolve": "^5.19.0",
+				"jiti": "^2.6.1",
+				"lightningcss": "1.32.0",
+				"magic-string": "^0.30.21",
+				"source-map-js": "^1.2.1",
+				"tailwindcss": "4.2.4"
+			}
+		},
+		"node_modules/@tailwindcss/oxide": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.4.tgz",
+			"integrity": "sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 20"
+			},
+			"optionalDependencies": {
+				"@tailwindcss/oxide-android-arm64": "4.2.4",
+				"@tailwindcss/oxide-darwin-arm64": "4.2.4",
+				"@tailwindcss/oxide-darwin-x64": "4.2.4",
+				"@tailwindcss/oxide-freebsd-x64": "4.2.4",
+				"@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.4",
+				"@tailwindcss/oxide-linux-arm64-gnu": "4.2.4",
+				"@tailwindcss/oxide-linux-arm64-musl": "4.2.4",
+				"@tailwindcss/oxide-linux-x64-gnu": "4.2.4",
+				"@tailwindcss/oxide-linux-x64-musl": "4.2.4",
+				"@tailwindcss/oxide-wasm32-wasi": "4.2.4",
+				"@tailwindcss/oxide-win32-arm64-msvc": "4.2.4",
+				"@tailwindcss/oxide-win32-x64-msvc": "4.2.4"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-android-arm64": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.4.tgz",
+			"integrity": "sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-darwin-arm64": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.4.tgz",
+			"integrity": "sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-darwin-x64": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.4.tgz",
+			"integrity": "sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-freebsd-x64": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.4.tgz",
+			"integrity": "sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"freebsd"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.4.tgz",
+			"integrity": "sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.4.tgz",
+			"integrity": "sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.4.tgz",
+			"integrity": "sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.4.tgz",
+			"integrity": "sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-linux-x64-musl": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.4.tgz",
+			"integrity": "sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-wasm32-wasi": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.4.tgz",
+			"integrity": "sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==",
+			"bundleDependencies": [
+				"@napi-rs/wasm-runtime",
+				"@emnapi/core",
+				"@emnapi/runtime",
+				"@tybys/wasm-util",
+				"@emnapi/wasi-threads",
+				"tslib"
+			],
+			"cpu": [
+				"wasm32"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"dependencies": {
+				"@emnapi/core": "^1.8.1",
+				"@emnapi/runtime": "^1.8.1",
+				"@emnapi/wasi-threads": "^1.1.0",
+				"@napi-rs/wasm-runtime": "^1.1.1",
+				"@tybys/wasm-util": "^0.10.1",
+				"tslib": "^2.8.1"
+			},
+			"engines": {
+				"node": ">=14.0.0"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.4.tgz",
+			"integrity": "sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.4.tgz",
+			"integrity": "sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">= 20"
+			}
+		},
+		"node_modules/@tailwindcss/vite": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.4.tgz",
+			"integrity": "sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@tailwindcss/node": "4.2.4",
+				"@tailwindcss/oxide": "4.2.4",
+				"tailwindcss": "4.2.4"
+			},
+			"peerDependencies": {
+				"vite": "^5.2.0 || ^6 || ^7 || ^8"
+			}
+		},
+		"node_modules/@tybys/wasm-util": {
+			"version": "0.10.1",
+			"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
+			"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"dependencies": {
+				"tslib": "^2.4.0"
+			}
+		},
+		"node_modules/@types/cookie": {
+			"version": "0.6.0",
+			"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+			"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@types/estree": {
+			"version": "1.0.8",
+			"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+			"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/acorn": {
+			"version": "8.16.0",
+			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+			"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+			"dev": true,
+			"license": "MIT",
+			"bin": {
+				"acorn": "bin/acorn"
+			},
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
+		"node_modules/aria-query": {
+			"version": "5.3.1",
+			"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz",
+			"integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/axobject-query": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
+			"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/chokidar": {
+			"version": "4.0.3",
+			"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+			"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"readdirp": "^4.0.1"
+			},
+			"engines": {
+				"node": ">= 14.16.0"
+			},
+			"funding": {
+				"url": "https://paulmillr.com/funding/"
+			}
+		},
+		"node_modules/clsx": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+			"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/cookie": {
+			"version": "0.7.2",
+			"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+			"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/dedent-js": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz",
+			"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/deepmerge": {
+			"version": "4.3.1",
+			"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+			"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/detect-libc": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+			"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/devalue": {
+			"version": "5.9.2",
+			"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.9.2.tgz",
+			"integrity": "sha512-po4PAY5c53tw5XMocSnf8A/5OHhbbUftpr93aEN6BBoAdntUmK7vu7wOATqvt7cXO7m1Cl4gMVn6p7n6n4mj0w==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/enhanced-resolve": {
+			"version": "5.20.1",
+			"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz",
+			"integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"graceful-fs": "^4.2.4",
+				"tapable": "^2.3.0"
+			},
+			"engines": {
+				"node": ">=10.13.0"
+			}
+		},
+		"node_modules/esm-env": {
+			"version": "1.2.2",
+			"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
+			"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/esrap": {
+			"version": "2.3.7",
+			"resolved": "https://registry.npmjs.org/esrap/-/esrap-2.3.7.tgz",
+			"integrity": "sha512-n2nf7fZR3c9yXf0BPEuHuXqT+KW0SJVj4cN5FMEkpCZ3scLjOQWpiccyCxVzCC2q1wubTghuEGzngJY/7Ah0Ow==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@jridgewell/sourcemap-codec": "^1.4.15"
+			},
+			"peerDependencies": {
+				"@typescript-eslint/types": "^8.2.0"
+			},
+			"peerDependenciesMeta": {
+				"@typescript-eslint/types": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/fdir": {
+			"version": "6.5.0",
+			"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+			"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12.0.0"
+			},
+			"peerDependencies": {
+				"picomatch": "^3 || ^4"
+			},
+			"peerDependenciesMeta": {
+				"picomatch": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/fsevents": {
+			"version": "2.3.3",
+			"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+			"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+			"dev": true,
+			"hasInstallScript": true,
+			"license": "MIT",
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+			}
+		},
+		"node_modules/graceful-fs": {
+			"version": "4.2.11",
+			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+			"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/is-reference": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
+			"integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@types/estree": "^1.0.6"
+			}
+		},
+		"node_modules/jiti": {
+			"version": "2.6.1",
+			"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
+			"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
+			"dev": true,
+			"license": "MIT",
+			"bin": {
+				"jiti": "lib/jiti-cli.mjs"
+			}
+		},
+		"node_modules/kleur": {
+			"version": "4.1.5",
+			"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+			"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/lightningcss": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+			"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+			"dev": true,
+			"license": "MPL-2.0",
+			"dependencies": {
+				"detect-libc": "^2.0.3"
+			},
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			},
+			"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"
+			}
+		},
+		"node_modules/lightningcss-android-arm64": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+			"integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-darwin-arm64": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+			"integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-darwin-x64": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+			"integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-freebsd-x64": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+			"integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"freebsd"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-linux-arm-gnueabihf": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+			"integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-linux-arm64-gnu": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+			"integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-linux-arm64-musl": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+			"integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-linux-x64-gnu": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+			"integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-linux-x64-musl": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+			"integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-win32-arm64-msvc": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+			"integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-win32-x64-msvc": {
+			"version": "1.32.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+			"integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/locate-character": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
+			"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/magic-string": {
+			"version": "0.30.21",
+			"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+			"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@jridgewell/sourcemap-codec": "^1.5.5"
+			}
+		},
+		"node_modules/mri": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+			"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/mrmime": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
+			"integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/nanoid": {
+			"version": "3.3.18",
+			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
+			"integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/ai"
+				}
+			],
+			"license": "MIT",
+			"bin": {
+				"nanoid": "bin/nanoid.cjs"
+			},
+			"engines": {
+				"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+			}
+		},
+		"node_modules/obug": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
+			"integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
+			"dev": true,
+			"funding": [
+				"https://github.com/sponsors/sxzz",
+				"https://opencollective.com/debug"
+			],
+			"license": "MIT"
+		},
+		"node_modules/package-manager-detector": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz",
+			"integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/picocolors": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+			"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/picomatch": {
+			"version": "4.0.7",
+			"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
+			"integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/jonschlinkert"
+			}
+		},
+		"node_modules/postcss": {
+			"version": "8.5.28",
+			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz",
+			"integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/postcss/"
+				},
+				{
+					"type": "tidelift",
+					"url": "https://tidelift.com/funding/github/npm/postcss"
+				},
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/ai"
+				}
+			],
+			"license": "MIT",
+			"dependencies": {
+				"nanoid": "^3.3.18",
+				"picocolors": "^1.1.1",
+				"source-map-js": "^1.2.1"
+			},
+			"engines": {
+				"node": "^10 || ^12 || >=14"
+			}
+		},
+		"node_modules/publint": {
+			"version": "0.3.18",
+			"resolved": "https://registry.npmjs.org/publint/-/publint-0.3.18.tgz",
+			"integrity": "sha512-JRJFeBTrfx4qLwEuGFPk+haJOJN97KnPuK01yj+4k/Wj5BgoOK5uNsivporiqBjk2JDaslg7qJOhGRnpltGeog==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@publint/pack": "^0.1.4",
+				"package-manager-detector": "^1.6.0",
+				"picocolors": "^1.1.1",
+				"sade": "^1.8.1"
+			},
+			"bin": {
+				"publint": "src/cli.js"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://bjornlu.com/sponsor"
+			}
+		},
+		"node_modules/readdirp": {
+			"version": "4.1.2",
+			"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+			"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 14.18.0"
+			},
+			"funding": {
+				"type": "individual",
+				"url": "https://paulmillr.com/funding/"
+			}
+		},
+		"node_modules/rolldown": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.7.tgz",
+			"integrity": "sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@oxc-project/types": "=0.148.0",
+				"@rolldown/pluginutils": "^1.0.0"
+			},
+			"bin": {
+				"rolldown": "bin/cli.mjs"
+			},
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			},
+			"optionalDependencies": {
+				"@rolldown/binding-android-arm-eabi": "1.2.7",
+				"@rolldown/binding-android-arm64": "1.2.7",
+				"@rolldown/binding-darwin-arm64": "1.2.7",
+				"@rolldown/binding-darwin-x64": "1.2.7",
+				"@rolldown/binding-freebsd-x64": "1.2.7",
+				"@rolldown/binding-linux-arm-gnueabihf": "1.2.7",
+				"@rolldown/binding-linux-arm64-gnu": "1.2.7",
+				"@rolldown/binding-linux-arm64-musl": "1.2.7",
+				"@rolldown/binding-linux-ppc64-gnu": "1.2.7",
+				"@rolldown/binding-linux-s390x-gnu": "1.2.7",
+				"@rolldown/binding-linux-x64-gnu": "1.2.7",
+				"@rolldown/binding-linux-x64-musl": "1.2.7",
+				"@rolldown/binding-openharmony-arm64": "1.2.7",
+				"@rolldown/binding-win32-arm64-msvc": "1.2.7",
+				"@rolldown/binding-win32-x64-msvc": "1.2.7"
+			}
+		},
+		"node_modules/sade": {
+			"version": "1.8.1",
+			"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
+			"integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"mri": "^1.1.0"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/scule": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
+			"integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/semver": {
+			"version": "7.7.4",
+			"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+			"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+			"dev": true,
+			"license": "ISC",
+			"bin": {
+				"semver": "bin/semver.js"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/set-cookie-parser": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz",
+			"integrity": "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/sirv": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
+			"integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@polka/url": "^1.0.0-next.24",
+				"mrmime": "^2.0.0",
+				"totalist": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/source-map-js": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+			"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+			"dev": true,
+			"license": "BSD-3-Clause",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/svelte": {
+			"version": "5.57.0",
+			"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.57.0.tgz",
+			"integrity": "sha512-NdbDn7fl4be1ViUG0oq/lvG6OZy3oENolV2ONjiqqsfVoeAfzaQAKUcEX3MrQod/Bebv1PgwET9rfXhgn9s4Kg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@jridgewell/remapping": "^2.3.4",
+				"@jridgewell/sourcemap-codec": "^1.5.0",
+				"@sveltejs/acorn-typescript": "^1.0.10",
+				"@types/estree": "^1.0.5",
+				"acorn": "^8.12.1",
+				"aria-query": "5.3.1",
+				"axobject-query": "^4.1.0",
+				"clsx": "^2.1.1",
+				"devalue": "^5.8.1",
+				"esm-env": "^1.2.1",
+				"esrap": "^2.2.12",
+				"is-reference": "^3.0.3",
+				"locate-character": "^3.0.0",
+				"magic-string": "^0.30.11",
+				"zimmerframe": "^1.1.2"
+			},
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/svelte-check": {
+			"version": "4.4.6",
+			"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.4.6.tgz",
+			"integrity": "sha512-kP1zG81EWaFe9ZyTv4ZXv44Csi6Pkdpb7S3oj6m+K2ec/IcDg/a8LsFsnVLqm2nxtkSwsd5xPj/qFkTBgXHXjg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@jridgewell/trace-mapping": "^0.3.25",
+				"chokidar": "^4.0.1",
+				"fdir": "^6.2.0",
+				"picocolors": "^1.0.0",
+				"sade": "^1.7.4"
+			},
+			"bin": {
+				"svelte-check": "bin/svelte-check"
+			},
+			"engines": {
+				"node": ">= 18.0.0"
+			},
+			"peerDependencies": {
+				"svelte": "^4.0.0 || ^5.0.0-next.0",
+				"typescript": ">=5.0.0"
+			}
+		},
+		"node_modules/tailwindcss": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.4.tgz",
+			"integrity": "sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==",
+			"license": "MIT"
+		},
+		"node_modules/tapable": {
+			"version": "2.3.3",
+			"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+			"integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/webpack"
+			}
+		},
+		"node_modules/tinyglobby": {
+			"version": "0.2.17",
+			"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+			"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"fdir": "^6.5.0",
+				"picomatch": "^4.0.4"
+			},
+			"engines": {
+				"node": ">=12.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/SuperchupuDev"
+			}
+		},
+		"node_modules/totalist": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+			"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/tslib": {
+			"version": "2.8.1",
+			"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+			"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+			"dev": true,
+			"license": "0BSD",
+			"optional": true
+		},
+		"node_modules/typescript": {
+			"version": "6.0.3",
+			"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
+			"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"bin": {
+				"tsc": "bin/tsc",
+				"tsserver": "bin/tsserver"
+			},
+			"engines": {
+				"node": ">=14.17"
+			}
+		},
+		"node_modules/vite": {
+			"version": "8.2.2",
+			"resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz",
+			"integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"lightningcss": "^1.33.0",
+				"picomatch": "^4.0.5",
+				"postcss": "^8.5.26",
+				"rolldown": "~1.2.4",
+				"tinyglobby": "^0.2.17"
+			},
+			"bin": {
+				"vite": "bin/vite.js"
+			},
+			"engines": {
+				"node": "^20.19.0 || >=22.12.0"
+			},
+			"funding": {
+				"url": "https://github.com/vitejs/vite?sponsor=1"
+			},
+			"optionalDependencies": {
+				"fsevents": "~2.3.3"
+			},
+			"peerDependencies": {
+				"@types/node": "^20.19.0 || >=22.12.0",
+				"@vitejs/devtools": "^0.4.0 || ^0.5.0",
+				"esbuild": "^0.27.0 || ^0.28.0",
+				"jiti": ">=1.21.0",
+				"less": "^4.0.0",
+				"sass": "^1.70.0",
+				"sass-embedded": "^1.70.0",
+				"stylus": ">=0.54.8",
+				"sugarss": "^5.0.0",
+				"terser": "^5.16.0",
+				"tsx": "^4.8.1",
+				"yaml": "^2.4.2"
+			},
+			"peerDependenciesMeta": {
+				"@types/node": {
+					"optional": true
+				},
+				"@vitejs/devtools": {
+					"optional": true
+				},
+				"esbuild": {
+					"optional": true
+				},
+				"jiti": {
+					"optional": true
+				},
+				"less": {
+					"optional": true
+				},
+				"sass": {
+					"optional": true
+				},
+				"sass-embedded": {
+					"optional": true
+				},
+				"stylus": {
+					"optional": true
+				},
+				"sugarss": {
+					"optional": true
+				},
+				"terser": {
+					"optional": true
+				},
+				"tsx": {
+					"optional": true
+				},
+				"yaml": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz",
+			"integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==",
+			"dev": true,
+			"license": "MPL-2.0",
+			"dependencies": {
+				"detect-libc": "^2.0.3"
+			},
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			},
+			"optionalDependencies": {
+				"lightningcss-android-arm64": "1.33.0",
+				"lightningcss-darwin-arm64": "1.33.0",
+				"lightningcss-darwin-x64": "1.33.0",
+				"lightningcss-freebsd-x64": "1.33.0",
+				"lightningcss-linux-arm-gnueabihf": "1.33.0",
+				"lightningcss-linux-arm64-gnu": "1.33.0",
+				"lightningcss-linux-arm64-musl": "1.33.0",
+				"lightningcss-linux-x64-gnu": "1.33.0",
+				"lightningcss-linux-x64-musl": "1.33.0",
+				"lightningcss-win32-arm64-msvc": "1.33.0",
+				"lightningcss-win32-x64-msvc": "1.33.0"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-android-arm64": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz",
+			"integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-darwin-arm64": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz",
+			"integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-darwin-x64": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz",
+			"integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-freebsd-x64": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz",
+			"integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"freebsd"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-linux-arm-gnueabihf": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz",
+			"integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-linux-arm64-gnu": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz",
+			"integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"libc": [
+				"glibc"
+			],
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-linux-arm64-musl": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz",
+			"integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"libc": [
+				"musl"
+			],
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-linux-x64-gnu": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz",
+			"integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"libc": [
+				"glibc"
+			],
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-linux-x64-musl": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz",
+			"integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"libc": [
+				"musl"
+			],
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-win32-arm64-msvc": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz",
+			"integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vite/node_modules/lightningcss-win32-x64-msvc": {
+			"version": "1.33.0",
+			"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz",
+			"integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"license": "MPL-2.0",
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/vitefu": {
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz",
+			"integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==",
+			"dev": true,
+			"license": "MIT",
+			"workspaces": [
+				"tests/deps/*",
+				"tests/projects/*",
+				"tests/projects/workspace/packages/*"
+			],
+			"peerDependencies": {
+				"vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+			},
+			"peerDependenciesMeta": {
+				"vite": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/zimmerframe": {
+			"version": "1.1.4",
+			"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
+			"integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
+			"dev": true,
+			"license": "MIT"
+		}
+	}
 }
 }

+ 16 - 11
package.json

@@ -1,6 +1,6 @@
 {
 {
 	"name": "@database.pizza/olive",
 	"name": "@database.pizza/olive",
-	"version": "0.0.1",
+	"version": "0.1.0",
 	"type": "module",
 	"type": "module",
 	"scripts": {
 	"scripts": {
 		"dev": "vite dev",
 		"dev": "vite dev",
@@ -14,34 +14,39 @@
 	},
 	},
 	"exports": {
 	"exports": {
 		".": {
 		".": {
-			"types": "./src/lib/index.ts",
-			"svelte": "./src/lib/index.ts",
-			"default": "./src/lib/index.ts"
+			"types": "./dist/index.d.ts",
+			"svelte": "./dist/index.js",
+			"default": "./dist/index.js"
 		},
 		},
-		"./styles": "./src/lib/styles.css"
+		"./styles": "./dist/styles.css",
+		"./tokens": "./dist/tokens.css",
+		"./tokens.css": "./dist/tokens.css"
 	},
 	},
-	"svelte": "./src/lib/index.ts",
+	"svelte": "./dist/index.js",
 	"types": "./dist/index.d.ts",
 	"types": "./dist/index.d.ts",
 	"files": [
 	"files": [
 		"dist"
 		"dist"
 	],
 	],
+	"dependencies": {
+		"tailwindcss": "^4.2.4"
+	},
 	"devDependencies": {
 	"devDependencies": {
 		"@sveltejs/adapter-auto": "^7.0.1",
 		"@sveltejs/adapter-auto": "^7.0.1",
 		"@sveltejs/kit": "^2.57.0",
 		"@sveltejs/kit": "^2.57.0",
 		"@sveltejs/package": "^2.5.7",
 		"@sveltejs/package": "^2.5.7",
 		"@sveltejs/vite-plugin-svelte": "^7.0.0",
 		"@sveltejs/vite-plugin-svelte": "^7.0.0",
+		"@tailwindcss/vite": "^4.2.4",
 		"publint": "^0.3.18",
 		"publint": "^0.3.18",
 		"svelte": "^5.55.2",
 		"svelte": "^5.55.2",
 		"svelte-check": "^4.4.6",
 		"svelte-check": "^4.4.6",
 		"typescript": "^6.0.2",
 		"typescript": "^6.0.2",
 		"vite": "^8.0.7"
 		"vite": "^8.0.7"
 	},
 	},
-	"dependencies": {
-		"@tailwindcss/vite": "^4.2.4",
-		"tailwindcss": "^4.2.4"
-	},
 	"peerDependencies": {
 	"peerDependencies": {
-		"svelte": "^5.0.0",
+		"svelte": "^5.20.0",
 		"@sveltejs/kit": "^2.0.0"
 		"@sveltejs/kit": "^2.0.0"
+	},
+	"overrides": {
+		"cookie": "^0.7.2"
 	}
 	}
 }
 }

+ 1 - 114
src/app.css

@@ -1,117 +1,4 @@
-@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap");
-@import "tailwindcss";
-
-/* ─── Design Tokens ─────────────────────────────────────────────────────── */
-
-@theme {
-  /* Fonts */
-  --font-sans: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
-  --font-mono: ui-monospace, "Cascadia Code", "Source Code Pro", "Fira Code", monospace;
-
-  /* Olive primitive palette */
-  --color-olive-50:  hsl(75 60% 96%);
-  --color-olive-100: hsl(75 60% 90%);
-  --color-olive-200: hsl(75 58% 78%);
-  --color-olive-300: hsl(75 56% 66%);
-  --color-olive-400: hsl(75 58% 54%);
-  --color-olive-500: hsl(75 60% 44%);
-  --color-olive-600: hsl(75 55% 38%);
-  --color-olive-700: hsl(75 50% 32%);
-  --color-olive-800: hsl(75 45% 24%);
-  --color-olive-900: hsl(75 40% 16%);
-
-  /* Border radius */
-  --radius: 0.75rem;        /* 12px — cards, panels, inputs */
-  --radius-button: 0.4375rem; /* 7px  — buttons specifically */
-  --radius-sm: calc(var(--radius) * 0.5);
-  --radius-lg: calc(var(--radius) * 1.5);
-  --radius-full: 9999px;
-
-  /* Motion */
-  --duration-micro:  100ms;
-  --duration-fast:   150ms;
-  --duration-base:   200ms;
-  --duration-slow:   250ms;
-  --duration-page:   350ms;
-
-  --ease-enter: cubic-bezier(0.16, 1, 0.3, 1);
-  --ease-exit:  cubic-bezier(0.4, 0, 1, 1);
-  --ease-move:  cubic-bezier(0.25, 0.46, 0.45, 0.94);
-}
-
-/* ─── Semantic color variables ──────────────────────────────────────────── */
-
-:root {
-  --background:          hsl(60 8% 95%);
-  --foreground:          hsl(70 8% 15%);
-
-  --card:                hsl(60 6% 97%);
-  --card-foreground:     hsl(70 8% 15%);
-
-  --muted:               hsl(65 8% 91%);
-  --muted-foreground:    hsl(70 4% 45%);
-
-  --border:              hsl(65 6% 86%);
-
-  --primary:             hsl(75 60% 44%);
-  --primary-foreground:  hsl(70 8% 15%);
-
-  --destructive:         hsl(0 55% 52%);
-  --destructive-foreground: hsl(0 0% 98%);
-
-  --ring:                hsl(75 60% 44%);
-
-  --shadow-sm: 0 1px 2px hsl(70 8% 15% / 0.06);
-  --shadow-md: 0 4px 12px hsl(70 8% 15% / 0.08);
-  --shadow-lg: 0 8px 24px hsl(70 8% 15% / 0.10);
-}
-
-.dark {
-  --background:          hsl(70 4% 9%);
-  --foreground:          hsl(60 8% 85%);
-
-  --card:                hsl(70 4% 11%);
-  --card-foreground:     hsl(60 8% 85%);
-
-  --muted:               hsl(70 4% 15%);
-  --muted-foreground:    hsl(65 4% 50%);
-
-  --border:              hsl(70 4% 18%);
-
-  --primary:             hsl(75 55% 52%);
-  --primary-foreground:  hsl(70 4% 9%);
-
-  --destructive:         hsl(0 45% 42%);
-  --destructive-foreground: hsl(0 0% 98%);
-
-  --ring:                hsl(75 55% 52%);
-
-  --shadow-sm: 0 1px 2px hsl(70 4% 4% / 0.4);
-  --shadow-md: 0 4px 12px hsl(70 4% 4% / 0.5);
-  --shadow-lg: 0 8px 24px hsl(70 4% 4% / 0.6);
-}
-
-/* ─── Tailwind v4 CSS variable bridge ───────────────────────────────────── */
-/*
-   Tailwind v4 uses @theme for its utility generation, but our semantic tokens
-   live in :root/:dark. We bridge them here so Tailwind utilities like
-   bg-background, text-foreground etc. work correctly.
-*/
-
-@theme inline {
-  --color-background:         var(--background);
-  --color-foreground:         var(--foreground);
-  --color-card:               var(--card);
-  --color-card-foreground:    var(--card-foreground);
-  --color-muted:              var(--muted);
-  --color-muted-foreground:   var(--muted-foreground);
-  --color-border:             var(--border);
-  --color-primary:            var(--primary);
-  --color-primary-foreground: var(--primary-foreground);
-  --color-destructive:        var(--destructive);
-  --color-destructive-foreground: var(--destructive-foreground);
-  --color-ring:               var(--ring);
-}
+@import "./lib/styles.css";
 
 
 /* ─── Base styles ───────────────────────────────────────────────────────── */
 /* ─── Base styles ───────────────────────────────────────────────────────── */
 
 

+ 23 - 8
src/lib/components/data/DataTable.svelte

@@ -104,16 +104,25 @@
         <tr class="border-b border-[var(--border)] bg-[var(--muted)]/40">
         <tr class="border-b border-[var(--border)] bg-[var(--muted)]/40">
           {#each columns as col}
           {#each columns as col}
             <th
             <th
+              scope="col"
+              aria-sort={col.sortable
+                ? sortKey === col.key
+                  ? sortDir === 'asc' ? 'ascending' : sortDir === 'desc' ? 'descending' : 'none'
+                  : 'none'
+                : undefined}
               class={cn(
               class={cn(
                 'px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-[var(--muted-foreground)]',
                 'px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-[var(--muted-foreground)]',
-                col.sortable && 'cursor-pointer select-none hover:text-[var(--foreground)] transition-colors'
+                col.sortable && 'select-none'
               )}
               )}
               style={col.width ? `width: ${col.width}` : ''}
               style={col.width ? `width: ${col.width}` : ''}
-              onclick={() => col.sortable && toggleSort(col.key)}
             >
             >
-              <span class="inline-flex items-center gap-1.5">
-                {col.header}
-                {#if col.sortable}
+              {#if col.sortable}
+                <button
+                  type="button"
+                  onclick={() => toggleSort(col.key)}
+                  class="inline-flex cursor-pointer items-center gap-1.5 rounded-sm hover:text-[var(--foreground)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] transition-colors"
+                >
+                  {col.header}
                   <span class="flex flex-col gap-px">
                   <span class="flex flex-col gap-px">
                     <svg width="8" height="5" viewBox="0 0 8 5" class={cn('transition-colors', sortKey === col.key && sortDir === 'asc' ? 'text-[var(--foreground)]' : 'text-[var(--border)]')}>
                     <svg width="8" height="5" viewBox="0 0 8 5" class={cn('transition-colors', sortKey === col.key && sortDir === 'asc' ? 'text-[var(--foreground)]' : 'text-[var(--border)]')}>
                       <path d="M0 5L4 0L8 5H0Z" fill="currentColor"/>
                       <path d="M0 5L4 0L8 5H0Z" fill="currentColor"/>
@@ -122,8 +131,10 @@
                       <path d="M0 0L4 5L8 0H0Z" fill="currentColor"/>
                       <path d="M0 0L4 5L8 0H0Z" fill="currentColor"/>
                     </svg>
                     </svg>
                   </span>
                   </span>
-                {/if}
-              </span>
+                </button>
+              {:else}
+                {col.header}
+              {/if}
             </th>
             </th>
           {/each}
           {/each}
         </tr>
         </tr>
@@ -137,7 +148,7 @@
           {#each paged as row, i}
           {#each paged as row, i}
             <tr class={cn('border-b border-[var(--border)] last:border-0 transition-colors duration-[100ms] hover:bg-[var(--muted)]/30', i % 2 === 1 && 'bg-[var(--muted)]/10')}>
             <tr class={cn('border-b border-[var(--border)] last:border-0 transition-colors duration-[100ms] hover:bg-[var(--muted)]/30', i % 2 === 1 && 'bg-[var(--muted)]/10')}>
               {#each columns as col}
               {#each columns as col}
-                <td class="px-4 py-3 text-[var(--foreground)]">{@html cellValue(row, col)}</td>
+                <td class="px-4 py-3 text-[var(--foreground)]">{cellValue(row, col)}</td>
               {/each}
               {/each}
             </tr>
             </tr>
           {/each}
           {/each}
@@ -152,6 +163,7 @@
       <div class="flex items-center gap-1">
       <div class="flex items-center gap-1">
         <button
         <button
           type="button"
           type="button"
+          aria-label="Previous page"
           onclick={() => page = Math.max(0, page - 1)}
           onclick={() => page = Math.max(0, page - 1)}
           disabled={page === 0}
           disabled={page === 0}
           class={cn(
           class={cn(
@@ -168,6 +180,8 @@
           {#if totalPages <= 7 || p === 0 || p === totalPages - 1 || Math.abs(p - page) <= 1}
           {#if totalPages <= 7 || p === 0 || p === totalPages - 1 || Math.abs(p - page) <= 1}
             <button
             <button
               type="button"
               type="button"
+              aria-label={`Page ${p + 1}`}
+              aria-current={p === page ? 'page' : undefined}
               onclick={() => page = p}
               onclick={() => page = p}
               class={cn(
               class={cn(
                 'flex h-7 min-w-7 cursor-pointer items-center justify-center rounded-[var(--radius-button)] border px-1.5 text-xs transition-colors',
                 'flex h-7 min-w-7 cursor-pointer items-center justify-center rounded-[var(--radius-button)] border px-1.5 text-xs transition-colors',
@@ -183,6 +197,7 @@
 
 
         <button
         <button
           type="button"
           type="button"
+          aria-label="Next page"
           onclick={() => page = Math.min(totalPages - 1, page + 1)}
           onclick={() => page = Math.min(totalPages - 1, page + 1)}
           disabled={page === totalPages - 1}
           disabled={page === totalPages - 1}
           class={cn(
           class={cn(

+ 11 - 6
src/lib/components/data/JsonViewer.svelte

@@ -1,4 +1,5 @@
 <script lang="ts">
 <script lang="ts">
+  import { untrack } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
   import JsonViewer from './JsonViewer.svelte';
   import JsonViewer from './JsonViewer.svelte';
 
 
@@ -36,14 +37,18 @@
     return 0;
     return 0;
   }
   }
 
 
-  let collapsed = $state(depth >= expandDepth);
+  let collapsed = $state(untrack(() => depth >= expandDepth));
 
 
-  const type = getType(data);
-  const expandable = isExpandable(data);
-  const count = entryCount(data);
+  let type = $derived(getType(data));
+  let expandable = $derived(isExpandable(data));
+  let count = $derived(entryCount(data));
 
 
-  const openBracket = type === 'array' ? '[' : '{';
-  const closeBracket = type === 'array' ? ']' : '}';
+  let openBracket = $derived(type === 'array' ? '[' : '{');
+  let closeBracket = $derived(type === 'array' ? ']' : '}');
+
+  $effect(() => {
+    collapsed = depth >= expandDepth;
+  });
 
 
   let entries = $derived.by((): [string, unknown][] => {
   let entries = $derived.by((): [string, unknown][] => {
     if (type === 'array') return (data as unknown[]).map((v, i) => [String(i), v]);
     if (type === 'array') return (data as unknown[]).map((v, i) => [String(i), v]);

+ 1 - 0
src/lib/components/data/KanbanCard.svelte

@@ -36,6 +36,7 @@
 </script>
 </script>
 
 
 <div
 <div
+  role="listitem"
   {draggable}
   {draggable}
   ondragstart={handleDragStart}
   ondragstart={handleDragStart}
   ondragend={() => { dragging = false; }}
   ondragend={() => { dragging = false; }}

+ 4 - 2
src/lib/components/data/KanbanColumn.svelte

@@ -36,6 +36,8 @@
 </script>
 </script>
 
 
 <div
 <div
+  role="group"
+  aria-label={`${title} drop zone`}
   ondragover={handleDragOver}
   ondragover={handleDragOver}
   ondragleave={() => { over = false; }}
   ondragleave={() => { over = false; }}
   ondrop={handleDrop}
   ondrop={handleDrop}
@@ -56,13 +58,13 @@
   </div>
   </div>
 
 
   <!-- Cards -->
   <!-- Cards -->
-  <div class="flex flex-1 flex-col gap-2 overflow-y-auto p-2.5 min-h-[120px]">
+  <div role="list" aria-label={title} class="flex flex-1 flex-col gap-2 overflow-y-auto p-2.5 min-h-[120px]">
     {#if children}
     {#if children}
       {@render children()}
       {@render children()}
     {/if}
     {/if}
 
 
     {#if over}
     {#if over}
-      <div class="rounded-[var(--radius)] border-2 border-dashed border-[var(--primary)]/40 h-14 transition-all duration-[150ms]"></div>
+      <div role="presentation" class="rounded-[var(--radius)] border-2 border-dashed border-[var(--primary)]/40 h-14 transition-all duration-[150ms]"></div>
     {/if}
     {/if}
   </div>
   </div>
 </div>
 </div>

+ 8 - 0
src/lib/components/data/Table.svelte

@@ -32,6 +32,12 @@
     if (val === null || val === undefined) return '—';
     if (val === null || val === undefined) return '—';
     return String(val);
     return String(val);
   }
   }
+
+  function handleRowKeydown(event: KeyboardEvent, row: Record<string, unknown>) {
+    if (!onrowclick || (event.key !== 'Enter' && event.key !== ' ')) return;
+    event.preventDefault();
+    onrowclick(row);
+  }
 </script>
 </script>
 
 
 <div class={cn('w-full overflow-x-auto rounded-[var(--radius)] border border-[var(--border)]', className)}>
 <div class={cn('w-full overflow-x-auto rounded-[var(--radius)] border border-[var(--border)]', className)}>
@@ -52,12 +58,14 @@
     <tbody>
     <tbody>
       {#each rows as row, i (rowKey ? row[rowKey as string] : i)}
       {#each rows as row, i (rowKey ? row[rowKey as string] : i)}
         <tr
         <tr
+          tabindex={onrowclick ? 0 : undefined}
           class={cn(
           class={cn(
             'border-b border-[var(--border)] last:border-0',
             'border-b border-[var(--border)] last:border-0',
             'transition-colors duration-[100ms]',
             'transition-colors duration-[100ms]',
             onrowclick ? 'cursor-pointer hover:bg-[var(--muted)]/50' : 'hover:bg-[var(--muted)]/30',
             onrowclick ? 'cursor-pointer hover:bg-[var(--muted)]/50' : 'hover:bg-[var(--muted)]/30',
           )}
           )}
           onclick={() => onrowclick?.(row)}
           onclick={() => onrowclick?.(row)}
+          onkeydown={(event) => handleRowKeydown(event, row)}
         >
         >
           {#each columns as col}
           {#each columns as col}
             <td
             <td

+ 72 - 9
src/lib/components/forms/Combobox.svelte

@@ -1,5 +1,7 @@
 <script lang="ts">
 <script lang="ts">
+  import { getContext } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { formFieldContext, type FormFieldContext } from '$lib/utils/form-field.js';
 
 
   interface Option {
   interface Option {
     value: string;
     value: string;
@@ -13,6 +15,9 @@
     placeholder?: string;
     placeholder?: string;
     disabled?: boolean;
     disabled?: boolean;
     error?: boolean;
     error?: boolean;
+    id?: string;
+    'aria-label'?: string;
+    'aria-describedby'?: string;
     class?: string;
     class?: string;
     onchange?: (value: string) => void;
     onchange?: (value: string) => void;
   }
   }
@@ -23,17 +28,26 @@
     placeholder = 'Select…',
     placeholder = 'Select…',
     disabled = false,
     disabled = false,
     error = false,
     error = false,
+    id,
+    'aria-label': ariaLabel,
+    'aria-describedby': ariaDescribedby,
     class: className = '',
     class: className = '',
     onchange,
     onchange,
   }: Props = $props();
   }: Props = $props();
+  const field = getContext<FormFieldContext | undefined>(formFieldContext);
+  const componentId = $props.id();
+  const listboxId = `${componentId}-listbox`;
+  let controlId = $derived(id ?? field?.controlId ?? `${componentId}-control`);
 
 
   let open = $state(false);
   let open = $state(false);
   let query = $state('');
   let query = $state('');
+  let editing = $state(false);
   let activeIndex = $state(0);
   let activeIndex = $state(0);
   let containerEl = $state<HTMLElement | null>(null);
   let containerEl = $state<HTMLElement | null>(null);
   let inputEl = $state<HTMLInputElement | null>(null);
   let inputEl = $state<HTMLInputElement | null>(null);
 
 
   let selected = $derived(options.find(o => o.value === value));
   let selected = $derived(options.find(o => o.value === value));
+  let displayValue = $derived(editing ? query : selected?.label ?? '');
 
 
   let filtered = $derived(
   let filtered = $derived(
     query
     query
@@ -44,19 +58,39 @@
   function select(opt: Option) {
   function select(opt: Option) {
     value = opt.value;
     value = opt.value;
     query = '';
     query = '';
+    editing = false;
     open = false;
     open = false;
     onchange?.(opt.value);
     onchange?.(opt.value);
   }
   }
 
 
   function handleInputKeydown(e: KeyboardEvent) {
   function handleInputKeydown(e: KeyboardEvent) {
-    if (e.key === 'Escape') { open = false; return; }
-    if (e.key === 'ArrowDown') { e.preventDefault(); activeIndex = Math.min(activeIndex + 1, filtered.length - 1); }
-    if (e.key === 'ArrowUp') { e.preventDefault(); activeIndex = Math.max(activeIndex - 1, 0); }
-    if (e.key === 'Enter') { e.preventDefault(); if (filtered[activeIndex]) select(filtered[activeIndex]); }
+    if (e.key === 'Escape') {
+      open = false;
+      query = '';
+      editing = false;
+    } else if (e.key === 'ArrowDown') {
+      e.preventDefault();
+      activeIndex = open ? Math.min(activeIndex + 1, filtered.length - 1) : 0;
+      open = true;
+    } else if (e.key === 'ArrowUp') {
+      e.preventDefault();
+      activeIndex = open ? Math.max(activeIndex - 1, 0) : Math.max(filtered.length - 1, 0);
+      open = true;
+    } else if (e.key === 'Enter') {
+      e.preventDefault();
+      if (open && filtered[activeIndex]) select(filtered[activeIndex]);
+      else open = true;
+    } else if (e.key === 'Tab') {
+      open = false;
+    }
   }
   }
 
 
   function handleOutside(e: MouseEvent) {
   function handleOutside(e: MouseEvent) {
-    if (containerEl && !containerEl.contains(e.target as Node)) { open = false; query = ''; }
+    if (containerEl && !containerEl.contains(e.target as Node)) {
+      open = false;
+      query = '';
+      editing = false;
+    }
   }
   }
 
 
   $effect(() => {
   $effect(() => {
@@ -66,6 +100,11 @@
       return () => document.removeEventListener('click', handleOutside);
       return () => document.removeEventListener('click', handleOutside);
     }
     }
   });
   });
+
+  $effect(() => {
+    query;
+    activeIndex = 0;
+  });
 </script>
 </script>
 
 
 <div class={cn('relative', className)} bind:this={containerEl}>
 <div class={cn('relative', className)} bind:this={containerEl}>
@@ -80,20 +119,35 @@
   >
   >
     <input
     <input
       bind:this={inputEl}
       bind:this={inputEl}
+      id={controlId}
       type="text"
       type="text"
       {disabled}
       {disabled}
-      placeholder={selected ? selected.label : placeholder}
-      bind:value={query}
+      placeholder={placeholder}
+      value={displayValue}
+      oninput={(event) => {
+        editing = true;
+        query = event.currentTarget.value;
+        open = true;
+      }}
       onfocus={() => { open = true; }}
       onfocus={() => { open = true; }}
       onkeydown={handleInputKeydown}
       onkeydown={handleInputKeydown}
+      role="combobox"
+      aria-label={ariaLabel}
+      aria-expanded={open}
+      aria-autocomplete="list"
+      aria-controls={listboxId}
+      aria-activedescendant={open && filtered.length > 0 ? `${componentId}-option-${activeIndex}` : undefined}
+      aria-describedby={ariaDescribedby ?? field?.descriptionId}
+      aria-invalid={error || field?.invalid ? 'true' : undefined}
       class={cn(
       class={cn(
         'flex-1 bg-transparent px-3 py-1 text-sm focus:outline-none',
         'flex-1 bg-transparent px-3 py-1 text-sm focus:outline-none',
-        selected && !query ? 'text-[var(--foreground)]' : 'text-[var(--foreground)] placeholder:text-[var(--muted-foreground)]',
+        'text-[var(--foreground)] placeholder:text-[var(--muted-foreground)]',
         disabled && 'cursor-not-allowed'
         disabled && 'cursor-not-allowed'
       )}
       )}
     />
     />
     <button
     <button
       type="button"
       type="button"
+      aria-label={open ? 'Close options' : 'Open options'}
       {disabled}
       {disabled}
       tabindex="-1"
       tabindex="-1"
       onclick={() => { open = !open; if (open) inputEl?.focus(); }}
       onclick={() => { open = !open; if (open) inputEl?.focus(); }}
@@ -107,6 +161,8 @@
 
 
   {#if open}
   {#if open}
     <div
     <div
+      id={listboxId}
+      role="listbox"
       class={cn(
       class={cn(
         'absolute top-full z-50 mt-1 w-full',
         'absolute top-full z-50 mt-1 w-full',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
@@ -119,7 +175,11 @@
       {:else}
       {:else}
         {#each filtered as opt, i}
         {#each filtered as opt, i}
           <button
           <button
+            id={`${componentId}-option-${i}`}
             type="button"
             type="button"
+            role="option"
+            aria-selected={opt.value === value}
+            tabindex="-1"
             onclick={() => select(opt)}
             onclick={() => select(opt)}
             onmouseenter={() => { activeIndex = i; }}
             onmouseenter={() => { activeIndex = i; }}
             class={cn(
             class={cn(
@@ -129,6 +189,9 @@
             )}
             )}
           >
           >
             <span class="flex-1 text-left truncate">{opt.label}</span>
             <span class="flex-1 text-left truncate">{opt.label}</span>
+            {#if opt.description}
+              <span class="truncate text-xs text-[var(--muted-foreground)]">{opt.description}</span>
+            {/if}
             {#if opt.value === value}
             {#if opt.value === value}
               <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
               <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
                 <path d="M20 6L9 17l-5-5"/>
                 <path d="M20 6L9 17l-5-5"/>
@@ -142,7 +205,7 @@
 </div>
 </div>
 
 
 <style>
 <style>
-  @keyframes popoverIn {
+  @keyframes -global-popoverIn {
     from { opacity: 0; transform: scale(0.97) translateY(-4px); }
     from { opacity: 0; transform: scale(0.97) translateY(-4px); }
     to   { opacity: 1; transform: scale(1) translateY(0); }
     to   { opacity: 1; transform: scale(1) translateY(0); }
   }
   }

+ 134 - 43
src/lib/components/forms/DatePicker.svelte

@@ -1,11 +1,16 @@
 <script lang="ts">
 <script lang="ts">
+  import { getContext } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { formFieldContext, type FormFieldContext } from '$lib/utils/form-field.js';
 
 
   interface Props {
   interface Props {
     value?: Date | null;
     value?: Date | null;
     placeholder?: string;
     placeholder?: string;
     disabled?: boolean;
     disabled?: boolean;
     error?: boolean;
     error?: boolean;
+    id?: string;
+    'aria-label'?: string;
+    'aria-describedby'?: string;
     min?: Date;
     min?: Date;
     max?: Date;
     max?: Date;
     class?: string;
     class?: string;
@@ -17,25 +22,29 @@
     placeholder = 'Pick a date…',
     placeholder = 'Pick a date…',
     disabled = false,
     disabled = false,
     error = false,
     error = false,
+    id,
+    'aria-label': ariaLabel,
+    'aria-describedby': ariaDescribedby,
     min,
     min,
     max,
     max,
     class: className = '',
     class: className = '',
     onchange,
     onchange,
   }: Props = $props();
   }: Props = $props();
+  const field = getContext<FormFieldContext | undefined>(formFieldContext);
+  const componentId = $props.id();
+  const dialogId = `${componentId}-dialog`;
+  let controlId = $derived(id ?? field?.controlId ?? `${componentId}-control`);
 
 
   let open = $state(false);
   let open = $state(false);
   let containerEl = $state<HTMLElement | null>(null);
   let containerEl = $state<HTMLElement | null>(null);
+  let triggerEl = $state<HTMLButtonElement | null>(null);
+  let dialogEl = $state<HTMLElement | null>(null);
 
 
   const DAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
   const DAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
   const MONTHS = ['January','February','March','April','May','June','July','August','September','October','November','December'];
   const MONTHS = ['January','February','March','April','May','June','July','August','September','October','November','December'];
 
 
-  let cursor = $state(() => {
-    const d = value ?? new Date();
-    return { year: d.getFullYear(), month: d.getMonth() };
-  });
-
-  let viewYear = $state(cursor().year);
-  let viewMonth = $state(cursor().month);
+  let viewYear = $state(new Date().getFullYear());
+  let viewMonth = $state(new Date().getMonth());
 
 
   function daysInMonth(y: number, m: number) { return new Date(y, m + 1, 0).getDate(); }
   function daysInMonth(y: number, m: number) { return new Date(y, m + 1, 0).getDate(); }
   function firstWeekday(y: number, m: number) { return new Date(y, m, 1).getDay(); }
   function firstWeekday(y: number, m: number) { return new Date(y, m, 1).getDay(); }
@@ -68,6 +77,7 @@
     value = new Date(viewYear, viewMonth, day);
     value = new Date(viewYear, viewMonth, day);
     open = false;
     open = false;
     onchange?.(value);
     onchange?.(value);
+    queueMicrotask(() => triggerEl?.focus());
   }
   }
 
 
   function prevMonth() {
   function prevMonth() {
@@ -80,17 +90,76 @@
     else viewMonth++;
     else viewMonth++;
   }
   }
 
 
+  function dateLabel(day: number) {
+    return new Date(viewYear, viewMonth, day).toLocaleDateString('en-US', {
+      weekday: 'long',
+      month: 'long',
+      day: 'numeric',
+      year: 'numeric',
+    });
+  }
+
+  function dateKey(year: number, month: number, day: number) {
+    return `${year}-${month + 1}-${day}`;
+  }
+
+  let focusableDay = $derived.by(() => {
+    if (value && value.getFullYear() === viewYear && value.getMonth() === viewMonth && !isDisabled(value.getDate())) {
+      return value.getDate();
+    }
+    const today = new Date();
+    if (today.getFullYear() === viewYear && today.getMonth() === viewMonth && !isDisabled(today.getDate())) {
+      return today.getDate();
+    }
+    return Array.from({ length: daysInMonth(viewYear, viewMonth) }, (_, index) => index + 1)
+      .find(day => !isDisabled(day)) ?? -1;
+  });
+
+  function focusDate(date: Date) {
+    viewYear = date.getFullYear();
+    viewMonth = date.getMonth();
+    queueMicrotask(() => {
+      dialogEl?.querySelector<HTMLElement>(`[data-date="${dateKey(date.getFullYear(), date.getMonth(), date.getDate())}"]`)?.focus();
+    });
+  }
+
+  function handleDayKeydown(event: KeyboardEvent, day: number) {
+    let offset = 0;
+    if (event.key === 'ArrowLeft') offset = -1;
+    else if (event.key === 'ArrowRight') offset = 1;
+    else if (event.key === 'ArrowUp') offset = -7;
+    else if (event.key === 'ArrowDown') offset = 7;
+    else if (event.key === 'Home') offset = -new Date(viewYear, viewMonth, day).getDay();
+    else if (event.key === 'End') offset = 6 - new Date(viewYear, viewMonth, day).getDay();
+    else return;
+
+    event.preventDefault();
+    focusDate(new Date(viewYear, viewMonth, day + offset));
+  }
+
   function handleOutside(e: MouseEvent) {
   function handleOutside(e: MouseEvent) {
     if (containerEl && !containerEl.contains(e.target as Node)) { open = false; }
     if (containerEl && !containerEl.contains(e.target as Node)) { open = false; }
   }
   }
 
 
   $effect(() => {
   $effect(() => {
     if (open) {
     if (open) {
+      const date = value ?? new Date();
+      viewYear = date.getFullYear();
+      viewMonth = date.getMonth();
       document.addEventListener('click', handleOutside);
       document.addEventListener('click', handleOutside);
+      queueMicrotask(() => dialogEl?.querySelector<HTMLElement>('[data-calendar-day][tabindex="0"]')?.focus());
       return () => document.removeEventListener('click', handleOutside);
       return () => document.removeEventListener('click', handleOutside);
     }
     }
   });
   });
 
 
+  function handleKeydown(event: KeyboardEvent) {
+    if (event.key === 'Escape' && open) {
+      event.preventDefault();
+      open = false;
+      queueMicrotask(() => triggerEl?.focus());
+    }
+  }
+
   let displayValue = $derived(
   let displayValue = $derived(
     value
     value
       ? value.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
       ? value.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
@@ -98,11 +167,19 @@
   );
   );
 </script>
 </script>
 
 
-<div class={cn('relative', className)} bind:this={containerEl}>
+<!-- svelte-ignore a11y_no_static_element_interactions -->
+<div class={cn('relative', className)} bind:this={containerEl} onkeydown={handleKeydown}>
   <button
   <button
+    bind:this={triggerEl}
+    id={controlId}
     type="button"
     type="button"
     {disabled}
     {disabled}
     onclick={() => { if (!disabled) open = !open; }}
     onclick={() => { if (!disabled) open = !open; }}
+    aria-label={ariaLabel}
+    aria-haspopup="dialog"
+    aria-expanded={open}
+    aria-controls={dialogId}
+    aria-describedby={ariaDescribedby ?? field?.descriptionId}
     class={cn(
     class={cn(
       'flex h-9 w-full items-center gap-2 rounded-[var(--radius)] border bg-transparent px-3 text-sm',
       'flex h-9 w-full items-center gap-2 rounded-[var(--radius)] border bg-transparent px-3 text-sm',
       'transition-colors duration-[150ms]',
       'transition-colors duration-[150ms]',
@@ -120,6 +197,7 @@
   {#if value}
   {#if value}
     <button
     <button
       type="button"
       type="button"
+      {disabled}
       onclick={(e) => { e.stopPropagation(); value = null; onchange?.(null); }}
       onclick={(e) => { e.stopPropagation(); value = null; onchange?.(null); }}
       class="absolute right-2.5 top-1/2 -translate-y-1/2 flex h-4 w-4 cursor-pointer items-center justify-center rounded-full text-[var(--muted-foreground)] hover:text-[var(--foreground)] transition-colors"
       class="absolute right-2.5 top-1/2 -translate-y-1/2 flex h-4 w-4 cursor-pointer items-center justify-center rounded-full text-[var(--muted-foreground)] hover:text-[var(--foreground)] transition-colors"
       aria-label="Clear date"
       aria-label="Clear date"
@@ -132,6 +210,10 @@
 
 
   {#if open}
   {#if open}
     <div
     <div
+      bind:this={dialogEl}
+      id={dialogId}
+      role="dialog"
+      aria-label="Choose date"
       class={cn(
       class={cn(
         'absolute top-full z-50 mt-1',
         'absolute top-full z-50 mt-1',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
@@ -164,40 +246,49 @@
         </button>
         </button>
       </div>
       </div>
 
 
-      <!-- Day names -->
-      <div class="mb-1 grid grid-cols-7">
-        {#each DAYS as d}
-          <div class="flex h-7 items-center justify-center text-xs font-medium text-[var(--muted-foreground)]">{d}</div>
-        {/each}
-      </div>
-
-      <!-- Day cells -->
-      <div class="grid grid-cols-7 gap-y-0.5">
-        {#each cells as day}
-          {#if day === null}
-            <div></div>
-          {:else}
-            {@const sel = isSelected(day)}
-            {@const tod = isToday(day)}
-            {@const dis = isDisabled(day)}
-            <button
-              type="button"
-              onclick={() => selectDay(day)}
-              disabled={dis}
-              class={cn(
-                'flex h-8 w-full items-center justify-center rounded-[var(--radius-button)] text-sm transition-colors duration-[100ms]',
-                sel
-                  ? 'bg-[var(--primary)] text-[var(--primary-foreground)] font-medium'
-                  : tod
-                    ? 'border border-[var(--primary)] text-[var(--primary)] font-medium hover:bg-[var(--primary)]/10'
-                    : 'text-[var(--foreground)] hover:bg-[var(--muted)]',
-                dis && 'opacity-30 cursor-not-allowed',
-                !dis && !sel && 'cursor-pointer'
-              )}
-            >
-              {day}
-            </button>
-          {/if}
+      <div class="grid grid-cols-7 gap-y-0.5" role="grid" aria-label={`${MONTHS[viewMonth]} ${viewYear}`}>
+        <div role="row" class="contents">
+          {#each DAYS as d}
+            <div role="columnheader" class="mb-1 flex h-7 items-center justify-center text-xs font-medium text-[var(--muted-foreground)]">{d}</div>
+          {/each}
+        </div>
+        {#each Array.from({ length: Math.ceil(cells.length / 7) }, (_, week) => cells.slice(week * 7, week * 7 + 7)) as week}
+          <div role="row" class="contents">
+            {#each Array.from({ length: 7 }, (_, index) => week[index] ?? null) as day}
+              {#if day === null}
+                <div role="gridcell" aria-hidden="true"></div>
+              {:else}
+                {@const sel = isSelected(day)}
+                {@const tod = isToday(day)}
+                {@const dis = isDisabled(day)}
+                <button
+                  type="button"
+                  role="gridcell"
+                  aria-label={dateLabel(day)}
+                  aria-selected={sel}
+                  aria-current={tod ? 'date' : undefined}
+                  data-calendar-day
+                  data-date={dateKey(viewYear, viewMonth, day)}
+                  tabindex={day === focusableDay ? 0 : -1}
+                  onclick={() => selectDay(day)}
+                  onkeydown={(event) => handleDayKeydown(event, day)}
+                  disabled={dis}
+                  class={cn(
+                    'flex h-8 w-full items-center justify-center rounded-[var(--radius-button)] text-sm transition-colors duration-[100ms]',
+                    sel
+                      ? 'bg-[var(--primary)] text-[var(--primary-foreground)] font-medium'
+                      : tod
+                        ? 'border border-[var(--primary)] text-[var(--primary)] font-medium hover:bg-[var(--primary)]/10'
+                        : 'text-[var(--foreground)] hover:bg-[var(--muted)]',
+                    dis && 'opacity-30 cursor-not-allowed',
+                    !dis && !sel && 'cursor-pointer'
+                  )}
+                >
+                  {day}
+                </button>
+              {/if}
+            {/each}
+          </div>
         {/each}
         {/each}
       </div>
       </div>
     </div>
     </div>
@@ -205,7 +296,7 @@
 </div>
 </div>
 
 
 <style>
 <style>
-  @keyframes popoverIn {
+  @keyframes -global-popoverIn {
     from { opacity: 0; transform: scale(0.97) translateY(-4px); }
     from { opacity: 0; transform: scale(0.97) translateY(-4px); }
     to   { opacity: 1; transform: scale(1) translateY(0); }
     to   { opacity: 1; transform: scale(1) translateY(0); }
   }
   }

+ 10 - 6
src/lib/components/forms/FormField.svelte

@@ -2,6 +2,7 @@
   import type { Snippet } from 'svelte';
   import type { Snippet } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
   import { setContext } from 'svelte';
   import { setContext } from 'svelte';
+  import { formFieldContext, type FormFieldContext } from '$lib/utils/form-field.js';
 
 
   interface Props {
   interface Props {
     name?: string;
     name?: string;
@@ -12,19 +13,22 @@
   }
   }
 
 
   let { name = '', error = '', hint = '', class: className = '', children }: Props = $props();
   let { name = '', error = '', hint = '', class: className = '', children }: Props = $props();
+  const fieldId = $props.id();
+  const controlId = `${fieldId}-control`;
+  const descriptionId = `${fieldId}-description`;
 
 
-  setContext('form-field', {
-    get name() { return name; },
-    get error() { return error; },
-    get hint() { return hint; },
+  setContext<FormFieldContext>(formFieldContext, {
+    get controlId() { return controlId; },
+    get descriptionId() { return error || hint ? descriptionId : undefined; },
+    get invalid() { return !!error; },
   });
   });
 </script>
 </script>
 
 
 <div class={cn('flex flex-col gap-1.5', className)}>
 <div class={cn('flex flex-col gap-1.5', className)}>
   {#if children}{@render children()}{/if}
   {#if children}{@render children()}{/if}
   {#if error}
   {#if error}
-    <p class="text-xs text-[var(--destructive)]">{error}</p>
+    <p id={descriptionId} role="alert" class="text-xs text-[var(--destructive)]">{error}</p>
   {:else if hint}
   {:else if hint}
-    <p class="text-xs text-[var(--muted-foreground)]">{hint}</p>
+    <p id={descriptionId} class="text-xs text-[var(--muted-foreground)]">{hint}</p>
   {/if}
   {/if}
 </div>
 </div>

+ 91 - 7
src/lib/components/forms/MultiSelect.svelte

@@ -1,5 +1,7 @@
 <script lang="ts">
 <script lang="ts">
+  import { getContext } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { formFieldContext, type FormFieldContext } from '$lib/utils/form-field.js';
 
 
   interface Option {
   interface Option {
     value: string;
     value: string;
@@ -12,6 +14,9 @@
     placeholder?: string;
     placeholder?: string;
     disabled?: boolean;
     disabled?: boolean;
     error?: boolean;
     error?: boolean;
+    id?: string;
+    'aria-label'?: string;
+    'aria-describedby'?: string;
     max?: number;
     max?: number;
     class?: string;
     class?: string;
     onchange?: (values: string[]) => void;
     onchange?: (values: string[]) => void;
@@ -23,10 +28,18 @@
     placeholder = 'Select…',
     placeholder = 'Select…',
     disabled = false,
     disabled = false,
     error = false,
     error = false,
+    id,
+    'aria-label': ariaLabel,
+    'aria-describedby': ariaDescribedby,
     max,
     max,
     class: className = '',
     class: className = '',
     onchange,
     onchange,
   }: Props = $props();
   }: Props = $props();
+  const field = getContext<FormFieldContext | undefined>(formFieldContext);
+  const componentId = $props.id();
+  const listboxId = `${componentId}-listbox`;
+  const selectedDescriptionId = `${componentId}-selection`;
+  let controlId = $derived(id ?? field?.controlId ?? `${componentId}-control`);
 
 
   let open = $state(false);
   let open = $state(false);
   let query = $state('');
   let query = $state('');
@@ -41,6 +54,35 @@
   );
   );
 
 
   let selectedOptions = $derived(options.filter(o => value.includes(o.value)));
   let selectedOptions = $derived(options.filter(o => value.includes(o.value)));
+  let describedBy = $derived(
+    [ariaDescribedby ?? field?.descriptionId, value.length > 0 ? selectedDescriptionId : undefined]
+      .filter(Boolean)
+      .join(' ') || undefined
+  );
+
+  function optionDisabled(opt: Option) {
+    return !value.includes(opt.value) && !!max && value.length >= max;
+  }
+
+  function enabledIndexes() {
+    return filtered
+      .map((opt, index) => optionDisabled(opt) ? -1 : index)
+      .filter(index => index >= 0);
+  }
+
+  function moveActive(direction: 1 | -1) {
+    const indexes = enabledIndexes();
+    if (indexes.length === 0) {
+      activeIndex = -1;
+      return;
+    }
+    const current = indexes.indexOf(activeIndex);
+    if (!open || current === -1) {
+      activeIndex = direction === 1 ? indexes[0] : indexes[indexes.length - 1];
+      return;
+    }
+    activeIndex = indexes[Math.max(0, Math.min(indexes.length - 1, current + direction))];
+  }
 
 
   function toggle(opt: Option) {
   function toggle(opt: Option) {
     if (value.includes(opt.value)) {
     if (value.includes(opt.value)) {
@@ -59,15 +101,28 @@
   }
   }
 
 
   function handleKeydown(e: KeyboardEvent) {
   function handleKeydown(e: KeyboardEvent) {
-    if (e.key === 'Escape') { open = false; return; }
+    if (e.key === 'Escape') { open = false; query = ''; return; }
     if (e.key === 'Backspace' && !query && value.length > 0) {
     if (e.key === 'Backspace' && !query && value.length > 0) {
       value = value.slice(0, -1);
       value = value.slice(0, -1);
       onchange?.(value);
       onchange?.(value);
       return;
       return;
     }
     }
-    if (e.key === 'ArrowDown') { e.preventDefault(); activeIndex = Math.min(activeIndex + 1, filtered.length - 1); }
-    if (e.key === 'ArrowUp') { e.preventDefault(); activeIndex = Math.max(activeIndex - 1, 0); }
-    if (e.key === 'Enter') { e.preventDefault(); if (filtered[activeIndex]) toggle(filtered[activeIndex]); }
+    if (e.key === 'ArrowDown') {
+      e.preventDefault();
+      moveActive(1);
+      open = true;
+    }
+    if (e.key === 'ArrowUp') {
+      e.preventDefault();
+      moveActive(-1);
+      open = true;
+    }
+    if (e.key === 'Enter') {
+      e.preventDefault();
+      if (open && filtered[activeIndex] && !optionDisabled(filtered[activeIndex])) toggle(filtered[activeIndex]);
+      else open = true;
+    }
+    if (e.key === 'Tab') open = false;
   }
   }
 
 
   function handleOutside(e: MouseEvent) {
   function handleOutside(e: MouseEvent) {
@@ -76,11 +131,16 @@
 
 
   $effect(() => {
   $effect(() => {
     if (open) {
     if (open) {
-      activeIndex = 0;
+      activeIndex = enabledIndexes()[0] ?? -1;
       document.addEventListener('click', handleOutside);
       document.addEventListener('click', handleOutside);
       return () => document.removeEventListener('click', handleOutside);
       return () => document.removeEventListener('click', handleOutside);
     }
     }
   });
   });
+
+  $effect(() => {
+    query;
+    activeIndex = enabledIndexes()[0] ?? -1;
+  });
 </script>
 </script>
 
 
 <div class={cn('relative', className)} bind:this={containerEl}>
 <div class={cn('relative', className)} bind:this={containerEl}>
@@ -100,6 +160,7 @@
         {opt.label}
         {opt.label}
         <button
         <button
           type="button"
           type="button"
+          {disabled}
           onclick={(e) => { e.stopPropagation(); removeTag(opt.value); }}
           onclick={(e) => { e.stopPropagation(); removeTag(opt.value); }}
           class="flex h-3.5 w-3.5 cursor-pointer items-center justify-center rounded-full text-[var(--muted-foreground)] hover:text-[var(--foreground)] transition-colors"
           class="flex h-3.5 w-3.5 cursor-pointer items-center justify-center rounded-full text-[var(--muted-foreground)] hover:text-[var(--foreground)] transition-colors"
           aria-label="Remove {opt.label}"
           aria-label="Remove {opt.label}"
@@ -113,20 +174,36 @@
 
 
     <input
     <input
       bind:this={inputEl}
       bind:this={inputEl}
+      id={controlId}
       type="text"
       type="text"
       {disabled}
       {disabled}
       placeholder={value.length === 0 ? placeholder : ''}
       placeholder={value.length === 0 ? placeholder : ''}
       bind:value={query}
       bind:value={query}
       onfocus={() => { open = true; }}
       onfocus={() => { open = true; }}
       onkeydown={handleKeydown}
       onkeydown={handleKeydown}
+      role="combobox"
+      aria-label={ariaLabel}
+      aria-expanded={open}
+      aria-autocomplete="list"
+      aria-controls={listboxId}
+      aria-activedescendant={open && activeIndex >= 0 ? `${componentId}-option-${activeIndex}` : undefined}
+      aria-describedby={describedBy}
+      aria-invalid={error || field?.invalid ? 'true' : undefined}
       class={cn(
       class={cn(
         'flex-1 min-w-[80px] bg-transparent text-sm text-[var(--foreground)] placeholder:text-[var(--muted-foreground)] focus:outline-none',
         'flex-1 min-w-[80px] bg-transparent text-sm text-[var(--foreground)] placeholder:text-[var(--muted-foreground)] focus:outline-none',
         disabled && 'cursor-not-allowed'
         disabled && 'cursor-not-allowed'
       )}
       )}
     />
     />
 
 
+    {#if value.length > 0}
+      <span id={selectedDescriptionId} class="sr-only">
+        Selected: {selectedOptions.map(option => option.label).join(', ')}
+      </span>
+    {/if}
+
     <button
     <button
       type="button"
       type="button"
+      aria-label={open ? 'Close options' : 'Open options'}
       {disabled}
       {disabled}
       tabindex="-1"
       tabindex="-1"
       onclick={() => { open = !open; if (open) inputEl?.focus(); }}
       onclick={() => { open = !open; if (open) inputEl?.focus(); }}
@@ -140,6 +217,9 @@
 
 
   {#if open}
   {#if open}
     <div
     <div
+      id={listboxId}
+      role="listbox"
+      aria-multiselectable="true"
       class={cn(
       class={cn(
         'absolute top-full z-50 mt-1 w-full',
         'absolute top-full z-50 mt-1 w-full',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
@@ -152,9 +232,13 @@
       {:else}
       {:else}
         {#each filtered as opt, i}
         {#each filtered as opt, i}
           {@const selected = value.includes(opt.value)}
           {@const selected = value.includes(opt.value)}
-          {@const atMax = !selected && !!max && value.length >= max}
+          {@const atMax = optionDisabled(opt)}
           <button
           <button
+            id={`${componentId}-option-${i}`}
             type="button"
             type="button"
+            role="option"
+            aria-selected={selected}
+            tabindex="-1"
             onclick={() => toggle(opt)}
             onclick={() => toggle(opt)}
             onmouseenter={() => { activeIndex = i; }}
             onmouseenter={() => { activeIndex = i; }}
             disabled={atMax}
             disabled={atMax}
@@ -193,7 +277,7 @@
 </div>
 </div>
 
 
 <style>
 <style>
-  @keyframes popoverIn {
+  @keyframes -global-popoverIn {
     from { opacity: 0; transform: scale(0.97) translateY(-4px); }
     from { opacity: 0; transform: scale(0.97) translateY(-4px); }
     to   { opacity: 1; transform: scale(1) translateY(0); }
     to   { opacity: 1; transform: scale(1) translateY(0); }
   }
   }

+ 29 - 2
src/lib/components/layout/Tabs.svelte

@@ -27,12 +27,33 @@
     children,
     children,
     onchange,
     onchange,
   }: Props = $props();
   }: Props = $props();
+  const tabsId = $props.id();
 
 
   function select(id: string) {
   function select(id: string) {
     active = id;
     active = id;
     onchange?.(id);
     onchange?.(id);
   }
   }
 
 
+  function handleKeydown(event: KeyboardEvent) {
+    if (!['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) return;
+
+    event.preventDefault();
+    const current = event.currentTarget as HTMLButtonElement;
+    const buttons = Array.from(current.parentElement?.querySelectorAll<HTMLButtonElement>('[role="tab"]:not(:disabled)') ?? []);
+    const currentIndex = buttons.indexOf(current);
+    let nextIndex = currentIndex;
+
+    if (event.key === 'Home') nextIndex = 0;
+    else if (event.key === 'End') nextIndex = buttons.length - 1;
+    else if (event.key === 'ArrowRight' || event.key === 'ArrowDown') nextIndex = (currentIndex + 1) % buttons.length;
+    else nextIndex = (currentIndex - 1 + buttons.length) % buttons.length;
+
+    const next = buttons[nextIndex];
+    if (!next) return;
+    next.focus();
+    select(next.dataset.tabId ?? '');
+  }
+
   setContext('tabs', { get active() { return active; } });
   setContext('tabs', { get active() { return active; } });
 </script>
 </script>
 
 
@@ -44,11 +65,15 @@
   >
   >
     {#each tabs as tab}
     {#each tabs as tab}
       <button
       <button
+        id={`${tabsId}-tab-${tab.id}`}
+        data-tab-id={tab.id}
         role="tab"
         role="tab"
         aria-selected={active === tab.id}
         aria-selected={active === tab.id}
-        aria-controls="tabpanel-{tab.id}"
+        aria-controls={`${tabsId}-panel`}
+        tabindex={active === tab.id ? 0 : -1}
         disabled={tab.disabled}
         disabled={tab.disabled}
         onclick={() => select(tab.id)}
         onclick={() => select(tab.id)}
+        onkeydown={handleKeydown}
         class={cn(
         class={cn(
           'relative flex items-center gap-1.5 px-3.5 py-2.5 text-sm font-medium',
           'relative flex items-center gap-1.5 px-3.5 py-2.5 text-sm font-medium',
           'whitespace-nowrap transition-colors duration-[150ms]',
           'whitespace-nowrap transition-colors duration-[150ms]',
@@ -73,8 +98,10 @@
 
 
   <!-- Panel -->
   <!-- Panel -->
   <div
   <div
-    id="tabpanel-{active}"
+    id={`${tabsId}-panel`}
     role="tabpanel"
     role="tabpanel"
+    aria-labelledby={`${tabsId}-tab-${active}`}
+    tabindex="0"
     class={cn('mt-4', panelClass)}
     class={cn('mt-4', panelClass)}
   >
   >
     {#if children}{@render children(active)}{/if}
     {#if children}{@render children(active)}{/if}

+ 40 - 18
src/lib/components/navigation/CommandPalette.svelte

@@ -1,6 +1,7 @@
 <script lang="ts">
 <script lang="ts">
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
   import { browser } from '$app/environment';
   import { browser } from '$app/environment';
+  import { modal } from '$lib/utils/modal.js';
 
 
   interface CommandItem {
   interface CommandItem {
     id: string;
     id: string;
@@ -28,7 +29,8 @@
 
 
   let query = $state('');
   let query = $state('');
   let activeIndex = $state(0);
   let activeIndex = $state(0);
-  let inputEl = $state<HTMLInputElement | null>(null);
+  const paletteId = $props.id();
+  const listboxId = `${paletteId}-listbox`;
 
 
   function close() {
   function close() {
     open = false;
     open = false;
@@ -56,7 +58,6 @@
   });
   });
 
 
   function handleKeydown(e: KeyboardEvent) {
   function handleKeydown(e: KeyboardEvent) {
-    if (e.key === 'Escape') { close(); return; }
     if (e.key === 'ArrowDown') {
     if (e.key === 'ArrowDown') {
       e.preventDefault();
       e.preventDefault();
       activeIndex = Math.min(activeIndex + 1, filtered.length - 1);
       activeIndex = Math.min(activeIndex + 1, filtered.length - 1);
@@ -64,8 +65,11 @@
       e.preventDefault();
       e.preventDefault();
       activeIndex = Math.max(activeIndex - 1, 0);
       activeIndex = Math.max(activeIndex - 1, 0);
     } else if (e.key === 'Enter') {
     } else if (e.key === 'Enter') {
-      filtered[activeIndex]?.onselect();
-      close();
+      const item = filtered[activeIndex];
+      if (item) {
+        item.onselect();
+        close();
+      }
     }
     }
   }
   }
 
 
@@ -74,7 +78,8 @@
     const handler = (e: KeyboardEvent) => {
     const handler = (e: KeyboardEvent) => {
       if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
       if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
         e.preventDefault();
         e.preventDefault();
-        open = !open;
+        if (open) close();
+        else open = true;
       }
       }
     };
     };
     document.addEventListener('keydown', handler);
     document.addEventListener('keydown', handler);
@@ -82,30 +87,42 @@
   });
   });
 
 
   $effect(() => {
   $effect(() => {
-    if (open) setTimeout(() => inputEl?.focus(), 10);
+    query;
+    activeIndex = 0;
   });
   });
 
 
-  // Track global index across groups for keyboard nav
-  let flatIndex = $state(0);
-  $effect(() => { flatIndex; activeIndex = 0; });
+  function portal(node: HTMLElement) {
+    document.body.appendChild(node);
+    return { destroy: () => node.remove() };
+  }
+
+  function handleBackdrop(event: MouseEvent) {
+    if (event.target === event.currentTarget) close();
+  }
 </script>
 </script>
 
 
 {#if open}
 {#if open}
-  <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
+  <!-- svelte-ignore a11y_click_events_have_key_events -->
   <div
   <div
-    class="fixed inset-0 z-[60] flex items-start justify-center pt-[15vh] px-4"
-    onclick={(e) => { if (e.target === e.currentTarget) close(); }}
+    use:portal
+    role="presentation"
+    class="fixed inset-0 z-[100] flex items-start justify-center pt-[15vh] px-4"
+    onclick={handleBackdrop}
   >
   >
-    <div class="absolute inset-0 bg-black/40 backdrop-blur-sm animate-[fadeIn_150ms_ease-out]"></div>
+    <div class="pointer-events-none absolute inset-0 bg-black/40 backdrop-blur-sm animate-[fadeIn_150ms_ease-out]"></div>
 
 
     <div
     <div
+      use:modal={{ onEscape: close, initialFocus: 'input' }}
+      role="dialog"
+      aria-modal="true"
+      aria-label="Command palette"
+      tabindex="-1"
       class={cn(
       class={cn(
         'relative z-10 w-full max-w-lg overflow-hidden',
         'relative z-10 w-full max-w-lg overflow-hidden',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
         'shadow-[var(--shadow-lg)]',
         'shadow-[var(--shadow-lg)]',
         'animate-[slideUpFadeIn_200ms_cubic-bezier(0.16,1,0.3,1)]'
         'animate-[slideUpFadeIn_200ms_cubic-bezier(0.16,1,0.3,1)]'
       )}
       )}
-      onkeydown={handleKeydown}
     >
     >
       <!-- Search input -->
       <!-- Search input -->
       <div class="flex items-center gap-3 border-b border-[var(--border)] px-4">
       <div class="flex items-center gap-3 border-b border-[var(--border)] px-4">
@@ -113,20 +130,23 @@
           <circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
           <circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
         </svg>
         </svg>
         <input
         <input
-          bind:this={inputEl}
           bind:value={query}
           bind:value={query}
           {placeholder}
           {placeholder}
           type="text"
           type="text"
           role="combobox"
           role="combobox"
           aria-expanded="true"
           aria-expanded="true"
           aria-autocomplete="list"
           aria-autocomplete="list"
+          aria-controls={listboxId}
+          aria-activedescendant={filtered.length > 0 ? `${paletteId}-option-${activeIndex}` : undefined}
+          aria-label="Search commands"
+          onkeydown={handleKeydown}
           class="flex-1 bg-transparent py-4 text-sm text-[var(--foreground)] placeholder:text-[var(--muted-foreground)] focus:outline-none"
           class="flex-1 bg-transparent py-4 text-sm text-[var(--foreground)] placeholder:text-[var(--muted-foreground)] focus:outline-none"
         />
         />
         <kbd class="hidden sm:flex items-center gap-1 rounded border border-[var(--border)] bg-[var(--muted)] px-1.5 py-0.5 text-xs text-[var(--muted-foreground)]">Esc</kbd>
         <kbd class="hidden sm:flex items-center gap-1 rounded border border-[var(--border)] bg-[var(--muted)] px-1.5 py-0.5 text-xs text-[var(--muted-foreground)]">Esc</kbd>
       </div>
       </div>
 
 
       <!-- Results -->
       <!-- Results -->
-      <div class="max-h-[340px] overflow-y-auto py-2" role="listbox">
+      <div id={listboxId} class="max-h-[340px] overflow-y-auto py-2" role="listbox" aria-label="Commands">
         {#if filtered.length === 0}
         {#if filtered.length === 0}
           <p class="px-4 py-10 text-center text-sm text-[var(--muted-foreground)]">No results for "{query}"</p>
           <p class="px-4 py-10 text-center text-sm text-[var(--muted-foreground)]">No results for "{query}"</p>
         {:else}
         {:else}
@@ -137,8 +157,10 @@
             {#each groupItems as item, i}
             {#each groupItems as item, i}
               {@const idx = filtered.indexOf(item)}
               {@const idx = filtered.indexOf(item)}
               <button
               <button
+                id={`${paletteId}-option-${idx}`}
                 role="option"
                 role="option"
                 aria-selected={idx === activeIndex}
                 aria-selected={idx === activeIndex}
+                tabindex="-1"
                 onclick={() => { item.onselect(); close(); }}
                 onclick={() => { item.onselect(); close(); }}
                 onmouseenter={() => { activeIndex = idx; }}
                 onmouseenter={() => { activeIndex = idx; }}
                 class={cn(
                 class={cn(
@@ -170,10 +192,10 @@
 {/if}
 {/if}
 
 
 <style>
 <style>
-  @keyframes fadeIn {
+  @keyframes -global-fadeIn {
     from { opacity: 0; } to { opacity: 1; }
     from { opacity: 0; } to { opacity: 1; }
   }
   }
-  @keyframes slideUpFadeIn {
+  @keyframes -global-slideUpFadeIn {
     from { opacity: 0; transform: translateY(-8px) scale(0.98); }
     from { opacity: 0; transform: translateY(-8px) scale(0.98); }
     to   { opacity: 1; transform: translateY(0) scale(1); }
     to   { opacity: 1; transform: translateY(0) scale(1); }
   }
   }

+ 15 - 0
src/lib/components/navigation/Navbar.svelte

@@ -20,8 +20,19 @@
   }: Props = $props();
   }: Props = $props();
 
 
   let menuOpen = $state(false);
   let menuOpen = $state(false);
+  let menuButton = $state<HTMLButtonElement | null>(null);
+  const navbarId = $props.id();
+  const menuId = `${navbarId}-mobile-menu`;
+
+  function handleKeydown(event: KeyboardEvent) {
+    if (event.key !== 'Escape' || !menuOpen) return;
+    event.preventDefault();
+    menuOpen = false;
+    menuButton?.focus();
+  }
 </script>
 </script>
 
 
+<!-- svelte-ignore a11y_no_static_element_interactions -->
 <header
 <header
   class={cn(
   class={cn(
     'sticky top-0 z-40 h-14 w-full',
     'sticky top-0 z-40 h-14 w-full',
@@ -29,6 +40,7 @@
     'border-b border-[var(--border)]',
     'border-b border-[var(--border)]',
     className
     className
   )}
   )}
+  onkeydown={handleKeydown}
 >
 >
   <div class="mx-auto flex h-full w-full max-w-7xl items-center gap-4 px-4 sm:px-6 lg:px-8">
   <div class="mx-auto flex h-full w-full max-w-7xl items-center gap-4 px-4 sm:px-6 lg:px-8">
     <!-- Logo -->
     <!-- Logo -->
@@ -59,9 +71,11 @@
       <!-- Mobile menu button -->
       <!-- Mobile menu button -->
       {#if nav}
       {#if nav}
         <button
         <button
+          bind:this={menuButton}
           type="button"
           type="button"
           aria-label="Toggle menu"
           aria-label="Toggle menu"
           aria-expanded={menuOpen}
           aria-expanded={menuOpen}
+          aria-controls={menuId}
           onclick={() => { menuOpen = !menuOpen; }}
           onclick={() => { menuOpen = !menuOpen; }}
           class={cn(
           class={cn(
             'md:hidden flex h-8 w-8 items-center justify-center rounded-[var(--radius)]',
             'md:hidden flex h-8 w-8 items-center justify-center rounded-[var(--radius)]',
@@ -85,6 +99,7 @@
   <!-- Mobile nav dropdown -->
   <!-- Mobile nav dropdown -->
   {#if nav && menuOpen}
   {#if nav && menuOpen}
     <div
     <div
+      id={menuId}
       class="md:hidden border-t border-[var(--border)] bg-[var(--card)]/95 backdrop-blur-xl"
       class="md:hidden border-t border-[var(--border)] bg-[var(--card)]/95 backdrop-blur-xl"
     >
     >
       <div class="mx-auto max-w-7xl px-4 py-3 flex flex-col gap-1">
       <div class="mx-auto max-w-7xl px-4 py-3 flex flex-col gap-1">

+ 15 - 4
src/lib/components/navigation/Sidebar.svelte

@@ -28,15 +28,26 @@
     collapsed = !collapsed;
     collapsed = !collapsed;
     oncollapsechange?.(collapsed);
     oncollapsechange?.(collapsed);
   }
   }
+
+  $effect(() => {
+    if (!mobileOpen) return;
+    const handleKeydown = (event: KeyboardEvent) => {
+      if (event.key === 'Escape') mobileOpen = false;
+    };
+    document.addEventListener('keydown', handleKeydown);
+    return () => document.removeEventListener('keydown', handleKeydown);
+  });
 </script>
 </script>
 
 
 <!-- Mobile overlay -->
 <!-- Mobile overlay -->
 {#if mobileOpen}
 {#if mobileOpen}
-  <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
-  <div
+  <button
+    type="button"
+    tabindex="-1"
+    aria-label="Close navigation"
     class="fixed inset-0 z-40 bg-black/40 backdrop-blur-sm lg:hidden animate-[fadeIn_150ms_ease-out]"
     class="fixed inset-0 z-40 bg-black/40 backdrop-blur-sm lg:hidden animate-[fadeIn_150ms_ease-out]"
     onclick={() => { mobileOpen = false; }}
     onclick={() => { mobileOpen = false; }}
-  ></div>
+  ></button>
 {/if}
 {/if}
 
 
 <!-- Sidebar panel -->
 <!-- Sidebar panel -->
@@ -108,7 +119,7 @@
 </aside>
 </aside>
 
 
 <style>
 <style>
-  @keyframes fadeIn {
+  @keyframes -global-fadeIn {
     from { opacity: 0; } to { opacity: 1; }
     from { opacity: 0; } to { opacity: 1; }
   }
   }
 </style>
 </style>

+ 16 - 11
src/lib/components/overlay/AlertDialog.svelte

@@ -1,6 +1,7 @@
 <script lang="ts">
 <script lang="ts">
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
   import Button from '$lib/components/primitives/Button.svelte';
   import Button from '$lib/components/primitives/Button.svelte';
+  import { modal } from '$lib/utils/modal.js';
 
 
   interface Props {
   interface Props {
     open?: boolean;
     open?: boolean;
@@ -24,6 +25,8 @@
     oncancel,
     oncancel,
   }: Props = $props();
   }: Props = $props();
 
 
+  const dialogId = $props.id();
+
   function cancel() {
   function cancel() {
     open = false;
     open = false;
     oncancel?.();
     oncancel?.();
@@ -34,25 +37,27 @@
     onconfirm?.();
     onconfirm?.();
   }
   }
 
 
-  function handleKeydown(e: KeyboardEvent) {
-    if (e.key === 'Escape') cancel();
+  function portal(node: HTMLElement) {
+    document.body.appendChild(node);
+    return { destroy: () => node.remove() };
   }
   }
 </script>
 </script>
 
 
 {#if open}
 {#if open}
   <div
   <div
+    use:portal
     role="presentation"
     role="presentation"
-    class="fixed inset-0 z-50 flex items-center justify-center p-4"
+    class="fixed inset-0 z-[100] flex items-center justify-center p-4"
   >
   >
     <div class="absolute inset-0 bg-black/50 backdrop-blur-sm animate-[fadeIn_200ms_ease-out]"></div>
     <div class="absolute inset-0 bg-black/50 backdrop-blur-sm animate-[fadeIn_200ms_ease-out]"></div>
 
 
     <div
     <div
+      use:modal={{ onEscape: cancel, initialFocus: '[data-modal-autofocus]' }}
       role="alertdialog"
       role="alertdialog"
       aria-modal="true"
       aria-modal="true"
       tabindex="-1"
       tabindex="-1"
-      aria-labelledby="alert-title"
-      aria-describedby={description ? 'alert-desc' : undefined}
-      onkeydown={handleKeydown}
+      aria-labelledby={`${dialogId}-title`}
+      aria-describedby={description ? `${dialogId}-description` : undefined}
       class={cn(
       class={cn(
         'relative z-10 w-full max-w-sm max-w-[calc(100vw-2rem)]',
         'relative z-10 w-full max-w-sm max-w-[calc(100vw-2rem)]',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
@@ -61,14 +66,14 @@
       )}
       )}
     >
     >
       <div class="px-6 pt-6 pb-4">
       <div class="px-6 pt-6 pb-4">
-        <h2 id="alert-title" class="text-base font-semibold text-[var(--foreground)]">{title}</h2>
+        <h2 id={`${dialogId}-title`} class="text-base font-semibold text-[var(--foreground)]">{title}</h2>
         {#if description}
         {#if description}
-          <p id="alert-desc" class="mt-2 text-sm text-[var(--muted-foreground)]">{description}</p>
+          <p id={`${dialogId}-description`} class="mt-2 text-sm text-[var(--muted-foreground)]">{description}</p>
         {/if}
         {/if}
       </div>
       </div>
 
 
       <div class="flex items-center justify-end gap-2 border-t border-[var(--border)] px-6 py-4">
       <div class="flex items-center justify-end gap-2 border-t border-[var(--border)] px-6 py-4">
-        <Button variant="outline" size="sm" onclick={cancel}>{cancelLabel}</Button>
+        <Button data-modal-autofocus variant="outline" size="sm" onclick={cancel}>{cancelLabel}</Button>
         <Button variant={destructive ? 'destructive' : 'default'} size="sm" onclick={confirm}>{confirmLabel}</Button>
         <Button variant={destructive ? 'destructive' : 'default'} size="sm" onclick={confirm}>{confirmLabel}</Button>
       </div>
       </div>
     </div>
     </div>
@@ -76,11 +81,11 @@
 {/if}
 {/if}
 
 
 <style>
 <style>
-  @keyframes fadeIn {
+  @keyframes -global-fadeIn {
     from { opacity: 0; }
     from { opacity: 0; }
     to   { opacity: 1; }
     to   { opacity: 1; }
   }
   }
-  @keyframes slideUpFadeIn {
+  @keyframes -global-slideUpFadeIn {
     from { opacity: 0; transform: translateY(8px) scale(0.97); }
     from { opacity: 0; transform: translateY(8px) scale(0.97); }
     to   { opacity: 1; transform: translateY(0) scale(1); }
     to   { opacity: 1; transform: translateY(0) scale(1); }
   }
   }

+ 20 - 15
src/lib/components/overlay/Dialog.svelte

@@ -1,6 +1,7 @@
 <script lang="ts">
 <script lang="ts">
   import type { Snippet } from 'svelte';
   import type { Snippet } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { modal } from '$lib/utils/modal.js';
 
 
   interface Props {
   interface Props {
     open?: boolean;
     open?: boolean;
@@ -22,6 +23,8 @@
     onclose,
     onclose,
   }: Props = $props();
   }: Props = $props();
 
 
+  const dialogId = $props.id();
+
   function close() {
   function close() {
     open = false;
     open = false;
     onclose?.();
     onclose?.();
@@ -31,8 +34,9 @@
     if (e.target === e.currentTarget) close();
     if (e.target === e.currentTarget) close();
   }
   }
 
 
-  function handleKeydown(e: KeyboardEvent) {
-    if (e.key === 'Escape') close();
+  function portal(node: HTMLElement) {
+    document.body.appendChild(node);
+    return { destroy: () => node.remove() };
   }
   }
 </script>
 </script>
 
 
@@ -40,23 +44,24 @@
   <!-- Backdrop -->
   <!-- Backdrop -->
   <!-- svelte-ignore a11y_click_events_have_key_events -->
   <!-- svelte-ignore a11y_click_events_have_key_events -->
   <div
   <div
+    use:portal
     role="presentation"
     role="presentation"
-    class="fixed inset-0 z-50 flex items-center justify-center p-4"
+    class="fixed inset-0 z-[100] flex items-center justify-center overflow-y-auto p-4"
     onclick={handleBackdrop}
     onclick={handleBackdrop}
   >
   >
     <!-- Overlay -->
     <!-- Overlay -->
-    <div class="absolute inset-0 bg-black/40 backdrop-blur-sm animate-[fadeIn_200ms_ease-out]"></div>
+    <div class="pointer-events-none absolute inset-0 bg-black/40 backdrop-blur-sm animate-[fadeIn_200ms_ease-out]"></div>
 
 
     <!-- Panel -->
     <!-- Panel -->
     <div
     <div
+      use:modal={{ onEscape: close }}
       role="dialog"
       role="dialog"
       aria-modal="true"
       aria-modal="true"
       tabindex="-1"
       tabindex="-1"
-      aria-labelledby={title ? 'dialog-title' : undefined}
-      aria-describedby={description ? 'dialog-desc' : undefined}
-      onkeydown={handleKeydown}
+      aria-labelledby={title ? `${dialogId}-title` : undefined}
+      aria-describedby={description ? `${dialogId}-description` : undefined}
       class={cn(
       class={cn(
-        'relative z-10 w-full max-w-md max-w-[calc(100vw-2rem)]',
+        'relative z-10 my-auto flex max-h-[calc(100dvh-2rem)] w-full max-w-md max-w-[calc(100vw-2rem)] flex-col overflow-hidden',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
         'shadow-[var(--shadow-lg)]',
         'shadow-[var(--shadow-lg)]',
         'animate-[slideUpFadeIn_250ms_cubic-bezier(0.16,1,0.3,1)]',
         'animate-[slideUpFadeIn_250ms_cubic-bezier(0.16,1,0.3,1)]',
@@ -65,12 +70,12 @@
     >
     >
       <!-- Header -->
       <!-- Header -->
       {#if title || description}
       {#if title || description}
-        <div class="px-6 pt-6 pb-4">
+        <div class="shrink-0 px-6 pt-6 pb-4">
           {#if title}
           {#if title}
-            <h2 id="dialog-title" class="text-base font-semibold text-[var(--foreground)]">{title}</h2>
+            <h2 id={`${dialogId}-title`} class="text-base font-semibold text-[var(--foreground)]">{title}</h2>
           {/if}
           {/if}
           {#if description}
           {#if description}
-            <p id="dialog-desc" class="mt-1 text-sm text-[var(--muted-foreground)]">{description}</p>
+            <p id={`${dialogId}-description`} class="mt-1 text-sm text-[var(--muted-foreground)]">{description}</p>
           {/if}
           {/if}
         </div>
         </div>
       {/if}
       {/if}
@@ -94,14 +99,14 @@
 
 
       <!-- Body -->
       <!-- Body -->
       {#if children}
       {#if children}
-        <div class="px-6 {title || description ? 'pb-4' : 'pt-6 pb-4'}">
+        <div class="min-h-0 overflow-y-auto overscroll-contain px-6 {title || description ? 'pb-4' : 'pt-6 pb-4'}">
           {@render children()}
           {@render children()}
         </div>
         </div>
       {/if}
       {/if}
 
 
       <!-- Footer -->
       <!-- Footer -->
       {#if footer}
       {#if footer}
-        <div class="flex items-center justify-end gap-2 border-t border-[var(--border)] px-6 py-4">
+        <div class="flex shrink-0 items-center justify-end gap-2 border-t border-[var(--border)] px-6 py-4">
           {@render footer()}
           {@render footer()}
         </div>
         </div>
       {/if}
       {/if}
@@ -110,11 +115,11 @@
 {/if}
 {/if}
 
 
 <style>
 <style>
-  @keyframes fadeIn {
+  @keyframes -global-fadeIn {
     from { opacity: 0; }
     from { opacity: 0; }
     to   { opacity: 1; }
     to   { opacity: 1; }
   }
   }
-  @keyframes slideUpFadeIn {
+  @keyframes -global-slideUpFadeIn {
     from { opacity: 0; transform: translateY(8px) scale(0.97); }
     from { opacity: 0; transform: translateY(8px) scale(0.97); }
     to   { opacity: 1; transform: translateY(0) scale(1); }
     to   { opacity: 1; transform: translateY(0) scale(1); }
   }
   }

+ 56 - 8
src/lib/components/overlay/DropdownMenu.svelte

@@ -1,6 +1,7 @@
 <script lang="ts">
 <script lang="ts">
   import type { Snippet } from 'svelte';
   import type { Snippet } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { popupElement, popupTrigger } from '$lib/utils/popup.js';
 
 
   interface Item {
   interface Item {
     label: string;
     label: string;
@@ -22,17 +23,56 @@
   let { items, align = 'start', side = 'bottom', class: className = '', trigger }: Props = $props();
   let { items, align = 'start', side = 'bottom', class: className = '', trigger }: Props = $props();
 
 
   let open = $state(false);
   let open = $state(false);
+  let containerEl = $state<HTMLElement | null>(null);
+  let triggerEl = $state<HTMLElement | null>(null);
   let menuEl = $state<HTMLElement | null>(null);
   let menuEl = $state<HTMLElement | null>(null);
+  const dropdownId = $props.id();
+  const menuId = `${dropdownId}-menu`;
 
 
-  function toggle() { open = !open; }
+  function focusItem(index: number) {
+    queueMicrotask(() => {
+      const items = Array.from(menuEl?.querySelectorAll<HTMLButtonElement>('[role="menuitem"]:not(:disabled)') ?? []);
+      if (items.length === 0) return;
+      items[(index + items.length) % items.length]?.focus();
+    });
+  }
+
+  function toggle() {
+    open = !open;
+    if (open) focusItem(0);
+  }
   function close() { open = false; }
   function close() { open = false; }
 
 
   function handleKeydown(e: KeyboardEvent) {
   function handleKeydown(e: KeyboardEvent) {
-    if (e.key === 'Escape') close();
+    const items = Array.from(menuEl?.querySelectorAll<HTMLButtonElement>('[role="menuitem"]:not(:disabled)') ?? []);
+    const currentIndex = items.indexOf(document.activeElement as HTMLButtonElement);
+    const fromTrigger = !!triggerEl && triggerEl.contains(e.target as Node);
+
+    if (e.key === 'Escape' && open) {
+      e.preventDefault();
+      close();
+      popupElement(triggerEl)?.focus();
+    } else if (e.key === 'ArrowDown') {
+      e.preventDefault();
+      if (!open) open = true;
+      focusItem(fromTrigger ? 0 : currentIndex + 1);
+    } else if (e.key === 'ArrowUp') {
+      e.preventDefault();
+      if (!open) open = true;
+      focusItem(fromTrigger ? -1 : currentIndex - 1);
+    } else if (e.key === 'Home' && open) {
+      e.preventDefault();
+      focusItem(0);
+    } else if (e.key === 'End' && open) {
+      e.preventDefault();
+      focusItem(-1);
+    } else if (e.key === 'Tab' && open) {
+      close();
+    }
   }
   }
 
 
   function handleOutside(e: MouseEvent) {
   function handleOutside(e: MouseEvent) {
-    if (menuEl && !menuEl.contains(e.target as Node)) close();
+    if (containerEl && !containerEl.contains(e.target as Node)) close();
   }
   }
 
 
   $effect(() => {
   $effect(() => {
@@ -46,18 +86,25 @@
 <!-- svelte-ignore a11y_no_static_element_interactions -->
 <!-- svelte-ignore a11y_no_static_element_interactions -->
 <div
 <div
   class={cn('relative inline-flex', className)}
   class={cn('relative inline-flex', className)}
-  bind:this={menuEl}
+  bind:this={containerEl}
   onkeydown={handleKeydown}
   onkeydown={handleKeydown}
 >
 >
   <!-- Trigger -->
   <!-- Trigger -->
   <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
   <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
-  <div onclick={toggle} class="inline-flex">
+  <div
+    bind:this={triggerEl}
+    use:popupTrigger={{ expanded: open, controls: menuId, haspopup: 'menu' }}
+    onclick={toggle}
+    class="inline-flex"
+  >
     {#if trigger}{@render trigger()}{/if}
     {#if trigger}{@render trigger()}{/if}
   </div>
   </div>
 
 
   <!-- Menu -->
   <!-- Menu -->
   {#if open}
   {#if open}
     <div
     <div
+      bind:this={menuEl}
+      id={menuId}
       role="menu"
       role="menu"
       class={cn(
       class={cn(
         'absolute z-50 mt-1 min-w-[160px]',
         'absolute z-50 mt-1 min-w-[160px]',
@@ -70,10 +117,11 @@
     >
     >
       {#each items as item}
       {#each items as item}
         {#if item.separator}
         {#if item.separator}
-          <div class="my-1 h-px bg-[var(--border)]"></div>
+          <div role="separator" class="my-1 h-px bg-[var(--border)]"></div>
         {:else}
         {:else}
           <button
           <button
             role="menuitem"
             role="menuitem"
+            tabindex="-1"
             disabled={item.disabled}
             disabled={item.disabled}
             onclick={() => { item.onclick?.(); close(); }}
             onclick={() => { item.onclick?.(); close(); }}
             class={cn(
             class={cn(
@@ -87,7 +135,7 @@
             )}
             )}
           >
           >
             {#if item.icon}
             {#if item.icon}
-              <span class="text-[var(--muted-foreground)]">{item.icon}</span>
+              <span aria-hidden="true" class="text-[var(--muted-foreground)]">{item.icon}</span>
             {/if}
             {/if}
             {item.label}
             {item.label}
           </button>
           </button>
@@ -98,7 +146,7 @@
 </div>
 </div>
 
 
 <style>
 <style>
-  @keyframes fadeInScale {
+  @keyframes -global-fadeInScale {
     from { opacity: 0; transform: scale(0.95); }
     from { opacity: 0; transform: scale(0.95); }
     to   { opacity: 1; transform: scale(1); }
     to   { opacity: 1; transform: scale(1); }
   }
   }

+ 22 - 3
src/lib/components/overlay/Popover.svelte

@@ -1,6 +1,7 @@
 <script lang="ts">
 <script lang="ts">
   import type { Snippet } from 'svelte';
   import type { Snippet } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { popupElement, popupTrigger } from '$lib/utils/popup.js';
 
 
   type Align = 'start' | 'center' | 'end';
   type Align = 'start' | 'center' | 'end';
   type Side = 'top' | 'bottom' | 'left' | 'right';
   type Side = 'top' | 'bottom' | 'left' | 'right';
@@ -9,6 +10,7 @@
     open?: boolean;
     open?: boolean;
     align?: Align;
     align?: Align;
     side?: Side;
     side?: Side;
+    label?: string;
     class?: string;
     class?: string;
     trigger?: Snippet;
     trigger?: Snippet;
     children?: Snippet;
     children?: Snippet;
@@ -18,12 +20,16 @@
     open = $bindable(false),
     open = $bindable(false),
     align = 'start',
     align = 'start',
     side = 'bottom',
     side = 'bottom',
+    label = 'Popover',
     class: className = '',
     class: className = '',
     trigger,
     trigger,
     children,
     children,
   }: Props = $props();
   }: Props = $props();
 
 
   let containerEl = $state<HTMLElement | null>(null);
   let containerEl = $state<HTMLElement | null>(null);
+  let triggerEl = $state<HTMLElement | null>(null);
+  const componentId = $props.id();
+  const popoverId = `${componentId}-popover`;
 
 
   function toggle() { open = !open; }
   function toggle() { open = !open; }
   function close() { open = false; }
   function close() { open = false; }
@@ -33,7 +39,11 @@
   }
   }
 
 
   function handleKeydown(e: KeyboardEvent) {
   function handleKeydown(e: KeyboardEvent) {
-    if (e.key === 'Escape') close();
+    if (e.key === 'Escape' && open) {
+      e.preventDefault();
+      close();
+      popupElement(triggerEl)?.focus();
+    }
   }
   }
 
 
   $effect(() => {
   $effect(() => {
@@ -63,12 +73,21 @@
   bind:this={containerEl}
   bind:this={containerEl}
   onkeydown={handleKeydown}
   onkeydown={handleKeydown}
 >
 >
-  <div onclick={toggle} class="inline-flex">
+  <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
+  <div
+    bind:this={triggerEl}
+    use:popupTrigger={{ expanded: open, controls: popoverId, haspopup: 'dialog' }}
+    onclick={toggle}
+    class="inline-flex"
+  >
     {#if trigger}{@render trigger()}{/if}
     {#if trigger}{@render trigger()}{/if}
   </div>
   </div>
 
 
   {#if open}
   {#if open}
     <div
     <div
+      id={popoverId}
+      role="dialog"
+      aria-label={label}
       class={cn(
       class={cn(
         'absolute z-50 min-w-[220px]',
         'absolute z-50 min-w-[220px]',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
         'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)]',
@@ -85,7 +104,7 @@
 </div>
 </div>
 
 
 <style>
 <style>
-  @keyframes popoverIn {
+  @keyframes -global-popoverIn {
     from { opacity: 0; transform: scale(0.96); }
     from { opacity: 0; transform: scale(0.96); }
     to   { opacity: 1; transform: scale(1); }
     to   { opacity: 1; transform: scale(1); }
   }
   }

+ 1 - 1
src/lib/components/overlay/Progress.svelte

@@ -50,7 +50,7 @@
 </div>
 </div>
 
 
 <style>
 <style>
-  @keyframes indeterminate {
+  @keyframes -global-indeterminate {
     0%   { transform: translateX(-100%); }
     0%   { transform: translateX(-100%); }
     100% { transform: translateX(350%); }
     100% { transform: translateX(350%); }
   }
   }

+ 30 - 21
src/lib/components/overlay/Sheet.svelte

@@ -1,6 +1,7 @@
 <script lang="ts">
 <script lang="ts">
   import type { Snippet } from 'svelte';
   import type { Snippet } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { modal } from '$lib/utils/modal.js';
 
 
   type Side = 'left' | 'right' | 'top' | 'bottom';
   type Side = 'left' | 'right' | 'top' | 'bottom';
 
 
@@ -26,13 +27,20 @@
     onclose,
     onclose,
   }: Props = $props();
   }: Props = $props();
 
 
+  const sheetId = $props.id();
+
   function close() {
   function close() {
     open = false;
     open = false;
     onclose?.();
     onclose?.();
   }
   }
 
 
-  function handleKeydown(e: KeyboardEvent) {
-    if (e.key === 'Escape') close();
+  function handleBackdrop(event: MouseEvent) {
+    if (event.target === event.currentTarget) close();
+  }
+
+  function portal(node: HTMLElement) {
+    document.body.appendChild(node);
+    return { destroy: () => node.remove() };
   }
   }
 
 
   const panelClasses: Record<Side, string> = {
   const panelClasses: Record<Side, string> = {
@@ -42,33 +50,34 @@
     bottom: 'inset-x-0 bottom-0 w-full max-h-[60vh] border-t',
     bottom: 'inset-x-0 bottom-0 w-full max-h-[60vh] border-t',
   };
   };
 
 
-  const enterFrom: Record<Side, string> = {
-    right:  'translate-x-full',
-    left:   '-translate-x-full',
-    top:    '-translate-y-full',
-    bottom: 'translate-y-full',
+  const enterStyle: Record<Side, string> = {
+    right:  '--sheet-enter-x: 100%; --sheet-enter-y: 0;',
+    left:   '--sheet-enter-x: -100%; --sheet-enter-y: 0;',
+    top:    '--sheet-enter-x: 0; --sheet-enter-y: -100%;',
+    bottom: '--sheet-enter-x: 0; --sheet-enter-y: 100%;',
   };
   };
 </script>
 </script>
 
 
 {#if open}
 {#if open}
+  <!-- svelte-ignore a11y_click_events_have_key_events -->
   <div
   <div
+    use:portal
     role="presentation"
     role="presentation"
-    class="fixed inset-0 z-50 flex"
-    onkeydown={handleKeydown}
+    class="fixed inset-0 z-[100] flex"
+    onclick={handleBackdrop}
   >
   >
     <!-- Backdrop -->
     <!-- Backdrop -->
-    <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
-    <div
-      class="absolute inset-0 bg-black/40 backdrop-blur-sm animate-[fadeIn_200ms_ease-out]"
-      onclick={close}
-    ></div>
+    <div class="pointer-events-none absolute inset-0 bg-black/40 backdrop-blur-sm animate-[fadeIn_200ms_ease-out]"></div>
 
 
     <!-- Panel -->
     <!-- Panel -->
     <div
     <div
+      use:modal={{ onEscape: close }}
       role="dialog"
       role="dialog"
       aria-modal="true"
       aria-modal="true"
       tabindex="-1"
       tabindex="-1"
-      aria-labelledby={title ? 'sheet-title' : undefined}
+      aria-labelledby={title ? `${sheetId}-title` : undefined}
+      aria-describedby={description ? `${sheetId}-description` : undefined}
+      style={enterStyle[side]}
       class={cn(
       class={cn(
         'absolute flex flex-col bg-[var(--card)] border-[var(--border)]',
         'absolute flex flex-col bg-[var(--card)] border-[var(--border)]',
         'shadow-[var(--shadow-lg)]',
         'shadow-[var(--shadow-lg)]',
@@ -81,10 +90,10 @@
       <div class="flex items-start justify-between gap-4 px-6 py-5 border-b border-[var(--border)]">
       <div class="flex items-start justify-between gap-4 px-6 py-5 border-b border-[var(--border)]">
         <div>
         <div>
           {#if title}
           {#if title}
-            <h2 id="sheet-title" class="text-base font-semibold text-[var(--foreground)]">{title}</h2>
+            <h2 id={`${sheetId}-title`} class="text-base font-semibold text-[var(--foreground)]">{title}</h2>
           {/if}
           {/if}
           {#if description}
           {#if description}
-            <p class="mt-1 text-sm text-[var(--muted-foreground)]">{description}</p>
+            <p id={`${sheetId}-description`} class="mt-1 text-sm text-[var(--muted-foreground)]">{description}</p>
           {/if}
           {/if}
         </div>
         </div>
         <button
         <button
@@ -115,12 +124,12 @@
 {/if}
 {/if}
 
 
 <style>
 <style>
-  @keyframes fadeIn {
+  @keyframes -global-fadeIn {
     from { opacity: 0; }
     from { opacity: 0; }
     to   { opacity: 1; }
     to   { opacity: 1; }
   }
   }
-  @keyframes sheetIn {
-    from { opacity: 0; transform: translateX(100%); }
-    to   { opacity: 1; transform: translateX(0); }
+  @keyframes -global-sheetIn {
+    from { opacity: 0; transform: translate(var(--sheet-enter-x), var(--sheet-enter-y)); }
+    to   { opacity: 1; transform: translate(0, 0); }
   }
   }
 </style>
 </style>

+ 1 - 1
src/lib/components/overlay/Skeleton.svelte

@@ -23,7 +23,7 @@
 ></div>
 ></div>
 
 
 <style>
 <style>
-  @keyframes shimmer {
+  @keyframes -global-shimmer {
     0%, 100% { opacity: 1; }
     0%, 100% { opacity: 1; }
     50%       { opacity: 0.5; }
     50%       { opacity: 0.5; }
   }
   }

+ 1 - 1
src/lib/components/overlay/Toaster.svelte

@@ -68,7 +68,7 @@
 </div>
 </div>
 
 
 <style>
 <style>
-  @keyframes toastIn {
+  @keyframes -global-toastIn {
     from { opacity: 0; transform: translateY(8px); }
     from { opacity: 0; transform: translateY(8px); }
     to   { opacity: 1; transform: translateY(0); }
     to   { opacity: 1; transform: translateY(0); }
   }
   }

+ 37 - 18
src/lib/components/overlay/Tooltip.svelte

@@ -1,6 +1,7 @@
 <script lang="ts">
 <script lang="ts">
   import type { Snippet } from 'svelte';
   import type { Snippet } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { popupElement } from '$lib/utils/popup.js';
 
 
   type Side = 'top' | 'bottom' | 'left' | 'right';
   type Side = 'top' | 'bottom' | 'left' | 'right';
 
 
@@ -16,6 +17,23 @@
 
 
   let visible = $state(false);
   let visible = $state(false);
   let timer: ReturnType<typeof setTimeout>;
   let timer: ReturnType<typeof setTimeout>;
+  const componentId = $props.id();
+  const tooltipId = `${componentId}-tooltip`;
+
+  function describeTrigger(node: HTMLElement) {
+    const trigger = popupElement(node);
+    const previousDescription = trigger?.getAttribute('aria-describedby');
+    const description = [previousDescription, tooltipId].filter(Boolean).join(' ');
+    trigger?.setAttribute('aria-describedby', description);
+
+    return {
+      destroy() {
+        if (!trigger) return;
+        if (previousDescription) trigger.setAttribute('aria-describedby', previousDescription);
+        else trigger.removeAttribute('aria-describedby');
+      },
+    };
+  }
 
 
   function show() {
   function show() {
     timer = setTimeout(() => { visible = true; }, delay);
     timer = setTimeout(() => { visible = true; }, delay);
@@ -35,6 +53,7 @@
 </script>
 </script>
 
 
 <div
 <div
+  use:describeTrigger
   role="group"
   role="group"
   class={cn('relative inline-flex', className)}
   class={cn('relative inline-flex', className)}
   onmouseenter={show}
   onmouseenter={show}
@@ -44,26 +63,26 @@
 >
 >
   {#if children}{@render children()}{/if}
   {#if children}{@render children()}{/if}
 
 
-  {#if visible}
-    <div
-      role="tooltip"
-      class={cn(
-        'pointer-events-none absolute z-50 whitespace-nowrap',
-        'rounded-[calc(var(--radius)*0.67)] bg-[var(--foreground)] px-2.5 py-1',
-        'text-xs font-medium text-[var(--background)]',
-        'shadow-[var(--shadow-md)]',
-        'animate-[fadeInScale_150ms_cubic-bezier(0.16,1,0.3,1)]',
-        sideClasses[side],
-      )}
-    >
-      {content}
-    </div>
-  {/if}
+  <div
+    id={tooltipId}
+    role="tooltip"
+    hidden={!visible}
+    class={cn(
+      'pointer-events-none absolute z-50 whitespace-nowrap',
+      'rounded-[calc(var(--radius)*0.67)] bg-[var(--foreground)] px-2.5 py-1',
+      'text-xs font-medium text-[var(--background)]',
+      'shadow-[var(--shadow-md)]',
+      'animate-[tooltipIn_150ms_cubic-bezier(0.16,1,0.3,1)]',
+      sideClasses[side],
+    )}
+  >
+    {content}
+  </div>
 </div>
 </div>
 
 
 <style>
 <style>
-  @keyframes fadeInScale {
-    from { opacity: 0; transform: scale(0.92) translateX(-50%); }
-    to   { opacity: 1; transform: scale(1) translateX(-50%); }
+  @keyframes -global-tooltipIn {
+    from { opacity: 0; }
+    to   { opacity: 1; }
   }
   }
 </style>
 </style>

+ 35 - 9
src/lib/components/primitives/Button.svelte

@@ -1,12 +1,15 @@
 <script lang="ts">
 <script lang="ts">
   import type { Snippet } from 'svelte';
   import type { Snippet } from 'svelte';
-  import type { HTMLButtonAttributes } from 'svelte/elements';
+  import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
 
 
   type Variant = 'default' | 'outline' | 'ghost' | 'destructive' | 'link';
   type Variant = 'default' | 'outline' | 'ghost' | 'destructive' | 'link';
   type Size = 'sm' | 'md' | 'lg' | 'icon';
   type Size = 'sm' | 'md' | 'lg' | 'icon';
 
 
   interface Props extends HTMLButtonAttributes {
   interface Props extends HTMLButtonAttributes {
+    href?: string;
+    target?: HTMLAnchorAttributes['target'];
+    rel?: string;
     variant?: Variant;
     variant?: Variant;
     size?: Size;
     size?: Size;
     class?: string;
     class?: string;
@@ -16,6 +19,11 @@
   let {
   let {
     variant = 'default',
     variant = 'default',
     size = 'md',
     size = 'md',
+    href,
+    target,
+    rel,
+    disabled = false,
+    tabindex,
     class: className = '',
     class: className = '',
     children,
     children,
     ...rest
     ...rest
@@ -43,16 +51,34 @@
     lg:   'h-10 rounded-[var(--radius-button)] px-5 text-sm',
     lg:   'h-10 rounded-[var(--radius-button)] px-5 text-sm',
     icon: 'h-8 w-8 rounded-[var(--radius-button)]',
     icon: 'h-8 w-8 rounded-[var(--radius-button)]',
   };
   };
+
+  function anchorAttributes(attributes: HTMLButtonAttributes): HTMLAnchorAttributes {
+    return attributes as unknown as HTMLAnchorAttributes;
+  }
 </script>
 </script>
 
 
-<button
-  class={cn(base, variants[variant], sizes[size], className)}
-  {...rest}
->
-  {#if children}
-    {@render children()}
-  {/if}
-</button>
+{#if href}
+  <a
+    {...anchorAttributes(rest)}
+    href={disabled ? undefined : href}
+    {target}
+    {rel}
+    aria-disabled={disabled || undefined}
+    tabindex={disabled ? -1 : tabindex}
+    class={cn(base, variants[variant], sizes[size], disabled && 'pointer-events-none opacity-40', className)}
+  >
+    {#if children}{@render children()}{/if}
+  </a>
+{:else}
+  <button
+    class={cn(base, variants[variant], sizes[size], className)}
+    {disabled}
+    {tabindex}
+    {...rest}
+  >
+    {#if children}{@render children()}{/if}
+  </button>
+{/if}
 
 
 <style>
 <style>
   /* Primary — depth via top inner highlight + bottom shadow */
   /* Primary — depth via top inner highlight + bottom shadow */

+ 15 - 2
src/lib/components/primitives/Input.svelte

@@ -1,23 +1,36 @@
 <script lang="ts">
 <script lang="ts">
   import type { HTMLInputAttributes } from 'svelte/elements';
   import type { HTMLInputAttributes } from 'svelte/elements';
+  import { getContext } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { formFieldContext, type FormFieldContext } from '$lib/utils/form-field.js';
 
 
   interface Props extends HTMLInputAttributes {
   interface Props extends HTMLInputAttributes {
     class?: string;
     class?: string;
     error?: boolean;
     error?: boolean;
   }
   }
 
 
-  let { class: className = '', error = false, ...rest }: Props = $props();
+  let {
+    class: className = '',
+    error = false,
+    id,
+    'aria-describedby': ariaDescribedby,
+    'aria-invalid': ariaInvalid,
+    ...rest
+  }: Props = $props();
+  const field = getContext<FormFieldContext | undefined>(formFieldContext);
 </script>
 </script>
 
 
 <input
 <input
+  id={id ?? field?.controlId}
+  aria-describedby={ariaDescribedby ?? field?.descriptionId}
+  aria-invalid={ariaInvalid ?? (field?.invalid ? 'true' : undefined)}
   class={cn(
   class={cn(
     'flex h-9 w-full rounded-[var(--radius)] border bg-transparent px-3 py-1 text-sm',
     'flex h-9 w-full rounded-[var(--radius)] border bg-transparent px-3 py-1 text-sm',
     'text-[var(--foreground)] placeholder:text-[var(--muted-foreground)]',
     'text-[var(--foreground)] placeholder:text-[var(--muted-foreground)]',
     'transition-colors duration-[150ms]',
     'transition-colors duration-[150ms]',
     'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-0',
     'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-0',
     'disabled:cursor-not-allowed disabled:opacity-40',
     'disabled:cursor-not-allowed disabled:opacity-40',
-    error
+    error || field?.invalid
       ? 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]'
       ? 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]'
       : 'border-[var(--border)] focus-visible:border-[var(--ring)]',
       : 'border-[var(--border)] focus-visible:border-[var(--ring)]',
     className
     className

+ 5 - 1
src/lib/components/primitives/Label.svelte

@@ -1,17 +1,21 @@
 <script lang="ts">
 <script lang="ts">
   import type { Snippet } from 'svelte';
   import type { Snippet } from 'svelte';
   import type { HTMLLabelAttributes } from 'svelte/elements';
   import type { HTMLLabelAttributes } from 'svelte/elements';
+  import { getContext } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { formFieldContext, type FormFieldContext } from '$lib/utils/form-field.js';
 
 
   interface Props extends HTMLLabelAttributes {
   interface Props extends HTMLLabelAttributes {
     class?: string;
     class?: string;
     children?: Snippet;
     children?: Snippet;
   }
   }
 
 
-  let { class: className = '', children, ...rest }: Props = $props();
+  let { class: className = '', children, for: htmlFor, ...rest }: Props = $props();
+  const field = getContext<FormFieldContext | undefined>(formFieldContext);
 </script>
 </script>
 
 
 <label
 <label
+  for={htmlFor ?? field?.controlId}
   class={cn(
   class={cn(
     'text-sm font-medium text-[var(--foreground)] leading-none',
     'text-sm font-medium text-[var(--foreground)] leading-none',
     'peer-disabled:cursor-not-allowed peer-disabled:opacity-40',
     'peer-disabled:cursor-not-allowed peer-disabled:opacity-40',

+ 11 - 2
src/lib/components/primitives/Select.svelte

@@ -1,6 +1,8 @@
 <script lang="ts">
 <script lang="ts">
   import type { Snippet } from 'svelte';
   import type { Snippet } from 'svelte';
+  import { getContext } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { formFieldContext, type FormFieldContext } from '$lib/utils/form-field.js';
 
 
   interface Props {
   interface Props {
     value?: string;
     value?: string;
@@ -8,6 +10,8 @@
     id?: string;
     id?: string;
     class?: string;
     class?: string;
     error?: boolean;
     error?: boolean;
+    'aria-describedby'?: string;
+    'aria-invalid'?: boolean | 'false' | 'true';
     children?: Snippet;
     children?: Snippet;
     onchange?: (value: string) => void;
     onchange?: (value: string) => void;
   }
   }
@@ -18,14 +22,19 @@
     id,
     id,
     class: className = '',
     class: className = '',
     error = false,
     error = false,
+    'aria-describedby': ariaDescribedby,
+    'aria-invalid': ariaInvalid,
     children,
     children,
     onchange,
     onchange,
   }: Props = $props();
   }: Props = $props();
+  const field = getContext<FormFieldContext | undefined>(formFieldContext);
 </script>
 </script>
 
 
 <div class={cn('relative w-full', className)}>
 <div class={cn('relative w-full', className)}>
   <select
   <select
-    {id}
+    id={id ?? field?.controlId}
+    aria-describedby={ariaDescribedby ?? field?.descriptionId}
+    aria-invalid={ariaInvalid ?? (field?.invalid ? 'true' : undefined)}
     {disabled}
     {disabled}
     bind:value
     bind:value
     onchange={(e) => onchange?.((e.target as HTMLSelectElement).value)}
     onchange={(e) => onchange?.((e.target as HTMLSelectElement).value)}
@@ -35,7 +44,7 @@
       'transition-colors duration-[150ms]',
       'transition-colors duration-[150ms]',
       'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-0',
       'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-0',
       'cursor-pointer disabled:cursor-not-allowed disabled:opacity-40',
       'cursor-pointer disabled:cursor-not-allowed disabled:opacity-40',
-      error
+      error || field?.invalid
         ? 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]'
         ? 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]'
         : 'border-[var(--border)] focus-visible:border-[var(--ring)]'
         : 'border-[var(--border)] focus-visible:border-[var(--ring)]'
     )}
     )}

+ 15 - 2
src/lib/components/primitives/Textarea.svelte

@@ -1,23 +1,36 @@
 <script lang="ts">
 <script lang="ts">
   import type { HTMLTextareaAttributes } from 'svelte/elements';
   import type { HTMLTextareaAttributes } from 'svelte/elements';
+  import { getContext } from 'svelte';
   import { cn } from '$lib/utils/cn.js';
   import { cn } from '$lib/utils/cn.js';
+  import { formFieldContext, type FormFieldContext } from '$lib/utils/form-field.js';
 
 
   interface Props extends HTMLTextareaAttributes {
   interface Props extends HTMLTextareaAttributes {
     class?: string;
     class?: string;
     error?: boolean;
     error?: boolean;
   }
   }
 
 
-  let { class: className = '', error = false, ...rest }: Props = $props();
+  let {
+    class: className = '',
+    error = false,
+    id,
+    'aria-describedby': ariaDescribedby,
+    'aria-invalid': ariaInvalid,
+    ...rest
+  }: Props = $props();
+  const field = getContext<FormFieldContext | undefined>(formFieldContext);
 </script>
 </script>
 
 
 <textarea
 <textarea
+  id={id ?? field?.controlId}
+  aria-describedby={ariaDescribedby ?? field?.descriptionId}
+  aria-invalid={ariaInvalid ?? (field?.invalid ? 'true' : undefined)}
   class={cn(
   class={cn(
     'flex min-h-[80px] w-full rounded-[var(--radius)] border bg-transparent px-3 py-2 text-sm',
     'flex min-h-[80px] w-full rounded-[var(--radius)] border bg-transparent px-3 py-2 text-sm',
     'text-[var(--foreground)] placeholder:text-[var(--muted-foreground)]',
     'text-[var(--foreground)] placeholder:text-[var(--muted-foreground)]',
     'resize-y transition-colors duration-[150ms]',
     'resize-y transition-colors duration-[150ms]',
     'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-0',
     'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-0',
     'disabled:cursor-not-allowed disabled:opacity-40',
     'disabled:cursor-not-allowed disabled:opacity-40',
-    error
+    error || field?.invalid
       ? 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]'
       ? 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]'
       : 'border-[var(--border)] focus-visible:border-[var(--ring)]',
       : 'border-[var(--border)] focus-visible:border-[var(--ring)]',
     className
     className

+ 13 - 90
src/lib/styles.css

@@ -1,96 +1,7 @@
 @import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap");
 @import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap");
+@import "./tokens.css";
 @import "tailwindcss";
 @import "tailwindcss";
 
 
-/* ─── Design Tokens ─────────────────────────────────────────────────────── */
-
-@theme {
-  /* Fonts */
-  --font-sans: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
-  --font-mono: ui-monospace, "Cascadia Code", "Source Code Pro", "Fira Code", monospace;
-
-  /* Olive primitive palette */
-  --color-olive-50:  hsl(75 60% 96%);
-  --color-olive-100: hsl(75 60% 90%);
-  --color-olive-200: hsl(75 58% 78%);
-  --color-olive-300: hsl(75 56% 66%);
-  --color-olive-400: hsl(75 58% 54%);
-  --color-olive-500: hsl(75 60% 44%);
-  --color-olive-600: hsl(75 55% 38%);
-  --color-olive-700: hsl(75 50% 32%);
-  --color-olive-800: hsl(75 45% 24%);
-  --color-olive-900: hsl(75 40% 16%);
-
-  /* Border radius */
-  --radius: 0.75rem;        /* 12px — cards, panels, inputs */
-  --radius-button: 0.4375rem; /* 7px  — buttons specifically */
-  --radius-sm: calc(var(--radius) * 0.5);
-  --radius-lg: calc(var(--radius) * 1.5);
-  --radius-full: 9999px;
-
-  /* Motion */
-  --duration-micro:  100ms;
-  --duration-fast:   150ms;
-  --duration-base:   200ms;
-  --duration-slow:   250ms;
-  --duration-page:   350ms;
-
-  --ease-enter: cubic-bezier(0.16, 1, 0.3, 1);
-  --ease-exit:  cubic-bezier(0.4, 0, 1, 1);
-  --ease-move:  cubic-bezier(0.25, 0.46, 0.45, 0.94);
-}
-
-/* ─── Semantic color variables ──────────────────────────────────────────── */
-
-:root {
-  --background:          hsl(60 8% 95%);
-  --foreground:          hsl(70 8% 15%);
-
-  --card:                hsl(60 6% 97%);
-  --card-foreground:     hsl(70 8% 15%);
-
-  --muted:               hsl(65 8% 91%);
-  --muted-foreground:    hsl(70 4% 45%);
-
-  --border:              hsl(65 6% 86%);
-
-  --primary:             hsl(75 60% 44%);
-  --primary-foreground:  hsl(70 8% 15%);
-
-  --destructive:         hsl(0 55% 52%);
-  --destructive-foreground: hsl(0 0% 98%);
-
-  --ring:                hsl(75 60% 44%);
-
-  --shadow-sm: 0 1px 2px hsl(70 8% 15% / 0.06);
-  --shadow-md: 0 4px 12px hsl(70 8% 15% / 0.08);
-  --shadow-lg: 0 8px 24px hsl(70 8% 15% / 0.10);
-}
-
-.dark {
-  --background:          hsl(70 4% 9%);
-  --foreground:          hsl(60 8% 85%);
-
-  --card:                hsl(70 4% 11%);
-  --card-foreground:     hsl(60 8% 85%);
-
-  --muted:               hsl(70 4% 15%);
-  --muted-foreground:    hsl(65 4% 50%);
-
-  --border:              hsl(70 4% 18%);
-
-  --primary:             hsl(75 55% 52%);
-  --primary-foreground:  hsl(70 4% 9%);
-
-  --destructive:         hsl(0 45% 42%);
-  --destructive-foreground: hsl(0 0% 98%);
-
-  --ring:                hsl(75 55% 52%);
-
-  --shadow-sm: 0 1px 2px hsl(70 4% 4% / 0.4);
-  --shadow-md: 0 4px 12px hsl(70 4% 4% / 0.5);
-  --shadow-lg: 0 8px 24px hsl(70 4% 4% / 0.6);
-}
-
 /* ─── Tailwind v4 CSS variable bridge ───────────────────────────────────── */
 /* ─── Tailwind v4 CSS variable bridge ───────────────────────────────────── */
 /*
 /*
    Tailwind v4 uses @theme for its utility generation, but our semantic tokens
    Tailwind v4 uses @theme for its utility generation, but our semantic tokens
@@ -99,6 +10,18 @@
 */
 */
 
 
 @theme inline {
 @theme inline {
+  --font-sans: var(--olive-font-sans);
+  --font-mono: var(--olive-font-mono);
+  --color-olive-50: var(--olive-50);
+  --color-olive-100: var(--olive-100);
+  --color-olive-200: var(--olive-200);
+  --color-olive-300: var(--olive-300);
+  --color-olive-400: var(--olive-400);
+  --color-olive-500: var(--olive-500);
+  --color-olive-600: var(--olive-600);
+  --color-olive-700: var(--olive-700);
+  --color-olive-800: var(--olive-800);
+  --color-olive-900: var(--olive-900);
   --color-background:         var(--background);
   --color-background:         var(--background);
   --color-foreground:         var(--foreground);
   --color-foreground:         var(--foreground);
   --color-card:               var(--card);
   --color-card:               var(--card);

+ 108 - 0
src/lib/tokens.css

@@ -0,0 +1,108 @@
+:root {
+  --olive-font-sans: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
+  --olive-font-mono: ui-monospace, "Cascadia Code", "Source Code Pro", "Fira Code", monospace;
+  --olive-text-caption: 0.75rem;
+  --olive-text-body: 0.875rem;
+  --olive-text-control: 0.875rem;
+  --olive-text-title: 1.125rem;
+  --olive-leading-tight: 1.25;
+  --olive-leading-body: 1.5;
+
+  --olive-space-1: 0.25rem;
+  --olive-space-2: 0.5rem;
+  --olive-space-3: 0.75rem;
+  --olive-space-4: 1rem;
+  --olive-space-5: 1.5rem;
+  --olive-space-6: 2rem;
+  --olive-space-7: 3rem;
+  --olive-space-8: 4rem;
+
+  --olive-50: hsl(75 60% 96%);
+  --olive-100: hsl(75 60% 90%);
+  --olive-200: hsl(75 58% 78%);
+  --olive-300: hsl(75 56% 66%);
+  --olive-400: hsl(75 58% 54%);
+  --olive-500: hsl(75 60% 44%);
+  --olive-600: hsl(75 55% 38%);
+  --olive-700: hsl(75 50% 32%);
+  --olive-800: hsl(75 45% 24%);
+  --olive-900: hsl(75 40% 16%);
+  --olive-brand-accent: var(--olive-500);
+  --olive-brand-accent-bright: var(--olive-400);
+
+  --olive-radius-surface: 0.75rem;
+  --olive-radius-control: 0.4375rem;
+  --olive-radius-sm: calc(var(--olive-radius-surface) * 0.5);
+  --olive-radius-lg: calc(var(--olive-radius-surface) * 1.5);
+  --olive-radius-full: 9999px;
+
+  --olive-duration-micro: 100ms;
+  --olive-duration-fast: 150ms;
+  --olive-duration-base: 200ms;
+  --olive-duration-slow: 250ms;
+  --olive-duration-page: 350ms;
+  --olive-ease-enter: cubic-bezier(0.16, 1, 0.3, 1);
+  --olive-ease-exit: cubic-bezier(0.4, 0, 1, 1);
+  --olive-ease-move: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+
+  /* Stable aliases consumed by Olive components and existing products. */
+  --font-sans: var(--olive-font-sans);
+  --font-mono: var(--olive-font-mono);
+  --color-olive-50: var(--olive-50);
+  --color-olive-100: var(--olive-100);
+  --color-olive-200: var(--olive-200);
+  --color-olive-300: var(--olive-300);
+  --color-olive-400: var(--olive-400);
+  --color-olive-500: var(--olive-500);
+  --color-olive-600: var(--olive-600);
+  --color-olive-700: var(--olive-700);
+  --color-olive-800: var(--olive-800);
+  --color-olive-900: var(--olive-900);
+  --radius: var(--olive-radius-surface);
+  --radius-button: var(--olive-radius-control);
+  --radius-sm: var(--olive-radius-sm);
+  --radius-lg: var(--olive-radius-lg);
+  --radius-full: var(--olive-radius-full);
+  --duration-micro: var(--olive-duration-micro);
+  --duration-fast: var(--olive-duration-fast);
+  --duration-base: var(--olive-duration-base);
+  --duration-slow: var(--olive-duration-slow);
+  --duration-page: var(--olive-duration-page);
+  --ease-enter: var(--olive-ease-enter);
+  --ease-exit: var(--olive-ease-exit);
+  --ease-move: var(--olive-ease-move);
+
+  --background: hsl(60 8% 95%);
+  --foreground: hsl(70 8% 15%);
+  --card: hsl(60 6% 97%);
+  --card-foreground: hsl(70 8% 15%);
+  --muted: hsl(65 8% 91%);
+  --muted-foreground: hsl(70 4% 45%);
+  --border: hsl(65 6% 86%);
+  --primary: hsl(75 60% 44%);
+  --primary-foreground: hsl(70 8% 15%);
+  --destructive: hsl(0 55% 52%);
+  --destructive-foreground: hsl(0 0% 98%);
+  --ring: hsl(75 60% 44%);
+  --shadow-sm: 0 1px 2px hsl(70 8% 15% / 0.06);
+  --shadow-md: 0 4px 12px hsl(70 8% 15% / 0.08);
+  --shadow-lg: 0 8px 24px hsl(70 8% 15% / 0.1);
+}
+
+.dark {
+  --background: hsl(70 4% 9%);
+  --foreground: hsl(60 8% 85%);
+  --card: hsl(70 4% 11%);
+  --card-foreground: hsl(60 8% 85%);
+  --muted: hsl(70 4% 15%);
+  --muted-foreground: hsl(65 4% 50%);
+  --border: hsl(70 4% 18%);
+  --primary: hsl(75 55% 52%);
+  --primary-foreground: hsl(70 4% 9%);
+  --destructive: hsl(0 45% 42%);
+  --destructive-foreground: hsl(0 0% 98%);
+  --ring: hsl(75 55% 52%);
+  --shadow-sm: 0 1px 2px hsl(70 4% 4% / 0.4);
+  --shadow-md: 0 4px 12px hsl(70 4% 4% / 0.5);
+  --shadow-lg: 0 8px 24px hsl(70 4% 4% / 0.6);
+}

+ 7 - 0
src/lib/utils/form-field.ts

@@ -0,0 +1,7 @@
+export const formFieldContext = Symbol('olive-form-field');
+
+export interface FormFieldContext {
+  readonly controlId: string;
+  readonly descriptionId: string | undefined;
+  readonly invalid: boolean;
+}

+ 143 - 0
src/lib/utils/modal.ts

@@ -0,0 +1,143 @@
+interface ModalOptions {
+  onEscape: () => void;
+  initialFocus?: string;
+}
+
+let bodyLockCount = 0;
+let previousBodyOverflow = '';
+const backgroundStates = new Map<HTMLElement, {
+  count: number;
+  inert: boolean;
+  ariaHidden: string | null;
+}>();
+
+const focusableSelector = [
+  'a[href]',
+  'area[href]',
+  'button:not([disabled])',
+  'input:not([disabled]):not([type="hidden"])',
+  'select:not([disabled])',
+  'textarea:not([disabled])',
+  '[tabindex]:not([tabindex="-1"])',
+  '[contenteditable="true"]',
+].join(',');
+
+function focusableElements(node: HTMLElement): HTMLElement[] {
+  return Array.from(node.querySelectorAll<HTMLElement>(focusableSelector)).filter((element) => {
+    if (element.closest('[hidden], [aria-hidden="true"], [inert]')) return false;
+    const style = getComputedStyle(element);
+    return style.display !== 'none' && style.visibility !== 'hidden';
+  });
+}
+
+function lockBodyScroll() {
+  if (bodyLockCount === 0) {
+    previousBodyOverflow = document.body.style.overflow;
+    document.body.style.overflow = 'hidden';
+  }
+  bodyLockCount += 1;
+}
+
+function unlockBodyScroll() {
+  bodyLockCount = Math.max(0, bodyLockCount - 1);
+  if (bodyLockCount === 0) document.body.style.overflow = previousBodyOverflow;
+}
+
+function hideBackground(node: HTMLElement): HTMLElement[] {
+  let modalRoot = node;
+  while (modalRoot.parentElement && modalRoot.parentElement !== document.body) {
+    modalRoot = modalRoot.parentElement;
+  }
+
+  return Array.from(document.body.children)
+    .filter((element): element is HTMLElement => element instanceof HTMLElement && element !== modalRoot)
+    .map((element) => {
+      const state = backgroundStates.get(element);
+      if (state) {
+        state.count += 1;
+      } else {
+        backgroundStates.set(element, {
+          count: 1,
+          inert: element.inert,
+          ariaHidden: element.getAttribute('aria-hidden'),
+        });
+      }
+      element.inert = true;
+      element.setAttribute('aria-hidden', 'true');
+      return element;
+    });
+}
+
+function restoreBackground(elements: HTMLElement[]) {
+  for (const element of elements) {
+    const state = backgroundStates.get(element);
+    if (!state) continue;
+    state.count -= 1;
+    if (state.count > 0) continue;
+
+    element.inert = state.inert;
+    if (state.ariaHidden === null) element.removeAttribute('aria-hidden');
+    else element.setAttribute('aria-hidden', state.ariaHidden);
+    backgroundStates.delete(element);
+  }
+}
+
+export function modal(node: HTMLElement, options: ModalOptions) {
+  let currentOptions = options;
+  const previousFocus = document.activeElement instanceof HTMLElement
+    ? document.activeElement
+    : null;
+
+  function focusInitial() {
+    const requested = currentOptions.initialFocus
+      ? node.querySelector<HTMLElement>(currentOptions.initialFocus)
+      : null;
+    (requested ?? focusableElements(node)[0] ?? node).focus();
+  }
+
+  function handleKeydown(event: KeyboardEvent) {
+    if (event.key === 'Escape') {
+      event.preventDefault();
+      currentOptions.onEscape();
+      return;
+    }
+
+    if (event.key !== 'Tab') return;
+
+    const focusable = focusableElements(node);
+    if (focusable.length === 0) {
+      event.preventDefault();
+      node.focus();
+      return;
+    }
+
+    const first = focusable[0];
+    const last = focusable[focusable.length - 1];
+    const active = document.activeElement;
+
+    if (event.shiftKey && (active === first || !node.contains(active))) {
+      event.preventDefault();
+      last.focus();
+    } else if (!event.shiftKey && (active === last || !node.contains(active))) {
+      event.preventDefault();
+      first.focus();
+    }
+  }
+
+  lockBodyScroll();
+  const hiddenBackground = hideBackground(node);
+  node.addEventListener('keydown', handleKeydown);
+  queueMicrotask(focusInitial);
+
+  return {
+    update(nextOptions: ModalOptions) {
+      currentOptions = nextOptions;
+    },
+    destroy() {
+      node.removeEventListener('keydown', handleKeydown);
+      restoreBackground(hiddenBackground);
+      unlockBodyScroll();
+      queueMicrotask(() => previousFocus?.focus());
+    },
+  };
+}

+ 72 - 0
src/lib/utils/popup.ts

@@ -0,0 +1,72 @@
+interface PopupTriggerOptions {
+  expanded: boolean;
+  controls: string;
+  haspopup: 'dialog' | 'listbox' | 'menu';
+}
+
+export function popupElement(node: HTMLElement | null): HTMLElement | null {
+  return node?.firstElementChild instanceof HTMLElement ? node.firstElementChild : null;
+}
+
+export function popupTrigger(node: HTMLElement, options: PopupTriggerOptions) {
+  let trigger: HTMLElement | null = null;
+  let addedRole = false;
+  let addedTabIndex = false;
+  let previousHasPopup: string | null = null;
+  let previousExpanded: string | null = null;
+  let previousControls: string | null = null;
+
+  function handleKeydown(event: KeyboardEvent) {
+    if (event.key !== 'Enter' && event.key !== ' ') return;
+    event.preventDefault();
+    node.click();
+  }
+
+  function connect() {
+    trigger = popupElement(node);
+    if (!trigger) return;
+
+    previousHasPopup = trigger.getAttribute('aria-haspopup');
+    previousExpanded = trigger.getAttribute('aria-expanded');
+    previousControls = trigger.getAttribute('aria-controls');
+
+    const nativeInteractive = trigger.matches('button, a[href], input, select, textarea');
+    if (!nativeInteractive && !trigger.hasAttribute('role')) {
+      trigger.setAttribute('role', 'button');
+      addedRole = true;
+    }
+    if (!nativeInteractive && !trigger.hasAttribute('tabindex')) {
+      trigger.tabIndex = 0;
+      addedTabIndex = true;
+    }
+    if (!nativeInteractive) trigger.addEventListener('keydown', handleKeydown);
+  }
+
+  function sync(nextOptions: PopupTriggerOptions) {
+    options = nextOptions;
+    trigger?.setAttribute('aria-haspopup', options.haspopup);
+    trigger?.setAttribute('aria-expanded', String(options.expanded));
+    trigger?.setAttribute('aria-controls', options.controls);
+  }
+
+  connect();
+  sync(options);
+
+  return {
+    update(nextOptions: PopupTriggerOptions) {
+      sync(nextOptions);
+    },
+    destroy() {
+      if (!trigger) return;
+      trigger.removeEventListener('keydown', handleKeydown);
+      if (previousHasPopup === null) trigger.removeAttribute('aria-haspopup');
+      else trigger.setAttribute('aria-haspopup', previousHasPopup);
+      if (previousExpanded === null) trigger.removeAttribute('aria-expanded');
+      else trigger.setAttribute('aria-expanded', previousExpanded);
+      if (previousControls === null) trigger.removeAttribute('aria-controls');
+      else trigger.setAttribute('aria-controls', previousControls);
+      if (addedRole) trigger.removeAttribute('role');
+      if (addedTabIndex) trigger.removeAttribute('tabindex');
+    },
+  };
+}

+ 4 - 3
src/routes/+layout.svelte

@@ -47,11 +47,12 @@
 <div class="flex min-h-screen bg-[var(--background)]">
 <div class="flex min-h-screen bg-[var(--background)]">
   <!-- Mobile overlay -->
   <!-- Mobile overlay -->
   {#if mobileOpen}
   {#if mobileOpen}
-    <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
-    <div
+    <button
+      type="button"
+      aria-label="Close navigation"
       class="fixed inset-0 z-40 bg-black/40 backdrop-blur-sm lg:hidden"
       class="fixed inset-0 z-40 bg-black/40 backdrop-blur-sm lg:hidden"
       onclick={() => { mobileOpen = false; }}
       onclick={() => { mobileOpen = false; }}
-    ></div>
+    ></button>
   {/if}
   {/if}
 
 
   <!-- Sidebar -->
   <!-- Sidebar -->

+ 1 - 1
src/routes/DocBlock.svelte

@@ -29,7 +29,7 @@
   }: Props = $props();
   }: Props = $props();
 
 
   let tab = $state<'preview' | 'code' | 'props'>('preview');
   let tab = $state<'preview' | 'code' | 'props'>('preview');
-  const tabs = ['preview', 'code', ...(props.length ? ['props'] : [])] as const;
+  let tabs = $derived(['preview', 'code', ...(props.length ? ['props'] : [])] as const);
 </script>
 </script>
 
 
 <div id={name.toLowerCase().replace(/\s+/g, '-')} class={cn('scroll-mt-20', className)}>
 <div id={name.toLowerCase().replace(/\s+/g, '-')} class={cn('scroll-mt-20', className)}>

+ 1 - 1
src/routes/data/+page.svelte

@@ -130,7 +130,7 @@
 />`}
 />`}
       props={[
       props={[
         { name: 'data', type: 'T[]', description: 'Array of row objects' },
         { name: 'data', type: 'T[]', description: 'Array of row objects' },
-        { name: 'columns', type: '{ key: keyof T; header: string; sortable?: boolean; width?: string; render?: fn }[]', description: 'Column definitions' },
+        { name: 'columns', type: '{ key: keyof T; header: string; sortable?: boolean; width?: string; render?: fn }[]', description: 'Column definitions; render returns escaped text' },
         { name: 'pageSize', type: 'number', default: '10', description: 'Rows per page' },
         { name: 'pageSize', type: 'number', default: '10', description: 'Rows per page' },
         { name: 'searchable', type: 'boolean', default: 'false', description: 'Shows a search input above the table' },
         { name: 'searchable', type: 'boolean', default: 'false', description: 'Shows a search input above the table' },
         { name: 'searchPlaceholder', type: 'string', default: "'Search…'", description: 'Search input placeholder' },
         { name: 'searchPlaceholder', type: 'string', default: "'Search…'", description: 'Search input placeholder' },

+ 3 - 9
tsconfig.json

@@ -1,4 +1,5 @@
 {
 {
+	"extends": "./.svelte-kit/tsconfig.json",
 	"compilerOptions": {
 	"compilerOptions": {
 		"allowJs": true,
 		"allowJs": true,
 		"checkJs": true,
 		"checkJs": true,
@@ -8,13 +9,6 @@
 		"skipLibCheck": true,
 		"skipLibCheck": true,
 		"sourceMap": true,
 		"sourceMap": true,
 		"strict": true,
 		"strict": true,
-		"moduleResolution": "bundler",
-		"module": "esnext",
-		"target": "esnext",
-		"paths": {
-			"$lib": ["./src/lib"],
-			"$lib/*": ["./src/lib/*"]
-		}
-	},
-	"include": ["src/**/*"]
+		"moduleResolution": "bundler"
+	}
 }
 }