0xc3 21 小时之前
当前提交
a8dd81a1d4
共有 43 个文件被更改,包括 6777 次插入0 次删除
  1. 2 0
      .env.development-templ
  2. 24 0
      .gitignore
  3. 1 0
      .npmrc
  4. 38 0
      README.md
  5. 2104 0
      package-lock.json
  6. 33 0
      package.json
  7. 1397 0
      pnpm-lock.yaml
  8. 7 0
      src/app.css
  9. 13 0
      src/app.d.ts
  10. 16 0
      src/app.html
  11. 7 0
      src/lib/api.ts
  12. 91 0
      src/lib/components/client/clientFilters.svelte
  13. 40 0
      src/lib/components/client/clientStats.svelte
  14. 170 0
      src/lib/components/client/clientTableRow.svelte
  15. 9 0
      src/lib/components/ui/Card.svelte
  16. 38 0
      src/lib/components/ui/ClientTable.svelte
  17. 3 0
      src/lib/components/ui/Footer.svelte
  18. 28 0
      src/lib/components/ui/Form.svelte
  19. 34 0
      src/lib/components/ui/List.svelte
  20. 30 0
      src/lib/components/ui/Navbar.svelte
  21. 31 0
      src/lib/components/ui/Sidebar.svelte
  22. 62 0
      src/lib/components/ui/Slider.svelte
  23. 95 0
      src/lib/components/ui/Table.svelte
  24. 1 0
      src/lib/index.ts
  25. 21 0
      src/lib/services/clientService.ts
  26. 32 0
      src/lib/types/client.ts
  27. 127 0
      src/lib/utils/clientUtils.ts
  28. 24 0
      src/routes/+layout.svelte
  29. 1 0
      src/routes/+page.svelte
  30. 1 0
      src/routes/calls/+page.svelte
  31. 335 0
      src/routes/client/test/+page.svelte
  32. 21 0
      src/routes/client/test/+page.ts
  33. 1853 0
      src/routes/clients/+page.svelte
  34. 21 0
      src/routes/clients/+page.ts
  35. 1 0
      src/routes/orders/+page.svelte
  36. 1 0
      src/routes/products/+page.svelte
  37. 20 0
      src/routes/test_ui/+page.svelte
  38. 1 0
      static/favicon.svg
  39. 二进制
      static/test/test.png
  40. 二进制
      static/test/test002.jpg
  41. 18 0
      svelte.config.js
  42. 19 0
      tsconfig.json
  43. 7 0
      vite.config.ts

+ 2 - 0
.env.development-templ

@@ -0,0 +1,2 @@
+VITE_SERVER_API_URL="http://api.localhost"
+VITE_SERVER_API_PORT=":8080"

+ 24 - 0
.gitignore

@@ -0,0 +1,24 @@
+node_modules
+
+# Output
+.output
+.vercel
+.netlify
+.wrangler
+/.svelte-kit
+/build
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Env
+.env
+.env.*
+!.env.example
+!.env.test
+!.env.development-templ
+
+# Vite
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*

+ 1 - 0
.npmrc

@@ -0,0 +1 @@
+engine-strict=true

+ 38 - 0
README.md

@@ -0,0 +1,38 @@
+# sv
+
+Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
+
+## Creating a project
+
+If you're seeing this, you've probably already done this step. Congrats!
+
+```bash
+# create a new project in the current directory
+npx sv create
+
+# create a new project in my-app
+npx sv create my-app
+```
+
+## Developing
+
+Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
+
+```bash
+npm run dev
+
+# or start the server and open the app in a new browser tab
+npm run dev -- --open
+```
+
+## Building
+
+To create a production version of your app:
+
+```bash
+npm run build
+```
+
+You can preview the production build with `npm run preview`.
+
+> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.

+ 2104 - 0
package-lock.json

@@ -0,0 +1,2104 @@
+{
+	"name": "test-svelte",
+	"version": "0.0.1",
+	"lockfileVersion": 3,
+	"requires": true,
+	"packages": {
+		"": {
+			"name": "test-svelte",
+			"version": "0.0.1",
+			"devDependencies": {
+				"@sveltejs/adapter-auto": "^6.0.0",
+				"@sveltejs/kit": "^2.16.0",
+				"@sveltejs/vite-plugin-svelte": "^5.0.0",
+				"@tailwindcss/forms": "^0.5.9",
+				"@tailwindcss/typography": "^0.5.15",
+				"@tailwindcss/vite": "^4.0.0",
+				"daisyui": "^5.0.46",
+				"svelte": "^5.0.0",
+				"svelte-check": "^4.0.0",
+				"tailwindcss": "^4.0.0",
+				"typescript": "^5.0.0",
+				"vite": "^6.2.6"
+			}
+		},
+		"node_modules/@esbuild/aix-ppc64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz",
+			"integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==",
+			"cpu": [
+				"ppc64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"aix"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/android-arm": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz",
+			"integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/android-arm64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz",
+			"integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/android-x64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz",
+			"integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/darwin-arm64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz",
+			"integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/darwin-x64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz",
+			"integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/freebsd-arm64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz",
+			"integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"freebsd"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/freebsd-x64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz",
+			"integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"freebsd"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/linux-arm": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz",
+			"integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/linux-arm64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz",
+			"integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/linux-ia32": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz",
+			"integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==",
+			"cpu": [
+				"ia32"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/linux-loong64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz",
+			"integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==",
+			"cpu": [
+				"loong64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/linux-mips64el": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz",
+			"integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==",
+			"cpu": [
+				"mips64el"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/linux-ppc64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz",
+			"integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==",
+			"cpu": [
+				"ppc64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/linux-riscv64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz",
+			"integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==",
+			"cpu": [
+				"riscv64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/linux-s390x": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz",
+			"integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==",
+			"cpu": [
+				"s390x"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/linux-x64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz",
+			"integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/netbsd-arm64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz",
+			"integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"netbsd"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/netbsd-x64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz",
+			"integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"netbsd"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/openbsd-arm64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz",
+			"integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"openbsd"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/openbsd-x64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz",
+			"integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"openbsd"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/openharmony-arm64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz",
+			"integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"openharmony"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/sunos-x64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz",
+			"integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"sunos"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/win32-arm64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz",
+			"integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/win32-ia32": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz",
+			"integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==",
+			"cpu": [
+				"ia32"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@esbuild/win32-x64": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz",
+			"integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"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,
+			"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,
+			"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,
+			"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
+		},
+		"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,
+			"dependencies": {
+				"@jridgewell/resolve-uri": "^3.1.0",
+				"@jridgewell/sourcemap-codec": "^1.4.14"
+			}
+		},
+		"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
+		},
+		"node_modules/@rollup/rollup-android-arm-eabi": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz",
+			"integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"android"
+			]
+		},
+		"node_modules/@rollup/rollup-android-arm64": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz",
+			"integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"android"
+			]
+		},
+		"node_modules/@rollup/rollup-darwin-arm64": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz",
+			"integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"darwin"
+			]
+		},
+		"node_modules/@rollup/rollup-darwin-x64": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz",
+			"integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"darwin"
+			]
+		},
+		"node_modules/@rollup/rollup-freebsd-arm64": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz",
+			"integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"freebsd"
+			]
+		},
+		"node_modules/@rollup/rollup-freebsd-x64": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz",
+			"integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"freebsd"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz",
+			"integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-arm-musleabihf": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz",
+			"integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-arm64-gnu": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz",
+			"integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-arm64-musl": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz",
+			"integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-loong64-gnu": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz",
+			"integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==",
+			"cpu": [
+				"loong64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-ppc64-gnu": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz",
+			"integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==",
+			"cpu": [
+				"ppc64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-riscv64-gnu": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz",
+			"integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==",
+			"cpu": [
+				"riscv64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-riscv64-musl": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz",
+			"integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==",
+			"cpu": [
+				"riscv64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-s390x-gnu": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz",
+			"integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==",
+			"cpu": [
+				"s390x"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-x64-gnu": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz",
+			"integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-linux-x64-musl": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz",
+			"integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
+		"node_modules/@rollup/rollup-openharmony-arm64": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz",
+			"integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"openharmony"
+			]
+		},
+		"node_modules/@rollup/rollup-win32-arm64-msvc": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz",
+			"integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"win32"
+			]
+		},
+		"node_modules/@rollup/rollup-win32-ia32-msvc": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz",
+			"integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==",
+			"cpu": [
+				"ia32"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"win32"
+			]
+		},
+		"node_modules/@rollup/rollup-win32-x64-gnu": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz",
+			"integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"win32"
+			]
+		},
+		"node_modules/@rollup/rollup-win32-x64-msvc": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz",
+			"integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"win32"
+			]
+		},
+		"node_modules/@standard-schema/spec": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
+			"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
+			"dev": true
+		},
+		"node_modules/@sveltejs/acorn-typescript": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.6.tgz",
+			"integrity": "sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ==",
+			"dev": true,
+			"peerDependencies": {
+				"acorn": "^8.9.0"
+			}
+		},
+		"node_modules/@sveltejs/adapter-auto": {
+			"version": "6.1.1",
+			"resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-6.1.1.tgz",
+			"integrity": "sha512-cBNt4jgH4KuaNO5gRSB2CZKkGtz+OCZ8lPjRQGjhvVUD4akotnj2weUia6imLl2v07K3IgsQRyM36909miSwoQ==",
+			"dev": true,
+			"peerDependencies": {
+				"@sveltejs/kit": "^2.0.0"
+			}
+		},
+		"node_modules/@sveltejs/kit": {
+			"version": "2.48.4",
+			"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.48.4.tgz",
+			"integrity": "sha512-TGFX1pZUt9qqY20Cv5NyYvy0iLWHf2jXi8s+eCGsig7jQMdwZWKUFMR6TbvFNhfDSUpc1sH/Y5EHv20g3HHA3g==",
+			"dev": true,
+			"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.3.2",
+				"esm-env": "^1.2.2",
+				"kleur": "^4.1.5",
+				"magic-string": "^0.30.5",
+				"mrmime": "^2.0.0",
+				"sade": "^1.8.1",
+				"set-cookie-parser": "^2.6.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",
+				"svelte": "^4.0.0 || ^5.0.0-next.0",
+				"vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0"
+			},
+			"peerDependenciesMeta": {
+				"@opentelemetry/api": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@sveltejs/vite-plugin-svelte": {
+			"version": "5.1.1",
+			"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz",
+			"integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==",
+			"dev": true,
+			"dependencies": {
+				"@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
+				"debug": "^4.4.1",
+				"deepmerge": "^4.3.1",
+				"kleur": "^4.1.5",
+				"magic-string": "^0.30.17",
+				"vitefu": "^1.0.6"
+			},
+			"engines": {
+				"node": "^18.0.0 || ^20.0.0 || >=22"
+			},
+			"peerDependencies": {
+				"svelte": "^5.0.0",
+				"vite": "^6.0.0"
+			}
+		},
+		"node_modules/@sveltejs/vite-plugin-svelte-inspector": {
+			"version": "4.0.1",
+			"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz",
+			"integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==",
+			"dev": true,
+			"dependencies": {
+				"debug": "^4.3.7"
+			},
+			"engines": {
+				"node": "^18.0.0 || ^20.0.0 || >=22"
+			},
+			"peerDependencies": {
+				"@sveltejs/vite-plugin-svelte": "^5.0.0",
+				"svelte": "^5.0.0",
+				"vite": "^6.0.0"
+			}
+		},
+		"node_modules/@tailwindcss/forms": {
+			"version": "0.5.10",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz",
+			"integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==",
+			"dev": true,
+			"dependencies": {
+				"mini-svg-data-uri": "^1.2.3"
+			},
+			"peerDependencies": {
+				"tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1"
+			}
+		},
+		"node_modules/@tailwindcss/node": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.16.tgz",
+			"integrity": "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==",
+			"dev": true,
+			"dependencies": {
+				"@jridgewell/remapping": "^2.3.4",
+				"enhanced-resolve": "^5.18.3",
+				"jiti": "^2.6.1",
+				"lightningcss": "1.30.2",
+				"magic-string": "^0.30.19",
+				"source-map-js": "^1.2.1",
+				"tailwindcss": "4.1.16"
+			}
+		},
+		"node_modules/@tailwindcss/oxide": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.16.tgz",
+			"integrity": "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==",
+			"dev": true,
+			"engines": {
+				"node": ">= 10"
+			},
+			"optionalDependencies": {
+				"@tailwindcss/oxide-android-arm64": "4.1.16",
+				"@tailwindcss/oxide-darwin-arm64": "4.1.16",
+				"@tailwindcss/oxide-darwin-x64": "4.1.16",
+				"@tailwindcss/oxide-freebsd-x64": "4.1.16",
+				"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16",
+				"@tailwindcss/oxide-linux-arm64-gnu": "4.1.16",
+				"@tailwindcss/oxide-linux-arm64-musl": "4.1.16",
+				"@tailwindcss/oxide-linux-x64-gnu": "4.1.16",
+				"@tailwindcss/oxide-linux-x64-musl": "4.1.16",
+				"@tailwindcss/oxide-wasm32-wasi": "4.1.16",
+				"@tailwindcss/oxide-win32-arm64-msvc": "4.1.16",
+				"@tailwindcss/oxide-win32-x64-msvc": "4.1.16"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-android-arm64": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.16.tgz",
+			"integrity": "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-darwin-arm64": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.16.tgz",
+			"integrity": "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-darwin-x64": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.16.tgz",
+			"integrity": "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-freebsd-x64": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.16.tgz",
+			"integrity": "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"freebsd"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.16.tgz",
+			"integrity": "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.16.tgz",
+			"integrity": "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.16.tgz",
+			"integrity": "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.16.tgz",
+			"integrity": "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-linux-x64-musl": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.16.tgz",
+			"integrity": "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-wasm32-wasi": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.16.tgz",
+			"integrity": "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==",
+			"bundleDependencies": [
+				"@napi-rs/wasm-runtime",
+				"@emnapi/core",
+				"@emnapi/runtime",
+				"@tybys/wasm-util",
+				"@emnapi/wasi-threads",
+				"tslib"
+			],
+			"cpu": [
+				"wasm32"
+			],
+			"dev": true,
+			"optional": true,
+			"dependencies": {
+				"@emnapi/core": "^1.5.0",
+				"@emnapi/runtime": "^1.5.0",
+				"@emnapi/wasi-threads": "^1.1.0",
+				"@napi-rs/wasm-runtime": "^1.0.7",
+				"@tybys/wasm-util": "^0.10.1",
+				"tslib": "^2.4.0"
+			},
+			"engines": {
+				"node": ">=14.0.0"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.16.tgz",
+			"integrity": "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.16.tgz",
+			"integrity": "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">= 10"
+			}
+		},
+		"node_modules/@tailwindcss/typography": {
+			"version": "0.5.19",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz",
+			"integrity": "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==",
+			"dev": true,
+			"dependencies": {
+				"postcss-selector-parser": "6.0.10"
+			},
+			"peerDependencies": {
+				"tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1"
+			}
+		},
+		"node_modules/@tailwindcss/vite": {
+			"version": "4.1.16",
+			"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.16.tgz",
+			"integrity": "sha512-bbguNBcDxsRmi9nnlWJxhfDWamY3lmcyACHcdO1crxfzuLpOhHLLtEIN/nCbbAtj5rchUgQD17QVAKi1f7IsKg==",
+			"dev": true,
+			"dependencies": {
+				"@tailwindcss/node": "4.1.16",
+				"@tailwindcss/oxide": "4.1.16",
+				"tailwindcss": "4.1.16"
+			},
+			"peerDependencies": {
+				"vite": "^5.2.0 || ^6 || ^7"
+			}
+		},
+		"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
+		},
+		"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
+		},
+		"node_modules/acorn": {
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+			"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+			"dev": true,
+			"bin": {
+				"acorn": "bin/acorn"
+			},
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
+		"node_modules/aria-query": {
+			"version": "5.3.2",
+			"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+			"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+			"dev": true,
+			"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,
+			"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,
+			"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,
+			"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,
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/cssesc": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+			"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+			"dev": true,
+			"bin": {
+				"cssesc": "bin/cssesc"
+			},
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/daisyui": {
+			"version": "5.3.10",
+			"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.3.10.tgz",
+			"integrity": "sha512-vmjyPmm0hvFhA95KB6uiGmWakziB2pBv6CUcs5Ka/3iMBMn9S+C3SZYx9G9l2JrgTZ1EFn61F/HrPcwaUm2kLQ==",
+			"dev": true,
+			"funding": {
+				"url": "https://github.com/saadeghi/daisyui?sponsor=1"
+			}
+		},
+		"node_modules/debug": {
+			"version": "4.4.3",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+			"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+			"dev": true,
+			"dependencies": {
+				"ms": "^2.1.3"
+			},
+			"engines": {
+				"node": ">=6.0"
+			},
+			"peerDependenciesMeta": {
+				"supports-color": {
+					"optional": true
+				}
+			}
+		},
+		"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,
+			"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,
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/devalue": {
+			"version": "5.4.2",
+			"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.4.2.tgz",
+			"integrity": "sha512-MwPZTKEPK2k8Qgfmqrd48ZKVvzSQjgW0lXLxiIBA8dQjtf/6mw6pggHNLcyDKyf+fI6eXxlQwPsfaCMTU5U+Bw==",
+			"dev": true
+		},
+		"node_modules/enhanced-resolve": {
+			"version": "5.18.3",
+			"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
+			"integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
+			"dev": true,
+			"dependencies": {
+				"graceful-fs": "^4.2.4",
+				"tapable": "^2.2.0"
+			},
+			"engines": {
+				"node": ">=10.13.0"
+			}
+		},
+		"node_modules/esbuild": {
+			"version": "0.25.11",
+			"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz",
+			"integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==",
+			"dev": true,
+			"hasInstallScript": true,
+			"bin": {
+				"esbuild": "bin/esbuild"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"optionalDependencies": {
+				"@esbuild/aix-ppc64": "0.25.11",
+				"@esbuild/android-arm": "0.25.11",
+				"@esbuild/android-arm64": "0.25.11",
+				"@esbuild/android-x64": "0.25.11",
+				"@esbuild/darwin-arm64": "0.25.11",
+				"@esbuild/darwin-x64": "0.25.11",
+				"@esbuild/freebsd-arm64": "0.25.11",
+				"@esbuild/freebsd-x64": "0.25.11",
+				"@esbuild/linux-arm": "0.25.11",
+				"@esbuild/linux-arm64": "0.25.11",
+				"@esbuild/linux-ia32": "0.25.11",
+				"@esbuild/linux-loong64": "0.25.11",
+				"@esbuild/linux-mips64el": "0.25.11",
+				"@esbuild/linux-ppc64": "0.25.11",
+				"@esbuild/linux-riscv64": "0.25.11",
+				"@esbuild/linux-s390x": "0.25.11",
+				"@esbuild/linux-x64": "0.25.11",
+				"@esbuild/netbsd-arm64": "0.25.11",
+				"@esbuild/netbsd-x64": "0.25.11",
+				"@esbuild/openbsd-arm64": "0.25.11",
+				"@esbuild/openbsd-x64": "0.25.11",
+				"@esbuild/openharmony-arm64": "0.25.11",
+				"@esbuild/sunos-x64": "0.25.11",
+				"@esbuild/win32-arm64": "0.25.11",
+				"@esbuild/win32-ia32": "0.25.11",
+				"@esbuild/win32-x64": "0.25.11"
+			}
+		},
+		"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
+		},
+		"node_modules/esrap": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.2.tgz",
+			"integrity": "sha512-DgvlIQeowRNyvLPWW4PT7Gu13WznY288Du086E751mwwbsgr29ytBiYeLzAGIo0qk3Ujob0SDk8TiSaM5WQzNg==",
+			"dev": true,
+			"dependencies": {
+				"@jridgewell/sourcemap-codec": "^1.4.15"
+			}
+		},
+		"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,
+			"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,
+			"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
+		},
+		"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,
+			"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,
+			"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,
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/lightningcss": {
+			"version": "1.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
+			"integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==",
+			"dev": true,
+			"dependencies": {
+				"detect-libc": "^2.0.3"
+			},
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			},
+			"optionalDependencies": {
+				"lightningcss-android-arm64": "1.30.2",
+				"lightningcss-darwin-arm64": "1.30.2",
+				"lightningcss-darwin-x64": "1.30.2",
+				"lightningcss-freebsd-x64": "1.30.2",
+				"lightningcss-linux-arm-gnueabihf": "1.30.2",
+				"lightningcss-linux-arm64-gnu": "1.30.2",
+				"lightningcss-linux-arm64-musl": "1.30.2",
+				"lightningcss-linux-x64-gnu": "1.30.2",
+				"lightningcss-linux-x64-musl": "1.30.2",
+				"lightningcss-win32-arm64-msvc": "1.30.2",
+				"lightningcss-win32-x64-msvc": "1.30.2"
+			}
+		},
+		"node_modules/lightningcss-android-arm64": {
+			"version": "1.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz",
+			"integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-darwin-arm64": {
+			"version": "1.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz",
+			"integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-darwin-x64": {
+			"version": "1.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz",
+			"integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">= 12.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/parcel"
+			}
+		},
+		"node_modules/lightningcss-freebsd-x64": {
+			"version": "1.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz",
+			"integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"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.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz",
+			"integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==",
+			"cpu": [
+				"arm"
+			],
+			"dev": true,
+			"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.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz",
+			"integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"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.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz",
+			"integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"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.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz",
+			"integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"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.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz",
+			"integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"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.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz",
+			"integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==",
+			"cpu": [
+				"arm64"
+			],
+			"dev": true,
+			"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.30.2",
+			"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz",
+			"integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==",
+			"cpu": [
+				"x64"
+			],
+			"dev": true,
+			"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
+		},
+		"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,
+			"dependencies": {
+				"@jridgewell/sourcemap-codec": "^1.5.5"
+			}
+		},
+		"node_modules/mini-svg-data-uri": {
+			"version": "1.4.4",
+			"resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
+			"integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
+			"dev": true,
+			"bin": {
+				"mini-svg-data-uri": "cli.js"
+			}
+		},
+		"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,
+			"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,
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/ms": {
+			"version": "2.1.3",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+			"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+			"dev": true
+		},
+		"node_modules/nanoid": {
+			"version": "3.3.11",
+			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+			"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/ai"
+				}
+			],
+			"bin": {
+				"nanoid": "bin/nanoid.cjs"
+			},
+			"engines": {
+				"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+			}
+		},
+		"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
+		},
+		"node_modules/picomatch": {
+			"version": "4.0.3",
+			"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+			"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+			"dev": true,
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/jonschlinkert"
+			}
+		},
+		"node_modules/postcss": {
+			"version": "8.5.6",
+			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+			"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+			"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"
+				}
+			],
+			"dependencies": {
+				"nanoid": "^3.3.11",
+				"picocolors": "^1.1.1",
+				"source-map-js": "^1.2.1"
+			},
+			"engines": {
+				"node": "^10 || ^12 || >=14"
+			}
+		},
+		"node_modules/postcss-selector-parser": {
+			"version": "6.0.10",
+			"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
+			"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
+			"dev": true,
+			"dependencies": {
+				"cssesc": "^3.0.0",
+				"util-deprecate": "^1.0.2"
+			},
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"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,
+			"engines": {
+				"node": ">= 14.18.0"
+			},
+			"funding": {
+				"type": "individual",
+				"url": "https://paulmillr.com/funding/"
+			}
+		},
+		"node_modules/rollup": {
+			"version": "4.52.5",
+			"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz",
+			"integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==",
+			"dev": true,
+			"dependencies": {
+				"@types/estree": "1.0.8"
+			},
+			"bin": {
+				"rollup": "dist/bin/rollup"
+			},
+			"engines": {
+				"node": ">=18.0.0",
+				"npm": ">=8.0.0"
+			},
+			"optionalDependencies": {
+				"@rollup/rollup-android-arm-eabi": "4.52.5",
+				"@rollup/rollup-android-arm64": "4.52.5",
+				"@rollup/rollup-darwin-arm64": "4.52.5",
+				"@rollup/rollup-darwin-x64": "4.52.5",
+				"@rollup/rollup-freebsd-arm64": "4.52.5",
+				"@rollup/rollup-freebsd-x64": "4.52.5",
+				"@rollup/rollup-linux-arm-gnueabihf": "4.52.5",
+				"@rollup/rollup-linux-arm-musleabihf": "4.52.5",
+				"@rollup/rollup-linux-arm64-gnu": "4.52.5",
+				"@rollup/rollup-linux-arm64-musl": "4.52.5",
+				"@rollup/rollup-linux-loong64-gnu": "4.52.5",
+				"@rollup/rollup-linux-ppc64-gnu": "4.52.5",
+				"@rollup/rollup-linux-riscv64-gnu": "4.52.5",
+				"@rollup/rollup-linux-riscv64-musl": "4.52.5",
+				"@rollup/rollup-linux-s390x-gnu": "4.52.5",
+				"@rollup/rollup-linux-x64-gnu": "4.52.5",
+				"@rollup/rollup-linux-x64-musl": "4.52.5",
+				"@rollup/rollup-openharmony-arm64": "4.52.5",
+				"@rollup/rollup-win32-arm64-msvc": "4.52.5",
+				"@rollup/rollup-win32-ia32-msvc": "4.52.5",
+				"@rollup/rollup-win32-x64-gnu": "4.52.5",
+				"@rollup/rollup-win32-x64-msvc": "4.52.5",
+				"fsevents": "~2.3.2"
+			}
+		},
+		"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,
+			"dependencies": {
+				"mri": "^1.1.0"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/set-cookie-parser": {
+			"version": "2.7.2",
+			"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
+			"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
+			"dev": true
+		},
+		"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,
+			"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,
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/svelte": {
+			"version": "5.43.2",
+			"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.43.2.tgz",
+			"integrity": "sha512-ro1umEzX8rT5JpCmlf0PPv7ncD8MdVob9e18bhwqTKNoLjS8kDvhVpaoYVPc+qMwDAOfcwJtyY7ZFSDbOaNPgA==",
+			"dev": true,
+			"dependencies": {
+				"@jridgewell/remapping": "^2.3.4",
+				"@jridgewell/sourcemap-codec": "^1.5.0",
+				"@sveltejs/acorn-typescript": "^1.0.5",
+				"@types/estree": "^1.0.5",
+				"acorn": "^8.12.1",
+				"aria-query": "^5.3.1",
+				"axobject-query": "^4.1.0",
+				"clsx": "^2.1.1",
+				"esm-env": "^1.2.1",
+				"esrap": "^2.1.0",
+				"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.3.3",
+			"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.3.tgz",
+			"integrity": "sha512-RYP0bEwenDXzfv0P1sKAwjZSlaRyqBn0Fz1TVni58lqyEiqgwztTpmodJrGzP6ZT2aHl4MbTvWP6gbmQ3FOnBg==",
+			"dev": true,
+			"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.1.16",
+			"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.16.tgz",
+			"integrity": "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==",
+			"dev": true
+		},
+		"node_modules/tapable": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
+			"integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+			"dev": true,
+			"engines": {
+				"node": ">=6"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/webpack"
+			}
+		},
+		"node_modules/tinyglobby": {
+			"version": "0.2.15",
+			"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+			"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+			"dev": true,
+			"dependencies": {
+				"fdir": "^6.5.0",
+				"picomatch": "^4.0.3"
+			},
+			"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,
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/typescript": {
+			"version": "5.9.3",
+			"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+			"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+			"dev": true,
+			"bin": {
+				"tsc": "bin/tsc",
+				"tsserver": "bin/tsserver"
+			},
+			"engines": {
+				"node": ">=14.17"
+			}
+		},
+		"node_modules/util-deprecate": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+			"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+			"dev": true
+		},
+		"node_modules/vite": {
+			"version": "6.4.1",
+			"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+			"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
+			"dev": true,
+			"dependencies": {
+				"esbuild": "^0.25.0",
+				"fdir": "^6.4.4",
+				"picomatch": "^4.0.2",
+				"postcss": "^8.5.3",
+				"rollup": "^4.34.9",
+				"tinyglobby": "^0.2.13"
+			},
+			"bin": {
+				"vite": "bin/vite.js"
+			},
+			"engines": {
+				"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/vitejs/vite?sponsor=1"
+			},
+			"optionalDependencies": {
+				"fsevents": "~2.3.3"
+			},
+			"peerDependencies": {
+				"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+				"jiti": ">=1.21.0",
+				"less": "*",
+				"lightningcss": "^1.21.0",
+				"sass": "*",
+				"sass-embedded": "*",
+				"stylus": "*",
+				"sugarss": "*",
+				"terser": "^5.16.0",
+				"tsx": "^4.8.1",
+				"yaml": "^2.4.2"
+			},
+			"peerDependenciesMeta": {
+				"@types/node": {
+					"optional": true
+				},
+				"jiti": {
+					"optional": true
+				},
+				"less": {
+					"optional": true
+				},
+				"lightningcss": {
+					"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.1",
+			"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz",
+			"integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==",
+			"dev": true,
+			"peerDependencies": {
+				"vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.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
+		}
+	}
+}

+ 33 - 0
package.json

@@ -0,0 +1,33 @@
+{
+	"name": "test-svelte",
+	"private": true,
+	"version": "0.0.1",
+	"type": "module",
+	"scripts": {
+		"dev": "vite dev",
+		"build": "vite build",
+		"preview": "vite preview",
+		"prepare": "svelte-kit sync || echo ''",
+		"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+		"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
+	},
+	"devDependencies": {
+		"@sveltejs/adapter-auto": "^6.0.0",
+		"@sveltejs/kit": "^2.16.0",
+		"@sveltejs/vite-plugin-svelte": "^5.0.0",
+		"@tailwindcss/forms": "^0.5.9",
+		"@tailwindcss/typography": "^0.5.15",
+		"@tailwindcss/vite": "^4.0.0",
+		"daisyui": "^5.0.46",
+		"svelte": "^5.0.0",
+		"svelte-check": "^4.0.0",
+		"tailwindcss": "^4.0.0",
+		"typescript": "^5.0.0",
+		"vite": "^6.2.6"
+	},
+	"pnpm": {
+		"onlyBuiltDependencies": [
+			"esbuild"
+		]
+	}
+}

+ 1397 - 0
pnpm-lock.yaml

@@ -0,0 +1,1397 @@
+lockfileVersion: '9.0'
+
+settings:
+  autoInstallPeers: true
+  excludeLinksFromLockfile: false
+
+importers:
+
+  .:
+    devDependencies:
+      '@sveltejs/adapter-auto':
+        specifier: ^6.0.0
+        version: 6.0.1(@sveltejs/kit@2.22.2(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))
+      '@sveltejs/kit':
+        specifier: ^2.16.0
+        version: 2.22.2(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+      '@sveltejs/vite-plugin-svelte':
+        specifier: ^5.0.0
+        version: 5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+      '@tailwindcss/forms':
+        specifier: ^0.5.9
+        version: 0.5.10(tailwindcss@4.1.11)
+      '@tailwindcss/typography':
+        specifier: ^0.5.15
+        version: 0.5.16(tailwindcss@4.1.11)
+      '@tailwindcss/vite':
+        specifier: ^4.0.0
+        version: 4.1.11(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+      daisyui:
+        specifier: ^5.0.46
+        version: 5.0.46
+      svelte:
+        specifier: ^5.0.0
+        version: 5.35.3
+      svelte-check:
+        specifier: ^4.0.0
+        version: 4.2.2(picomatch@4.0.2)(svelte@5.35.3)(typescript@5.8.3)
+      tailwindcss:
+        specifier: ^4.0.0
+        version: 4.1.11
+      typescript:
+        specifier: ^5.0.0
+        version: 5.8.3
+      vite:
+        specifier: ^6.2.6
+        version: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
+
+packages:
+
+  '@ampproject/remapping@2.3.0':
+    resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+    engines: {node: '>=6.0.0'}
+
+  '@esbuild/aix-ppc64@0.25.5':
+    resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [aix]
+
+  '@esbuild/android-arm64@0.25.5':
+    resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm@0.25.5':
+    resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-x64@0.25.5':
+    resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/darwin-arm64@0.25.5':
+    resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.25.5':
+    resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/freebsd-arm64@0.25.5':
+    resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.25.5':
+    resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/linux-arm64@0.25.5':
+    resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.25.5':
+    resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.25.5':
+    resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.25.5':
+    resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==}
+    engines: {node: '>=18'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.25.5':
+    resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==}
+    engines: {node: '>=18'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.25.5':
+    resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.25.5':
+    resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==}
+    engines: {node: '>=18'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.25.5':
+    resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==}
+    engines: {node: '>=18'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.25.5':
+    resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/netbsd-arm64@0.25.5':
+    resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-x64@0.25.5':
+    resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/openbsd-arm64@0.25.5':
+    resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-x64@0.25.5':
+    resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/sunos-x64@0.25.5':
+    resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/win32-arm64@0.25.5':
+    resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.25.5':
+    resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.25.5':
+    resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [win32]
+
+  '@isaacs/fs-minipass@4.0.1':
+    resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
+    engines: {node: '>=18.0.0'}
+
+  '@jridgewell/gen-mapping@0.3.12':
+    resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==}
+
+  '@jridgewell/resolve-uri@3.1.2':
+    resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/sourcemap-codec@1.5.4':
+    resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
+
+  '@jridgewell/trace-mapping@0.3.29':
+    resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==}
+
+  '@polka/url@1.0.0-next.29':
+    resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
+
+  '@rollup/rollup-android-arm-eabi@4.44.2':
+    resolution: {integrity: sha512-g0dF8P1e2QYPOj1gu7s/3LVP6kze9A7m6x0BZ9iTdXK8N5c2V7cpBKHV3/9A4Zd8xxavdhK0t4PnqjkqVmUc9Q==}
+    cpu: [arm]
+    os: [android]
+
+  '@rollup/rollup-android-arm64@4.44.2':
+    resolution: {integrity: sha512-Yt5MKrOosSbSaAK5Y4J+vSiID57sOvpBNBR6K7xAaQvk3MkcNVV0f9fE20T+41WYN8hDn6SGFlFrKudtx4EoxA==}
+    cpu: [arm64]
+    os: [android]
+
+  '@rollup/rollup-darwin-arm64@4.44.2':
+    resolution: {integrity: sha512-EsnFot9ZieM35YNA26nhbLTJBHD0jTwWpPwmRVDzjylQT6gkar+zenfb8mHxWpRrbn+WytRRjE0WKsfaxBkVUA==}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@rollup/rollup-darwin-x64@4.44.2':
+    resolution: {integrity: sha512-dv/t1t1RkCvJdWWxQ2lWOO+b7cMsVw5YFaS04oHpZRWehI1h0fV1gF4wgGCTyQHHjJDfbNpwOi6PXEafRBBezw==}
+    cpu: [x64]
+    os: [darwin]
+
+  '@rollup/rollup-freebsd-arm64@4.44.2':
+    resolution: {integrity: sha512-W4tt4BLorKND4qeHElxDoim0+BsprFTwb+vriVQnFFtT/P6v/xO5I99xvYnVzKWrK6j7Hb0yp3x7V5LUbaeOMg==}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@rollup/rollup-freebsd-x64@4.44.2':
+    resolution: {integrity: sha512-tdT1PHopokkuBVyHjvYehnIe20fxibxFCEhQP/96MDSOcyjM/shlTkZZLOufV3qO6/FQOSiJTBebhVc12JyPTA==}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@rollup/rollup-linux-arm-gnueabihf@4.44.2':
+    resolution: {integrity: sha512-+xmiDGGaSfIIOXMzkhJ++Oa0Gwvl9oXUeIiwarsdRXSe27HUIvjbSIpPxvnNsRebsNdUo7uAiQVgBD1hVriwSQ==}
+    cpu: [arm]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm-musleabihf@4.44.2':
+    resolution: {integrity: sha512-bDHvhzOfORk3wt8yxIra8N4k/N0MnKInCW5OGZaeDYa/hMrdPaJzo7CSkjKZqX4JFUWjUGm88lI6QJLCM7lDrA==}
+    cpu: [arm]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm64-gnu@4.44.2':
+    resolution: {integrity: sha512-NMsDEsDiYghTbeZWEGnNi4F0hSbGnsuOG+VnNvxkKg0IGDvFh7UVpM/14mnMwxRxUf9AdAVJgHPvKXf6FpMB7A==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm64-musl@4.44.2':
+    resolution: {integrity: sha512-lb5bxXnxXglVq+7imxykIp5xMq+idehfl+wOgiiix0191av84OqbjUED+PRC5OA8eFJYj5xAGcpAZ0pF2MnW+A==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@rollup/rollup-linux-loongarch64-gnu@4.44.2':
+    resolution: {integrity: sha512-Yl5Rdpf9pIc4GW1PmkUGHdMtbx0fBLE1//SxDmuf3X0dUC57+zMepow2LK0V21661cjXdTn8hO2tXDdAWAqE5g==}
+    cpu: [loong64]
+    os: [linux]
+
+  '@rollup/rollup-linux-powerpc64le-gnu@4.44.2':
+    resolution: {integrity: sha512-03vUDH+w55s680YYryyr78jsO1RWU9ocRMaeV2vMniJJW/6HhoTBwyyiiTPVHNWLnhsnwcQ0oH3S9JSBEKuyqw==}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@rollup/rollup-linux-riscv64-gnu@4.44.2':
+    resolution: {integrity: sha512-iYtAqBg5eEMG4dEfVlkqo05xMOk6y/JXIToRca2bAWuqjrJYJlx/I7+Z+4hSrsWU8GdJDFPL4ktV3dy4yBSrzg==}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@rollup/rollup-linux-riscv64-musl@4.44.2':
+    resolution: {integrity: sha512-e6vEbgaaqz2yEHqtkPXa28fFuBGmUJ0N2dOJK8YUfijejInt9gfCSA7YDdJ4nYlv67JfP3+PSWFX4IVw/xRIPg==}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@rollup/rollup-linux-s390x-gnu@4.44.2':
+    resolution: {integrity: sha512-evFOtkmVdY3udE+0QKrV5wBx7bKI0iHz5yEVx5WqDJkxp9YQefy4Mpx3RajIVcM6o7jxTvVd/qpC1IXUhGc1Mw==}
+    cpu: [s390x]
+    os: [linux]
+
+  '@rollup/rollup-linux-x64-gnu@4.44.2':
+    resolution: {integrity: sha512-/bXb0bEsWMyEkIsUL2Yt5nFB5naLAwyOWMEviQfQY1x3l5WsLKgvZf66TM7UTfED6erckUVUJQ/jJ1FSpm3pRQ==}
+    cpu: [x64]
+    os: [linux]
+
+  '@rollup/rollup-linux-x64-musl@4.44.2':
+    resolution: {integrity: sha512-3D3OB1vSSBXmkGEZR27uiMRNiwN08/RVAcBKwhUYPaiZ8bcvdeEwWPvbnXvvXHY+A/7xluzcN+kaiOFNiOZwWg==}
+    cpu: [x64]
+    os: [linux]
+
+  '@rollup/rollup-win32-arm64-msvc@4.44.2':
+    resolution: {integrity: sha512-VfU0fsMK+rwdK8mwODqYeM2hDrF2WiHaSmCBrS7gColkQft95/8tphyzv2EupVxn3iE0FI78wzffoULH1G+dkw==}
+    cpu: [arm64]
+    os: [win32]
+
+  '@rollup/rollup-win32-ia32-msvc@4.44.2':
+    resolution: {integrity: sha512-+qMUrkbUurpE6DVRjiJCNGZBGo9xM4Y0FXU5cjgudWqIBWbcLkjE3XprJUsOFgC6xjBClwVa9k6O3A7K3vxb5Q==}
+    cpu: [ia32]
+    os: [win32]
+
+  '@rollup/rollup-win32-x64-msvc@4.44.2':
+    resolution: {integrity: sha512-3+QZROYfJ25PDcxFF66UEk8jGWigHJeecZILvkPkyQN7oc5BvFo4YEXFkOs154j3FTMp9mn9Ky8RCOwastduEA==}
+    cpu: [x64]
+    os: [win32]
+
+  '@sveltejs/acorn-typescript@1.0.5':
+    resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==}
+    peerDependencies:
+      acorn: ^8.9.0
+
+  '@sveltejs/adapter-auto@6.0.1':
+    resolution: {integrity: sha512-mcWud3pYGPWM2Pphdj8G9Qiq24nZ8L4LB7coCUckUEy5Y7wOWGJ/enaZ4AtJTcSm5dNK1rIkBRoqt+ae4zlxcQ==}
+    peerDependencies:
+      '@sveltejs/kit': ^2.0.0
+
+  '@sveltejs/kit@2.22.2':
+    resolution: {integrity: sha512-2MvEpSYabUrsJAoq5qCOBGAlkICjfjunrnLcx3YAk2XV7TvAIhomlKsAgR4H/4uns5rAfYmj7Wet5KRtc8dPIg==}
+    engines: {node: '>=18.13'}
+    hasBin: true
+    peerDependencies:
+      '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0
+      svelte: ^4.0.0 || ^5.0.0-next.0
+      vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0
+
+  '@sveltejs/vite-plugin-svelte-inspector@4.0.1':
+    resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22}
+    peerDependencies:
+      '@sveltejs/vite-plugin-svelte': ^5.0.0
+      svelte: ^5.0.0
+      vite: ^6.0.0
+
+  '@sveltejs/vite-plugin-svelte@5.1.0':
+    resolution: {integrity: sha512-wojIS/7GYnJDYIg1higWj2ROA6sSRWvcR1PO/bqEyFr/5UZah26c8Cz4u0NaqjPeVltzsVpt2Tm8d2io0V+4Tw==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22}
+    peerDependencies:
+      svelte: ^5.0.0
+      vite: ^6.0.0
+
+  '@tailwindcss/forms@0.5.10':
+    resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==}
+    peerDependencies:
+      tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1'
+
+  '@tailwindcss/node@4.1.11':
+    resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==}
+
+  '@tailwindcss/oxide-android-arm64@4.1.11':
+    resolution: {integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [android]
+
+  '@tailwindcss/oxide-darwin-arm64@4.1.11':
+    resolution: {integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@tailwindcss/oxide-darwin-x64@4.1.11':
+    resolution: {integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@tailwindcss/oxide-freebsd-x64@4.1.11':
+    resolution: {integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11':
+    resolution: {integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==}
+    engines: {node: '>= 10'}
+    cpu: [arm]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-arm64-gnu@4.1.11':
+    resolution: {integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-arm64-musl@4.1.11':
+    resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-x64-gnu@4.1.11':
+    resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-x64-musl@4.1.11':
+    resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@tailwindcss/oxide-wasm32-wasi@4.1.11':
+    resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==}
+    engines: {node: '>=14.0.0'}
+    cpu: [wasm32]
+    bundledDependencies:
+      - '@napi-rs/wasm-runtime'
+      - '@emnapi/core'
+      - '@emnapi/runtime'
+      - '@tybys/wasm-util'
+      - '@emnapi/wasi-threads'
+      - tslib
+
+  '@tailwindcss/oxide-win32-arm64-msvc@4.1.11':
+    resolution: {integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@tailwindcss/oxide-win32-x64-msvc@4.1.11':
+    resolution: {integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [win32]
+
+  '@tailwindcss/oxide@4.1.11':
+    resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==}
+    engines: {node: '>= 10'}
+
+  '@tailwindcss/typography@0.5.16':
+    resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==}
+    peerDependencies:
+      tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
+
+  '@tailwindcss/vite@4.1.11':
+    resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==}
+    peerDependencies:
+      vite: ^5.2.0 || ^6 || ^7
+
+  '@types/cookie@0.6.0':
+    resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
+
+  '@types/estree@1.0.8':
+    resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+  acorn@8.15.0:
+    resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+
+  aria-query@5.3.2:
+    resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
+    engines: {node: '>= 0.4'}
+
+  axobject-query@4.1.0:
+    resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
+    engines: {node: '>= 0.4'}
+
+  chokidar@4.0.3:
+    resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
+    engines: {node: '>= 14.16.0'}
+
+  chownr@3.0.0:
+    resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
+    engines: {node: '>=18'}
+
+  clsx@2.1.1:
+    resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
+    engines: {node: '>=6'}
+
+  cookie@0.6.0:
+    resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
+    engines: {node: '>= 0.6'}
+
+  cssesc@3.0.0:
+    resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  daisyui@5.0.46:
+    resolution: {integrity: sha512-vMDZK1tI/bOb2Mc3Mk5WpquBG3ZqBz1YKZ0xDlvpOvey60dOS4/5Qhdowq1HndbQl7PgDLDYysxAjjUjwR7/eQ==}
+
+  debug@4.4.1:
+    resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
+    engines: {node: '>=6.0'}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
+  deepmerge@4.3.1:
+    resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
+    engines: {node: '>=0.10.0'}
+
+  detect-libc@2.0.4:
+    resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
+    engines: {node: '>=8'}
+
+  devalue@5.1.1:
+    resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==}
+
+  enhanced-resolve@5.18.2:
+    resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==}
+    engines: {node: '>=10.13.0'}
+
+  esbuild@0.25.5:
+    resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==}
+    engines: {node: '>=18'}
+    hasBin: true
+
+  esm-env@1.2.2:
+    resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
+
+  esrap@2.1.0:
+    resolution: {integrity: sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==}
+
+  fdir@6.4.6:
+    resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
+    peerDependencies:
+      picomatch: ^3 || ^4
+    peerDependenciesMeta:
+      picomatch:
+        optional: true
+
+  fsevents@2.3.3:
+    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+    os: [darwin]
+
+  graceful-fs@4.2.11:
+    resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+  is-reference@3.0.3:
+    resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
+
+  jiti@2.4.2:
+    resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
+    hasBin: true
+
+  kleur@4.1.5:
+    resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
+    engines: {node: '>=6'}
+
+  lightningcss-darwin-arm64@1.30.1:
+    resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [darwin]
+
+  lightningcss-darwin-x64@1.30.1:
+    resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [darwin]
+
+  lightningcss-freebsd-x64@1.30.1:
+    resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [freebsd]
+
+  lightningcss-linux-arm-gnueabihf@1.30.1:
+    resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm]
+    os: [linux]
+
+  lightningcss-linux-arm64-gnu@1.30.1:
+    resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  lightningcss-linux-arm64-musl@1.30.1:
+    resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  lightningcss-linux-x64-gnu@1.30.1:
+    resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [linux]
+
+  lightningcss-linux-x64-musl@1.30.1:
+    resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [linux]
+
+  lightningcss-win32-arm64-msvc@1.30.1:
+    resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [win32]
+
+  lightningcss-win32-x64-msvc@1.30.1:
+    resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [win32]
+
+  lightningcss@1.30.1:
+    resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
+    engines: {node: '>= 12.0.0'}
+
+  locate-character@3.0.0:
+    resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
+
+  lodash.castarray@4.4.0:
+    resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
+
+  lodash.isplainobject@4.0.6:
+    resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
+
+  lodash.merge@4.6.2:
+    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+  magic-string@0.30.17:
+    resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+
+  mini-svg-data-uri@1.4.4:
+    resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
+    hasBin: true
+
+  minipass@7.1.2:
+    resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  minizlib@3.0.2:
+    resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==}
+    engines: {node: '>= 18'}
+
+  mkdirp@3.0.1:
+    resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  mri@1.2.0:
+    resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
+    engines: {node: '>=4'}
+
+  mrmime@2.0.1:
+    resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
+    engines: {node: '>=10'}
+
+  ms@2.1.3:
+    resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+  nanoid@3.3.11:
+    resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+    hasBin: true
+
+  picocolors@1.1.1:
+    resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+  picomatch@4.0.2:
+    resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
+    engines: {node: '>=12'}
+
+  postcss-selector-parser@6.0.10:
+    resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
+    engines: {node: '>=4'}
+
+  postcss@8.5.6:
+    resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+    engines: {node: ^10 || ^12 || >=14}
+
+  readdirp@4.1.2:
+    resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
+    engines: {node: '>= 14.18.0'}
+
+  rollup@4.44.2:
+    resolution: {integrity: sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==}
+    engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+    hasBin: true
+
+  sade@1.8.1:
+    resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
+    engines: {node: '>=6'}
+
+  set-cookie-parser@2.7.1:
+    resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
+
+  sirv@3.0.1:
+    resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
+    engines: {node: '>=18'}
+
+  source-map-js@1.2.1:
+    resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+    engines: {node: '>=0.10.0'}
+
+  svelte-check@4.2.2:
+    resolution: {integrity: sha512-1+31EOYZ7NKN0YDMKusav2hhEoA51GD9Ws6o//0SphMT0ve9mBTsTUEX7OmDMadUP3KjNHsSKtJrqdSaD8CrGQ==}
+    engines: {node: '>= 18.0.0'}
+    hasBin: true
+    peerDependencies:
+      svelte: ^4.0.0 || ^5.0.0-next.0
+      typescript: '>=5.0.0'
+
+  svelte@5.35.3:
+    resolution: {integrity: sha512-/eW3yMa+7FECZBlrt5px5pbw7nRY7QcZqUvx4zcodB25tVEBYSoWbTjH8CbAvw8jdU9VoxUzcy5x0UPp/bNJDw==}
+    engines: {node: '>=18'}
+
+  tailwindcss@4.1.11:
+    resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==}
+
+  tapable@2.2.2:
+    resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==}
+    engines: {node: '>=6'}
+
+  tar@7.4.3:
+    resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
+    engines: {node: '>=18'}
+
+  tinyglobby@0.2.14:
+    resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
+    engines: {node: '>=12.0.0'}
+
+  totalist@3.0.1:
+    resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
+    engines: {node: '>=6'}
+
+  typescript@5.8.3:
+    resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+
+  util-deprecate@1.0.2:
+    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+  vite@6.3.5:
+    resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+    hasBin: true
+    peerDependencies:
+      '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+      jiti: '>=1.21.0'
+      less: '*'
+      lightningcss: ^1.21.0
+      sass: '*'
+      sass-embedded: '*'
+      stylus: '*'
+      sugarss: '*'
+      terser: ^5.16.0
+      tsx: ^4.8.1
+      yaml: ^2.4.2
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+      jiti:
+        optional: true
+      less:
+        optional: true
+      lightningcss:
+        optional: true
+      sass:
+        optional: true
+      sass-embedded:
+        optional: true
+      stylus:
+        optional: true
+      sugarss:
+        optional: true
+      terser:
+        optional: true
+      tsx:
+        optional: true
+      yaml:
+        optional: true
+
+  vitefu@1.1.1:
+    resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==}
+    peerDependencies:
+      vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
+    peerDependenciesMeta:
+      vite:
+        optional: true
+
+  yallist@5.0.0:
+    resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
+    engines: {node: '>=18'}
+
+  zimmerframe@1.1.2:
+    resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
+
+snapshots:
+
+  '@ampproject/remapping@2.3.0':
+    dependencies:
+      '@jridgewell/gen-mapping': 0.3.12
+      '@jridgewell/trace-mapping': 0.3.29
+
+  '@esbuild/aix-ppc64@0.25.5':
+    optional: true
+
+  '@esbuild/android-arm64@0.25.5':
+    optional: true
+
+  '@esbuild/android-arm@0.25.5':
+    optional: true
+
+  '@esbuild/android-x64@0.25.5':
+    optional: true
+
+  '@esbuild/darwin-arm64@0.25.5':
+    optional: true
+
+  '@esbuild/darwin-x64@0.25.5':
+    optional: true
+
+  '@esbuild/freebsd-arm64@0.25.5':
+    optional: true
+
+  '@esbuild/freebsd-x64@0.25.5':
+    optional: true
+
+  '@esbuild/linux-arm64@0.25.5':
+    optional: true
+
+  '@esbuild/linux-arm@0.25.5':
+    optional: true
+
+  '@esbuild/linux-ia32@0.25.5':
+    optional: true
+
+  '@esbuild/linux-loong64@0.25.5':
+    optional: true
+
+  '@esbuild/linux-mips64el@0.25.5':
+    optional: true
+
+  '@esbuild/linux-ppc64@0.25.5':
+    optional: true
+
+  '@esbuild/linux-riscv64@0.25.5':
+    optional: true
+
+  '@esbuild/linux-s390x@0.25.5':
+    optional: true
+
+  '@esbuild/linux-x64@0.25.5':
+    optional: true
+
+  '@esbuild/netbsd-arm64@0.25.5':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.25.5':
+    optional: true
+
+  '@esbuild/openbsd-arm64@0.25.5':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.25.5':
+    optional: true
+
+  '@esbuild/sunos-x64@0.25.5':
+    optional: true
+
+  '@esbuild/win32-arm64@0.25.5':
+    optional: true
+
+  '@esbuild/win32-ia32@0.25.5':
+    optional: true
+
+  '@esbuild/win32-x64@0.25.5':
+    optional: true
+
+  '@isaacs/fs-minipass@4.0.1':
+    dependencies:
+      minipass: 7.1.2
+
+  '@jridgewell/gen-mapping@0.3.12':
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.5.4
+      '@jridgewell/trace-mapping': 0.3.29
+
+  '@jridgewell/resolve-uri@3.1.2': {}
+
+  '@jridgewell/sourcemap-codec@1.5.4': {}
+
+  '@jridgewell/trace-mapping@0.3.29':
+    dependencies:
+      '@jridgewell/resolve-uri': 3.1.2
+      '@jridgewell/sourcemap-codec': 1.5.4
+
+  '@polka/url@1.0.0-next.29': {}
+
+  '@rollup/rollup-android-arm-eabi@4.44.2':
+    optional: true
+
+  '@rollup/rollup-android-arm64@4.44.2':
+    optional: true
+
+  '@rollup/rollup-darwin-arm64@4.44.2':
+    optional: true
+
+  '@rollup/rollup-darwin-x64@4.44.2':
+    optional: true
+
+  '@rollup/rollup-freebsd-arm64@4.44.2':
+    optional: true
+
+  '@rollup/rollup-freebsd-x64@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-arm-gnueabihf@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-arm-musleabihf@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-arm64-gnu@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-arm64-musl@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-loongarch64-gnu@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-powerpc64le-gnu@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-riscv64-gnu@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-riscv64-musl@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-s390x-gnu@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-x64-gnu@4.44.2':
+    optional: true
+
+  '@rollup/rollup-linux-x64-musl@4.44.2':
+    optional: true
+
+  '@rollup/rollup-win32-arm64-msvc@4.44.2':
+    optional: true
+
+  '@rollup/rollup-win32-ia32-msvc@4.44.2':
+    optional: true
+
+  '@rollup/rollup-win32-x64-msvc@4.44.2':
+    optional: true
+
+  '@sveltejs/acorn-typescript@1.0.5(acorn@8.15.0)':
+    dependencies:
+      acorn: 8.15.0
+
+  '@sveltejs/adapter-auto@6.0.1(@sveltejs/kit@2.22.2(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))':
+    dependencies:
+      '@sveltejs/kit': 2.22.2(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+
+  '@sveltejs/kit@2.22.2(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))':
+    dependencies:
+      '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
+      '@sveltejs/vite-plugin-svelte': 5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+      '@types/cookie': 0.6.0
+      acorn: 8.15.0
+      cookie: 0.6.0
+      devalue: 5.1.1
+      esm-env: 1.2.2
+      kleur: 4.1.5
+      magic-string: 0.30.17
+      mrmime: 2.0.1
+      sade: 1.8.1
+      set-cookie-parser: 2.7.1
+      sirv: 3.0.1
+      svelte: 5.35.3
+      vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
+      vitefu: 1.1.1(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+
+  '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))':
+    dependencies:
+      '@sveltejs/vite-plugin-svelte': 5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+      debug: 4.4.1
+      svelte: 5.35.3
+      vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
+    transitivePeerDependencies:
+      - supports-color
+
+  '@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))':
+    dependencies:
+      '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+      debug: 4.4.1
+      deepmerge: 4.3.1
+      kleur: 4.1.5
+      magic-string: 0.30.17
+      svelte: 5.35.3
+      vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
+      vitefu: 1.1.1(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+    transitivePeerDependencies:
+      - supports-color
+
+  '@tailwindcss/forms@0.5.10(tailwindcss@4.1.11)':
+    dependencies:
+      mini-svg-data-uri: 1.4.4
+      tailwindcss: 4.1.11
+
+  '@tailwindcss/node@4.1.11':
+    dependencies:
+      '@ampproject/remapping': 2.3.0
+      enhanced-resolve: 5.18.2
+      jiti: 2.4.2
+      lightningcss: 1.30.1
+      magic-string: 0.30.17
+      source-map-js: 1.2.1
+      tailwindcss: 4.1.11
+
+  '@tailwindcss/oxide-android-arm64@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-darwin-arm64@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-darwin-x64@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-freebsd-x64@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-linux-arm64-gnu@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-linux-arm64-musl@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-linux-x64-gnu@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-linux-x64-musl@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-wasm32-wasi@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-win32-arm64-msvc@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide-win32-x64-msvc@4.1.11':
+    optional: true
+
+  '@tailwindcss/oxide@4.1.11':
+    dependencies:
+      detect-libc: 2.0.4
+      tar: 7.4.3
+    optionalDependencies:
+      '@tailwindcss/oxide-android-arm64': 4.1.11
+      '@tailwindcss/oxide-darwin-arm64': 4.1.11
+      '@tailwindcss/oxide-darwin-x64': 4.1.11
+      '@tailwindcss/oxide-freebsd-x64': 4.1.11
+      '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.11
+      '@tailwindcss/oxide-linux-arm64-gnu': 4.1.11
+      '@tailwindcss/oxide-linux-arm64-musl': 4.1.11
+      '@tailwindcss/oxide-linux-x64-gnu': 4.1.11
+      '@tailwindcss/oxide-linux-x64-musl': 4.1.11
+      '@tailwindcss/oxide-wasm32-wasi': 4.1.11
+      '@tailwindcss/oxide-win32-arm64-msvc': 4.1.11
+      '@tailwindcss/oxide-win32-x64-msvc': 4.1.11
+
+  '@tailwindcss/typography@0.5.16(tailwindcss@4.1.11)':
+    dependencies:
+      lodash.castarray: 4.4.0
+      lodash.isplainobject: 4.0.6
+      lodash.merge: 4.6.2
+      postcss-selector-parser: 6.0.10
+      tailwindcss: 4.1.11
+
+  '@tailwindcss/vite@4.1.11(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))':
+    dependencies:
+      '@tailwindcss/node': 4.1.11
+      '@tailwindcss/oxide': 4.1.11
+      tailwindcss: 4.1.11
+      vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
+
+  '@types/cookie@0.6.0': {}
+
+  '@types/estree@1.0.8': {}
+
+  acorn@8.15.0: {}
+
+  aria-query@5.3.2: {}
+
+  axobject-query@4.1.0: {}
+
+  chokidar@4.0.3:
+    dependencies:
+      readdirp: 4.1.2
+
+  chownr@3.0.0: {}
+
+  clsx@2.1.1: {}
+
+  cookie@0.6.0: {}
+
+  cssesc@3.0.0: {}
+
+  daisyui@5.0.46: {}
+
+  debug@4.4.1:
+    dependencies:
+      ms: 2.1.3
+
+  deepmerge@4.3.1: {}
+
+  detect-libc@2.0.4: {}
+
+  devalue@5.1.1: {}
+
+  enhanced-resolve@5.18.2:
+    dependencies:
+      graceful-fs: 4.2.11
+      tapable: 2.2.2
+
+  esbuild@0.25.5:
+    optionalDependencies:
+      '@esbuild/aix-ppc64': 0.25.5
+      '@esbuild/android-arm': 0.25.5
+      '@esbuild/android-arm64': 0.25.5
+      '@esbuild/android-x64': 0.25.5
+      '@esbuild/darwin-arm64': 0.25.5
+      '@esbuild/darwin-x64': 0.25.5
+      '@esbuild/freebsd-arm64': 0.25.5
+      '@esbuild/freebsd-x64': 0.25.5
+      '@esbuild/linux-arm': 0.25.5
+      '@esbuild/linux-arm64': 0.25.5
+      '@esbuild/linux-ia32': 0.25.5
+      '@esbuild/linux-loong64': 0.25.5
+      '@esbuild/linux-mips64el': 0.25.5
+      '@esbuild/linux-ppc64': 0.25.5
+      '@esbuild/linux-riscv64': 0.25.5
+      '@esbuild/linux-s390x': 0.25.5
+      '@esbuild/linux-x64': 0.25.5
+      '@esbuild/netbsd-arm64': 0.25.5
+      '@esbuild/netbsd-x64': 0.25.5
+      '@esbuild/openbsd-arm64': 0.25.5
+      '@esbuild/openbsd-x64': 0.25.5
+      '@esbuild/sunos-x64': 0.25.5
+      '@esbuild/win32-arm64': 0.25.5
+      '@esbuild/win32-ia32': 0.25.5
+      '@esbuild/win32-x64': 0.25.5
+
+  esm-env@1.2.2: {}
+
+  esrap@2.1.0:
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.5.4
+
+  fdir@6.4.6(picomatch@4.0.2):
+    optionalDependencies:
+      picomatch: 4.0.2
+
+  fsevents@2.3.3:
+    optional: true
+
+  graceful-fs@4.2.11: {}
+
+  is-reference@3.0.3:
+    dependencies:
+      '@types/estree': 1.0.8
+
+  jiti@2.4.2: {}
+
+  kleur@4.1.5: {}
+
+  lightningcss-darwin-arm64@1.30.1:
+    optional: true
+
+  lightningcss-darwin-x64@1.30.1:
+    optional: true
+
+  lightningcss-freebsd-x64@1.30.1:
+    optional: true
+
+  lightningcss-linux-arm-gnueabihf@1.30.1:
+    optional: true
+
+  lightningcss-linux-arm64-gnu@1.30.1:
+    optional: true
+
+  lightningcss-linux-arm64-musl@1.30.1:
+    optional: true
+
+  lightningcss-linux-x64-gnu@1.30.1:
+    optional: true
+
+  lightningcss-linux-x64-musl@1.30.1:
+    optional: true
+
+  lightningcss-win32-arm64-msvc@1.30.1:
+    optional: true
+
+  lightningcss-win32-x64-msvc@1.30.1:
+    optional: true
+
+  lightningcss@1.30.1:
+    dependencies:
+      detect-libc: 2.0.4
+    optionalDependencies:
+      lightningcss-darwin-arm64: 1.30.1
+      lightningcss-darwin-x64: 1.30.1
+      lightningcss-freebsd-x64: 1.30.1
+      lightningcss-linux-arm-gnueabihf: 1.30.1
+      lightningcss-linux-arm64-gnu: 1.30.1
+      lightningcss-linux-arm64-musl: 1.30.1
+      lightningcss-linux-x64-gnu: 1.30.1
+      lightningcss-linux-x64-musl: 1.30.1
+      lightningcss-win32-arm64-msvc: 1.30.1
+      lightningcss-win32-x64-msvc: 1.30.1
+
+  locate-character@3.0.0: {}
+
+  lodash.castarray@4.4.0: {}
+
+  lodash.isplainobject@4.0.6: {}
+
+  lodash.merge@4.6.2: {}
+
+  magic-string@0.30.17:
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.5.4
+
+  mini-svg-data-uri@1.4.4: {}
+
+  minipass@7.1.2: {}
+
+  minizlib@3.0.2:
+    dependencies:
+      minipass: 7.1.2
+
+  mkdirp@3.0.1: {}
+
+  mri@1.2.0: {}
+
+  mrmime@2.0.1: {}
+
+  ms@2.1.3: {}
+
+  nanoid@3.3.11: {}
+
+  picocolors@1.1.1: {}
+
+  picomatch@4.0.2: {}
+
+  postcss-selector-parser@6.0.10:
+    dependencies:
+      cssesc: 3.0.0
+      util-deprecate: 1.0.2
+
+  postcss@8.5.6:
+    dependencies:
+      nanoid: 3.3.11
+      picocolors: 1.1.1
+      source-map-js: 1.2.1
+
+  readdirp@4.1.2: {}
+
+  rollup@4.44.2:
+    dependencies:
+      '@types/estree': 1.0.8
+    optionalDependencies:
+      '@rollup/rollup-android-arm-eabi': 4.44.2
+      '@rollup/rollup-android-arm64': 4.44.2
+      '@rollup/rollup-darwin-arm64': 4.44.2
+      '@rollup/rollup-darwin-x64': 4.44.2
+      '@rollup/rollup-freebsd-arm64': 4.44.2
+      '@rollup/rollup-freebsd-x64': 4.44.2
+      '@rollup/rollup-linux-arm-gnueabihf': 4.44.2
+      '@rollup/rollup-linux-arm-musleabihf': 4.44.2
+      '@rollup/rollup-linux-arm64-gnu': 4.44.2
+      '@rollup/rollup-linux-arm64-musl': 4.44.2
+      '@rollup/rollup-linux-loongarch64-gnu': 4.44.2
+      '@rollup/rollup-linux-powerpc64le-gnu': 4.44.2
+      '@rollup/rollup-linux-riscv64-gnu': 4.44.2
+      '@rollup/rollup-linux-riscv64-musl': 4.44.2
+      '@rollup/rollup-linux-s390x-gnu': 4.44.2
+      '@rollup/rollup-linux-x64-gnu': 4.44.2
+      '@rollup/rollup-linux-x64-musl': 4.44.2
+      '@rollup/rollup-win32-arm64-msvc': 4.44.2
+      '@rollup/rollup-win32-ia32-msvc': 4.44.2
+      '@rollup/rollup-win32-x64-msvc': 4.44.2
+      fsevents: 2.3.3
+
+  sade@1.8.1:
+    dependencies:
+      mri: 1.2.0
+
+  set-cookie-parser@2.7.1: {}
+
+  sirv@3.0.1:
+    dependencies:
+      '@polka/url': 1.0.0-next.29
+      mrmime: 2.0.1
+      totalist: 3.0.1
+
+  source-map-js@1.2.1: {}
+
+  svelte-check@4.2.2(picomatch@4.0.2)(svelte@5.35.3)(typescript@5.8.3):
+    dependencies:
+      '@jridgewell/trace-mapping': 0.3.29
+      chokidar: 4.0.3
+      fdir: 6.4.6(picomatch@4.0.2)
+      picocolors: 1.1.1
+      sade: 1.8.1
+      svelte: 5.35.3
+      typescript: 5.8.3
+    transitivePeerDependencies:
+      - picomatch
+
+  svelte@5.35.3:
+    dependencies:
+      '@ampproject/remapping': 2.3.0
+      '@jridgewell/sourcemap-codec': 1.5.4
+      '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
+      '@types/estree': 1.0.8
+      acorn: 8.15.0
+      aria-query: 5.3.2
+      axobject-query: 4.1.0
+      clsx: 2.1.1
+      esm-env: 1.2.2
+      esrap: 2.1.0
+      is-reference: 3.0.3
+      locate-character: 3.0.0
+      magic-string: 0.30.17
+      zimmerframe: 1.1.2
+
+  tailwindcss@4.1.11: {}
+
+  tapable@2.2.2: {}
+
+  tar@7.4.3:
+    dependencies:
+      '@isaacs/fs-minipass': 4.0.1
+      chownr: 3.0.0
+      minipass: 7.1.2
+      minizlib: 3.0.2
+      mkdirp: 3.0.1
+      yallist: 5.0.0
+
+  tinyglobby@0.2.14:
+    dependencies:
+      fdir: 6.4.6(picomatch@4.0.2)
+      picomatch: 4.0.2
+
+  totalist@3.0.1: {}
+
+  typescript@5.8.3: {}
+
+  util-deprecate@1.0.2: {}
+
+  vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1):
+    dependencies:
+      esbuild: 0.25.5
+      fdir: 6.4.6(picomatch@4.0.2)
+      picomatch: 4.0.2
+      postcss: 8.5.6
+      rollup: 4.44.2
+      tinyglobby: 0.2.14
+    optionalDependencies:
+      fsevents: 2.3.3
+      jiti: 2.4.2
+      lightningcss: 1.30.1
+
+  vitefu@1.1.1(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)):
+    optionalDependencies:
+      vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
+
+  yallist@5.0.0: {}
+
+  zimmerframe@1.1.2: {}

+ 7 - 0
src/app.css

@@ -0,0 +1,7 @@
+@import "tailwindcss";
+@plugin "daisyui";
+
+body {
+    font-family: "Inter", sans-serif;
+    font-size: 22px;
+}

+ 13 - 0
src/app.d.ts

@@ -0,0 +1,13 @@
+// See https://svelte.dev/docs/kit/types#app.d.ts
+// for information about these interfaces
+declare global {
+  namespace App {
+    // interface Error {}
+    // interface Locals {}
+    // interface PageData {}
+    // interface PageState {}
+    // interface Platform {}
+  }
+}
+
+export {};

+ 16 - 0
src/app.html

@@ -0,0 +1,16 @@
+<!doctype html>
+<html lang="en">
+    <head>
+        <meta charset="utf-8" />
+        <link rel="icon" href="%sveltekit.assets%/favicon.svg" />
+        <link
+            href="https://fonts.googleapis.com/css?family=Inter"
+            rel="stylesheet"
+        />
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        %sveltekit.head%
+    </head>
+    <body data-sveltekit-preload-data="hover">
+        <div style="display: contents">%sveltekit.body%</div>
+    </body>
+</html>

+ 7 - 0
src/lib/api.ts

@@ -0,0 +1,7 @@
+export const META_ENV_MODE = import.meta.env.MODE;
+export const SERVER_API_URL = import.meta.env.VITE_SERVER_API_URL;
+export const SERVER_API_PORT = import.meta.env.VITE_SERVER_API_PORT;
+
+console.log(META_ENV_MODE);
+console.log(SERVER_API_URL);
+console.log(SERVER_API_PORT);

+ 91 - 0
src/lib/components/client/clientFilters.svelte

@@ -0,0 +1,91 @@
+<script lang="ts">
+    import type { ClientRole } from "$lib/types/client";
+
+    interface ComponentProps {
+        searchQuery?: string;
+        filterType?: ClientRole | "Все";
+        sortBy?: "name" | "date" | "income" | "requests";
+        sortOrder?: "asc" | "desc";
+        resultsCount?: number;
+        totalCount?: number;
+    }
+
+    let {
+        searchQuery = "",
+        filterType = "Все",
+        sortBy = "name",
+        sortOrder = "asc",
+        resultsCount = 0,
+        totalCount = 0,
+    }: ComponentProps = $props();
+
+    function toggleSortOrder() {
+        sortOrder = sortOrder === "asc" ? "desc" : "asc";
+    }
+</script>
+
+<div class="mb-6 bg-white border border-neutral-300 p-4">
+    <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
+        <div>
+            <label
+                class="block text-xs font-semibold text-neutral-700 uppercase tracking-wider mb-2"
+                >Глобальный поиск</label
+            >
+            <input
+                type="text"
+                bind:value={searchQuery}
+                placeholder="ID, ФИО, email, телефон, адрес, канал..."
+                class="w-full px-3 py-2 border border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 focus:ring-1 focus:ring-neutral-900"
+            />
+        </div>
+
+        <div>
+            <label
+                class="block text-xs font-semibold text-neutral-700 uppercase tracking-wider mb-2"
+                >Тип клиента</label
+            >
+            <select
+                bind:value={filterType}
+                class="w-full px-3 py-2 border border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 focus:ring-1 focus:ring-neutral-900"
+            >
+                <option value="Все">Все типы</option>
+                <option value="Физ">Физ. лицо</option>
+                <option value="Юр">Юр. лицо</option>
+                <option value="Поставщик">Поставщик</option>
+                <option value="Сотрудник">Сотрудник</option>
+                <option value="Контрагент">Контрагент</option>
+                <option value="Покупатель">Покупатель</option>
+            </select>
+        </div>
+
+        <div>
+            <label
+                class="block text-xs font-semibold text-neutral-700 uppercase tracking-wider mb-2"
+                >Сортировка</label
+            >
+            <div class="flex gap-2">
+                <select
+                    bind:value={sortBy}
+                    class="flex-1 px-3 py-2 border border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 focus:ring-1 focus:ring-neutral-900"
+                >
+                    <option value="name">По имени</option>
+                    <option value="date">По дате</option>
+                    <option value="income">По доходу</option>
+                    <option value="requests">По заявкам</option>
+                </select>
+                <button
+                    onclick={toggleSortOrder}
+                    class="px-4 py-2 border border-neutral-300 hover:bg-neutral-100 transition-colors font-bold"
+                >
+                    {sortOrder === "asc" ? "↑" : "↓"}
+                </button>
+            </div>
+        </div>
+    </div>
+
+    {#if searchQuery || filterType !== "Все"}
+        <div class="mt-3 text-sm text-neutral-600">
+            Найдено: <span class="font-semibold">{resultsCount}</span> из {totalCount}
+        </div>
+    {/if}
+</div>

+ 40 - 0
src/lib/components/client/clientStats.svelte

@@ -0,0 +1,40 @@
+<script lang="ts">
+    import { formatMoney } from "$lib/utils/clientUtils";
+
+    export let stats: {
+        total: number;
+        totalIncome: number;
+        totalRequests: number;
+    };
+</script>
+
+<div class="grid grid-cols-5 gap-4">
+    <div class="bg-white border border-neutral-300 p-4">
+        <div
+            class="text-xs font-semibold text-neutral-600 uppercase tracking-wider mb-1"
+        >
+            Всего клиентов
+        </div>
+        <div class="text-2xl font-bold text-neutral-900">{stats.total}</div>
+    </div>
+    <div class="bg-white border border-neutral-300 p-4">
+        <div
+            class="text-xs font-semibold text-neutral-600 uppercase tracking-wider mb-1"
+        >
+            Всего заявок
+        </div>
+        <div class="text-2xl font-bold text-neutral-900">
+            {stats.totalRequests}
+        </div>
+    </div>
+    <div class="bg-white border border-neutral-300 p-4">
+        <div
+            class="text-xs font-semibold text-neutral-600 uppercase tracking-wider mb-1"
+        >
+            Общий доход
+        </div>
+        <div class="text-2xl font-bold text-green-700">
+            {formatMoney({ amount: stats.totalIncome, currency: "RUB" })}
+        </div>
+    </div>
+</div>

+ 170 - 0
src/lib/components/client/clientTableRow.svelte

@@ -0,0 +1,170 @@
+<script lang="ts">
+    import type { ClientInfo } from "$lib/types/client";
+    import { formatMoney, formatDate } from "$lib/utils/clientUtils";
+
+    interface ComponentProps {
+        client: ClientInfo;
+        isSelected: boolean;
+        contextmenu: (event: MouseEvent, clientId: string) => void;
+        ontoggleselect?: (clientId: string) => void;
+        onviewdetails?: (client: ClientInfo) => void;
+        onedit?: (client: ClientInfo) => void;
+        ondelete?: (clientId: string) => void;
+    }
+
+    let {
+        client,
+        isSelected,
+        contextmenu,
+        ontoggleselect,
+        onviewdetails,
+        onedit,
+        ondelete,
+    }: ComponentProps = $props();
+</script>
+
+<tr
+    class="hover:bg-neutral-50 transition-colors group"
+    oncontextmenu={(e) => {
+        e.preventDefault();
+        contextmenu?.(e, client.id);
+    }}
+>
+    <td class="px-4 py-3">
+        <input
+            type="checkbox"
+            checked={isSelected}
+            onchange={() => ontoggleselect?.(client.id)}
+            class="w-4 h-4 border-2 border-neutral-400"
+        />
+    </td>
+    <td class="px-4 py-3 text-sm font-mono text-neutral-600"
+        >{client.id2 || client.id.slice(0, 8)}</td
+    >
+    <td class="px-4 py-3">
+        <div class="flex gap-1 items-center">
+            {#if client.mark}
+                <span
+                    class="inline-block px-2 py-1 text-xs font-bold bg-amber-100 text-amber-900 border border-amber-400 uppercase"
+                    >{client.mark}</span
+                >
+            {/if}
+        </div>
+    </td>
+    <td class="px-4 py-3">
+        <button
+            onclick={() => onviewdetails?.(client)}
+            class="text-left hover:text-blue-700 transition-colors"
+        >
+            <div class="text-sm font-bold text-neutral-900">
+                {client.full_name}
+            </div>
+            {#if client.birthday}
+                <div class="text-xs text-neutral-500">
+                    ДР: {formatDate(client.birthday)}
+                </div>
+            {/if}
+        </button>
+    </td>
+    <td class="px-4 py-3 text-sm">
+        <div class="group/contact relative">
+            {#if client.phones && client.phones.length > 0}
+                <div class="text-neutral-700 cursor-help font-medium">
+                    {client.phones[0]}
+                    {#if client.phones.length > 1}
+                        <span class="text-neutral-400 text-xs ml-1"
+                            >+{client.phones.length - 1}</span
+                        >
+                    {/if}
+                </div>
+                {#if client.phones.length > 1}
+                    <div
+                        class="absolute left-0 top-full mt-1 bg-white border-2 border-neutral-300 shadow-lg p-3 z-10 hidden group-hover/contact:block min-w-[200px]"
+                    >
+                        <div
+                            class="text-xs font-bold text-neutral-600 uppercase mb-2"
+                        >
+                            Все телефоны:
+                        </div>
+                        {#each client.phones as phone}
+                            <div class="text-sm py-1 font-medium">{phone}</div>
+                        {/each}
+                    </div>
+                {/if}
+            {/if}
+            {#if client.emails && client.emails.length > 0}
+                <div class="text-blue-700 cursor-help font-medium text-xs mt-1">
+                    {client.emails[0]}
+                    {#if client.emails.length > 1}
+                        <span class="text-neutral-400 text-xs ml-1"
+                            >+{client.emails.length - 1}</span
+                        >
+                    {/if}
+                </div>
+                {#if client.emails.length > 1}
+                    <div
+                        class="absolute left-0 top-full mt-1 bg-white border-2 border-neutral-300 shadow-lg p-3 z-10 hidden group-hover/contact:block min-w-[250px]"
+                    >
+                        <div
+                            class="text-xs font-bold text-neutral-600 uppercase mb-2"
+                        >
+                            Все email:
+                        </div>
+                        {#each client.emails as email}
+                            <a
+                                href="mailto:{email}"
+                                class="text-sm py-1 block text-blue-700 hover:text-blue-900"
+                                >{email}</a
+                            >
+                        {/each}
+                    </div>
+                {/if}
+            {/if}
+        </div>
+    </td>
+    <td class="px-4 py-3 text-sm text-neutral-600 max-w-[200px]">
+        {#if client.physical_address}
+            <div class="truncate font-medium" title={client.physical_address}>
+                {client.physical_address}
+            </div>
+        {:else if client.legal_address}
+            <div class="truncate text-neutral-500" title={client.legal_address}>
+                {client.legal_address}
+            </div>
+        {:else}
+            <span class="text-neutral-400">—</span>
+        {/if}
+    </td>
+    <td class="px-4 py-3 text-sm text-neutral-700 font-medium"
+        >{formatDate(client.registration_date)}</td
+    >
+    <td class="px-4 py-3 text-center">
+        <span
+            class="inline-block px-3 py-1 text-sm font-bold bg-neutral-100 border border-neutral-300"
+            >{client.request_count || 0}</span
+        >
+    </td>
+    <td class="px-4 py-3 text-right text-sm font-bold text-green-800"
+        >{formatMoney(client.income)}</td
+    >
+    <td class="px-4 py-3">
+        <div
+            class="flex gap-1 justify-center opacity-0 group-hover:opacity-100 transition-opacity"
+        >
+            <button
+                onclick={() => onedit?.(client)}
+                class="px-3 py-1 text-xs border-2 border-neutral-400 hover:bg-neutral-100 font-bold uppercase"
+                title="Редактировать"
+            >
+                Ред
+            </button>
+            <button
+                onclick={() => ondelete?.(client.id)}
+                class="px-3 py-1 text-xs border-2 border-red-400 text-red-700 hover:bg-red-50 font-bold uppercase"
+                title="Удалить"
+            >
+                Удал
+            </button>
+        </div>
+    </td>
+</tr>

+ 9 - 0
src/lib/components/ui/Card.svelte

@@ -0,0 +1,9 @@
+<script lang="ts">
+  export let title: string;
+  export let description: string;
+</script>
+
+<div class="p-6 bg-white border rounded-lg shadow-md">
+  <h2 class="text-xl font-semibold">{title}</h2>
+  <p class="mt-2 text-gray-600">{description}</p>
+</div>

+ 38 - 0
src/lib/components/ui/ClientTable.svelte

@@ -0,0 +1,38 @@
+<script lang="ts">
+    import { fetchClients } from "$lib/services/clientService";
+    import type { ClientInfo } from "$lib/types/client";
+
+    let items: ClientInfo[] = [];
+</script>
+
+<div class="overflow-x-auto">
+    <table class="table">
+        <thead>
+            <tr>
+                <th><input type="checkbox" class="checkbox" /></th>
+                <th>ID</th>
+                <th>Name</th>
+                <th></th>
+            </tr>
+        </thead>
+        <tbody>
+            {#each items as item}
+                <tr>
+                    <th class="w-0 p-4">
+                        <input type="checkbox" class="checkbox" />
+                    </th>
+                    <td class="w-0 p-4">{item.id}</td>
+                    <td class="w-0 p-4 flex gap-2">
+                        <button class="btn btn-primary w-24"> Edit </button>
+                        <button class="btn btn-error w-24"> Delete </button>
+                    </td>
+                </tr>
+            {/each}
+            {#if items.length === 0}
+                <tr>
+                    <td colspan="4" class="text-center">Список пуст</td>
+                </tr>
+            {/if}
+        </tbody>
+    </table>
+</div>

+ 3 - 0
src/lib/components/ui/Footer.svelte

@@ -0,0 +1,3 @@
+<div class="bg-gray-100 text-black p-4 text-center">
+    <p>Footer &copy; 2025</p>
+</div>

+ 28 - 0
src/lib/components/ui/Form.svelte

@@ -0,0 +1,28 @@
+<script lang="ts">
+  export let name: string = '';
+  export let email: string = '';
+</script>
+
+<form class="space-y-4 p-6 bg-white rounded-lg shadow-md">
+  <div>
+    <label for="name" class="block text-sm font-medium text-gray-700">Name</label>
+    <input
+      id="name"
+      type="text"
+      bind:value={name}
+      class="mt-1 block w-full p-2 border rounded-md focus:ring focus:ring-blue-300"
+    />
+  </div>
+  <div>
+    <label for="email" class="block text-sm font-medium text-gray-700">Email</label>
+    <input
+      id="email"
+      type="email"
+      bind:value={email}
+      class="mt-1 block w-full p-2 border rounded-md focus:ring focus:ring-blue-300"
+    />
+  </div>
+  <button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600">
+    Submit
+  </button>
+</form>

+ 34 - 0
src/lib/components/ui/List.svelte

@@ -0,0 +1,34 @@
+<script lang="ts">
+    export let items: string[] = ["Item 1", "Item 2", "Item 3"];
+</script>
+
+<ul class="list bg-base-100 rounded-box shadow-md">
+    {#each items as item, idx}
+        <li class="list-row">
+            <div>
+                <div>ID</div>
+                <div class="text-xs uppercase font-semibold opacity-60">
+                    {idx + 1}
+                </div>
+            </div>
+            {item}
+            <button class="btn btn-square btn-ghost">
+                <svg
+                    class="size-[1.2em]"
+                    xmlns="http://www.w3.org/2000/svg"
+                    viewBox="0 0 24 24"
+                    ><g
+                        stroke-linejoin="round"
+                        stroke-linecap="round"
+                        stroke-width="2"
+                        fill="none"
+                        stroke="currentColor"
+                        ><path
+                            d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"
+                        ></path></g
+                    ></svg
+                >
+            </button>
+        </li>
+    {/each}
+</ul>

+ 30 - 0
src/lib/components/ui/Navbar.svelte

@@ -0,0 +1,30 @@
+<script lang="ts">
+    import { page } from "$app/state";
+    import { onMount } from "svelte";
+
+    type Link = { label: string; href: string };
+    let links: Link[] = [];
+
+    onMount(async () => {
+        links = [
+            { label: "Главная", href: "/" },
+            { label: "Клиенты", href: "/clients" },
+            { label: "Товары", href: "/products" },
+            { label: "Звонки", href: "/calls" },
+            { label: "Заказы", href: "/orders" },
+        ];
+    });
+</script>
+
+<nav class="flex justify-center items-center bg-gray-100 p-4">
+    {#each links as link}
+        <a
+            href={link.href}
+            class="px-4 py-2 mx-2 rounded text-black"
+            class:border-b-2={page.url.pathname === link.href}
+            class:border-black={page.url.pathname === link.href}
+        >
+            {link.label}
+        </a>
+    {/each}
+</nav>

+ 31 - 0
src/lib/components/ui/Sidebar.svelte

@@ -0,0 +1,31 @@
+<script lang="ts">
+    import { page } from "$app/state";
+    import { onMount } from "svelte";
+
+    type Link = { label: string; href: string };
+    let links: Link[] = [];
+
+    onMount(async () => {
+        links = [
+            { label: "Главная", href: "/" },
+            { label: "Клиенты", href: "/clients" },
+            { label: "Товары", href: "/products" },
+            { label: "Звонки", href: "/calls" },
+            { label: "Заказы", href: "/orders" },
+        ];
+    });
+</script>
+
+<nav class="flex flex-col w-44 p-4 bg-gray-100 h-screen">
+    {#each links as link}
+        <a
+            href={link.href}
+            class="px-4 py-2 mb-2 rounded font-medium text-black {page.url
+                .pathname === link.href
+                ? 'bg-gray-300 '
+                : ''}"
+        >
+            {link.label}
+        </a>
+    {/each}
+</nav>

+ 62 - 0
src/lib/components/ui/Slider.svelte

@@ -0,0 +1,62 @@
+<script lang="ts">
+    import { onMount } from "svelte";
+    let currentIndex = 0;
+    const images = ["/test/test.png", "/test/test002.jpg"];
+
+    function nextSlide() {
+        currentIndex = (currentIndex + 1) % images.length;
+    }
+
+    function prevSlide() {
+        currentIndex = (currentIndex - 1 + images.length) % images.length;
+    }
+
+    function handleWheel(event: WheelEvent) {
+        // Прокрутка вниз (deltaY > 0) — следующий слайд
+        // Прокрутка вверх (deltaY < 0) — предыдущий слайд
+        if (event.deltaY > 0) {
+            nextSlide();
+        } else if (event.deltaY < 0) {
+            prevSlide();
+        }
+    }
+
+    // Добавляем обработчик события wheel при монтировании компонента
+    onMount(() => {
+        const slider = document.querySelector(".slider-container");
+        if (slider instanceof HTMLElement) {
+            slider.addEventListener("wheel", handleWheel as EventListener);
+        }
+        // Очищаем обработчик при размонтировании
+        return () => {
+            if (slider instanceof HTMLElement) {
+                slider.removeEventListener(
+                    "wheel",
+                    handleWheel as EventListener,
+                );
+            }
+        };
+    });
+</script>
+
+<div class="slider-container relative w-full max-w-2xl mx-auto">
+    <div class="overflow-hidden rounded-lg">
+        <img
+            src={images[currentIndex]}
+            alt="Slide"
+            class="w-full h-64 object-cover"
+        />
+    </div>
+    <button
+        on:click={prevSlide}
+        class="absolute left-0 top-1/2 transform -translate-y-1/2 bg-gray-800 text-white p-2 rounded-r"
+    >
+        ←
+    </button>
+    <button
+        on:click={nextSlide}
+        class="absolute right-0 top-1/2 transform -translate-y-1/2 bg-gray-800 text-white p-2 rounded-l"
+    >
+        →
+    </button>
+</div>

+ 95 - 0
src/lib/components/ui/Table.svelte

@@ -0,0 +1,95 @@
+<script lang="ts">
+    let items: { id: number; name: string }[] = [
+        { id: 1, name: "Item 1" },
+        { id: 2, name: "Item 2" },
+        { id: 3, name: "Item 3" },
+    ];
+    const API_BASE = "http://api.localhost/v1/client";
+
+    async function handleEdit(id: number, currentName: string) {
+        const newName = prompt("Новое имя:", currentName);
+        if (!newName) return;
+
+        try {
+            const response = await fetch(`${API_BASE}/${id}`, {
+                method: "PUT",
+                headers: { "Content-Type": "application/json" },
+                body: JSON.stringify({ name: newName }),
+            });
+            if (response.ok) {
+                const index = items.findIndex((item) => item.id === id);
+                if (index !== -1) {
+                    items[index].name = newName;
+                    items = items; // Триггер реактивности
+                }
+            } else {
+                throw new Error("Ошибка редактирования");
+            }
+        } catch (error) {
+            console.error(error);
+            alert("Ошибка при редактировании");
+        }
+    }
+
+    async function handleDelete(id: number) {
+        if (!confirm(`Удалить элемент с ID ${id}?`)) return;
+
+        try {
+            const response = await fetch(`${API_BASE}/${id}`, {
+                method: "DELETE",
+                headers: { "Content-Type": "application/json" },
+            });
+            if (response.ok) {
+                items = items.filter((item) => item.id !== id);
+            } else {
+                throw new Error("Ошибка удаления");
+            }
+        } catch (error) {
+            console.error(error);
+            alert("Ошибка при удалении");
+        }
+    }
+</script>
+
+<div class="overflow-x-auto">
+    <table class="table">
+        <thead>
+            <tr>
+                <th><input type="checkbox" class="checkbox" /></th>
+                <th>ID</th>
+                <th>Name</th>
+                <th></th>
+            </tr>
+        </thead>
+        <tbody>
+            {#each items as item}
+                <tr>
+                    <th class="w-0 p-4">
+                        <input type="checkbox" class="checkbox" />
+                    </th>
+                    <td class="w-0 p-4">{item.id}</td>
+                    <td>{item.name}</td>
+                    <td class="w-0 p-4 flex gap-2">
+                        <button
+                            class="btn btn-primary w-24"
+                            on:click={() => handleEdit(item.id, item.name)}
+                        >
+                            Edit
+                        </button>
+                        <button
+                            class="btn btn-error w-24"
+                            on:click={() => handleDelete(item.id)}
+                        >
+                            Delete
+                        </button>
+                    </td>
+                </tr>
+            {/each}
+            {#if items.length === 0}
+                <tr>
+                    <td colspan="4" class="text-center">Список пуст</td>
+                </tr>
+            {/if}
+        </tbody>
+    </table>
+</div>

+ 1 - 0
src/lib/index.ts

@@ -0,0 +1 @@
+// place files you want to import through the `$lib` alias in this folder.

+ 21 - 0
src/lib/services/clientService.ts

@@ -0,0 +1,21 @@
+import { SERVER_API_PORT, SERVER_API_URL } from "$lib/api";
+import type { ClientInfo } from "$lib/types/client";
+
+export async function fetchClients(
+  offset: number = 0,
+  limit: number = 10,
+): Promise<ClientInfo[]> {
+  try {
+    const response = await fetch(
+      `${SERVER_API_URL}${SERVER_API_PORT}/v1/clients?offset=${offset}&limit=${limit}`,
+    );
+    if (!response.ok) {
+      throw new Error(`HTTP error! status: ${response.status}`);
+    }
+    const clients: ClientInfo[] = await response.json();
+    return clients;
+  } catch (error) {
+    console.error("Error fetching clients:", error);
+    throw error;
+  }
+}

+ 32 - 0
src/lib/types/client.ts

@@ -0,0 +1,32 @@
+export interface Money {
+  amount: number;
+  currency: string;
+}
+
+export enum ClientRole {
+  Individual = "Физ",
+  Legal = "Юр",
+  Supplier = "Поставщик",
+  Employee = "Сотрудник",
+  Contractor = "Контрагент",
+  Customer = "Покупатель",
+}
+
+export interface ClientInfo {
+  id: string;
+  id2: string;
+  mark: string;
+  full_name: string;
+  roles: ClientRole[];
+  phones: string[];
+  emails: string[];
+  legal_address: string;
+  physical_address: string;
+  registration_date: string;
+  ad_channel: string;
+  reg_data: Record<string, string>;
+  note: string;
+  request_count: number;
+  birthday: string;
+  income: Money;
+}

+ 127 - 0
src/lib/utils/clientUtils.ts

@@ -0,0 +1,127 @@
+import type { ClientInfo } from "$lib/types/client";
+import { ClientRole } from "$lib/types/client";
+
+export function formatMoney(
+  money: { amount: number; currency: string } | null,
+): string {
+  if (!money || !money.currency) return "—";
+  try {
+    return new Intl.NumberFormat("ru-RU", {
+      style: "currency",
+      currency: money.currency,
+    }).format(money.amount);
+  } catch {
+    return `${money.amount} ${money.currency}`;
+  }
+}
+
+export function formatDate(date: string): string {
+  if (!date) return "—";
+  return new Date(date).toLocaleDateString("ru-RU");
+}
+
+export function getTypeColor(type: ClientRole): string {
+  const colors: Record<ClientRole, string> = {
+    Физ: "bg-blue-100 text-blue-900 border-blue-300",
+    Юр: "bg-purple-100 text-purple-900 border-purple-300",
+    Поставщик: "bg-green-100 text-green-900 border-green-300",
+    Сотрудник: "bg-orange-100 text-orange-900 border-orange-300",
+    Контрагент: "bg-red-100 text-red-900 border-red-300",
+    Покупатель: "bg-teal-100 text-teal-900 border-teal-300",
+  };
+  return colors[type];
+}
+
+export function filterClients(
+  clients: ClientInfo[],
+  searchQuery: string,
+  filterRole: ClientRole | "Все",
+): ClientInfo[] {
+  return clients.filter((client) => {
+    if (!searchQuery && filterRole === "Все") {
+      return true;
+    }
+
+    const query = searchQuery.toLowerCase();
+    const matchesSearch =
+      !searchQuery ||
+      client.id.toLowerCase().includes(query) ||
+      client.id2?.toLowerCase().includes(query) ||
+      client.full_name.toLowerCase().includes(query) ||
+      client.emails?.some((e) => e.toLowerCase().includes(query)) ||
+      client.phones?.some((p) => p.toLowerCase().includes(query)) ||
+      client.physical_address?.toLowerCase().includes(query) ||
+      client.legal_address?.toLowerCase().includes(query) ||
+      client.ad_channel?.toLowerCase().includes(query) ||
+      client.note?.toLowerCase().includes(query) ||
+      client.mark?.toLowerCase().includes(query);
+
+    const matchesType = filterRole === "Все";
+    return matchesSearch && matchesType;
+  });
+}
+
+export function sortClients(
+  clients: ClientInfo[],
+  sortBy: "name" | "date" | "income" | "requests",
+  sortOrder: "asc" | "desc",
+): ClientInfo[] {
+  return [...clients].sort((a, b) => {
+    let comparison = 0;
+    switch (sortBy) {
+      case "name":
+        comparison = a.full_name.localeCompare(b.full_name);
+        break;
+      case "date":
+        comparison =
+          new Date(a.registration_date).getTime() -
+          new Date(b.registration_date).getTime();
+        break;
+      case "income":
+        comparison = (a.income?.amount || 0) - (b.income?.amount || 0);
+        break;
+      case "requests":
+        comparison = (a.request_count || 0) - (b.request_count || 0);
+        break;
+    }
+    return sortOrder === "asc" ? comparison : -comparison;
+  });
+}
+
+export function calculateStats(clients: ClientInfo[]) {
+  return {
+    total: clients.length,
+    totalIncome: clients.reduce((sum, c) => sum + (c.income?.amount || 0), 0),
+    totalRequests: clients.reduce((sum, c) => sum + (c.request_count || 0), 0),
+  };
+}
+
+export function createEmptyClient(): ClientInfo {
+  return {
+    id: crypto.randomUUID(),
+    id2: "",
+    mark: "",
+    full_name: "",
+    roles: [ClientRole.Individual],
+    phones: [""],
+    emails: [""],
+    legal_address: "",
+    physical_address: "",
+    registration_date: new Date().toISOString().split("T")[0],
+    ad_channel: "",
+    reg_data: {},
+    note: "",
+    request_count: 0,
+    birthday: "",
+    income: { amount: 0, currency: "RUB" },
+  };
+}
+
+export function ensureClientFields(client: ClientInfo): ClientInfo {
+  return {
+    ...client,
+    reg_data: client.reg_data || {},
+    emails: client.emails || [],
+    phones: client.phones?.length > 0 ? client.phones : [""],
+  };
+}

+ 24 - 0
src/routes/+layout.svelte

@@ -0,0 +1,24 @@
+<script lang="ts">
+    import { page } from "$app/state";
+    import "../app.css";
+    import Sidebar from "$lib/components/ui/Sidebar.svelte";
+    import Navbar from "$lib/components/ui/Navbar.svelte";
+    import Footer from "$lib/components/ui/Footer.svelte";
+
+    let { children } = $props();
+</script>
+
+<div class="min-h-screen flex flex-col gap-1 p-1">
+    <!-- <Navbar /> -->
+    <!-- Main content area -->
+    <div class="flex flex-1 overflow-hidden gap-1">
+        <!-- <Sidebar /> -->
+        <!-- Page content -->
+        <main class="flex-1 p-4 overflow-auto">
+            <!-- <h1>{page.url.pathname}</h1> -->
+
+            {@render children()}
+        </main>
+    </div>
+    <!-- <Footer /> -->
+</div>

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

@@ -0,0 +1 @@
+<h1>Main</h1>

+ 1 - 0
src/routes/calls/+page.svelte

@@ -0,0 +1 @@
+<h1>Calls</h1>

+ 335 - 0
src/routes/client/test/+page.svelte

@@ -0,0 +1,335 @@
+<script lang="ts">
+    import type { PageData } from "./$types";
+    import type { ClientInfo, ClientRole } from "$lib/types/client";
+    import {
+        filterClients,
+        sortClients,
+        calculateStats,
+        createEmptyClient,
+        ensureClientFields,
+    } from "$lib/utils/clientUtils";
+    import ClientStats from "$lib/components/client/clientStats.svelte";
+    import ClientTableRow from "$lib/components/client/clientTableRow.svelte";
+    import ClientFilters from "$lib/components/client/clientFilters.svelte";
+
+    export let data: PageData;
+
+    let clients: ClientInfo[] = data?.clients || [];
+    let filterRole: ClientRole | "Все" = "Все";
+    let searchQuery = "";
+    let sortBy: "name" | "date" | "income" | "requests" = "name";
+    let sortOrder: "asc" | "desc" = "asc";
+    let selectedClients = new Set<string>();
+    let contextMenu: { x: number; y: number; clientId: string } | null = null;
+
+    let showEditModal = false;
+    let showCreateModal = false;
+    let showDetailsModal = false;
+    let showActivityModal = false;
+    let editingClient: ClientInfo | null = null;
+    let selectedClient: ClientInfo | null = null;
+
+    $: stats = calculateStats(clients);
+    $: filteredAndSorted = sortClients(
+        filterClients(clients, searchQuery, filterRole),
+        sortBy,
+        sortOrder,
+    );
+
+    function handleContextMenu(event: MouseEvent, clientId: string) {
+        event.preventDefault(); // Предотвращаем стандартное контекстное меню
+
+        contextMenu = {
+            x: event.clientX, // Берем координаты напрямую из MouseEvent
+            y: event.clientY,
+            clientId: clientId, // Используем clientId напрямую
+        };
+    }
+
+    function closeContextMenu() {
+        contextMenu = null;
+    }
+
+    function toggleSelectAll() {
+        if (selectedClients.size === filteredAndSorted.length) {
+            selectedClients.clear();
+        } else {
+            selectedClients = new Set(filteredAndSorted.map((c) => c.id));
+        }
+        selectedClients = selectedClients;
+    }
+
+    function toggleSelect(id: string) {
+        if (selectedClients.has(id)) {
+            selectedClients.delete(id);
+        } else {
+            selectedClients.add(id);
+        }
+        selectedClients = selectedClients;
+    }
+
+    function openEditModal(client: ClientInfo) {
+        editingClient = ensureClientFields(structuredClone(client));
+        showEditModal = true;
+        closeContextMenu();
+    }
+
+    function openCreateModal() {
+        editingClient = createEmptyClient();
+        showCreateModal = true;
+    }
+
+    function saveClient(updatedClient: ClientInfo) {
+        const index = clients.findIndex((c) => c.id === updatedClient.id);
+        if (index !== -1) {
+            clients[index] = updatedClient;
+        } else {
+            clients = [...clients, updatedClient];
+        }
+        showEditModal = false;
+        showCreateModal = false;
+        editingClient = null;
+    }
+
+    function handleDelete(id: string) {
+        if (confirm("Удалить клиента?")) {
+            clients = clients.filter((c) => c.id !== id);
+        }
+        closeContextMenu();
+    }
+
+    function deleteSelected() {
+        if (confirm(`Удалить выбранных клиентов (${selectedClients.size})?`)) {
+            clients = clients.filter((c) => !selectedClients.has(c.id));
+            selectedClients.clear();
+            selectedClients = selectedClients;
+        }
+    }
+
+    function viewDetails(client: ClientInfo) {
+        selectedClient = client;
+        showDetailsModal = true;
+        closeContextMenu();
+    }
+</script>
+
+<ClientStats {stats} />
+
+<!-- Filters & Search -->
+<div class="mb-6 bg-white border border-neutral-300 p-4">
+    <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
+        <div>
+            <label
+                class="block text-xs font-semibold text-neutral-700 uppercase tracking-wider mb-2"
+                >Глобальный поиск</label
+            >
+            <input
+                type="text"
+                bind:value={searchQuery}
+                placeholder="ID, ФИО, email, телефон, адрес, канал..."
+                class="w-full px-3 py-2 border border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 focus:ring-1 focus:ring-neutral-900"
+            />
+        </div>
+
+        <div>
+            <label
+                class="block text-xs font-semibold text-neutral-700 uppercase tracking-wider mb-2"
+                >Тип клиента</label
+            >
+            <select
+                bind:value={filterRole}
+                class="w-full px-3 py-2 border border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 focus:ring-1 focus:ring-neutral-900"
+            >
+                <option value="Все">Все типы</option>
+                <option value="Физ">Физ. лицо</option>
+                <option value="Юр">Юр. лицо</option>
+                <option value="Поставщик">Поставщик</option>
+                <option value="Сотрудник">Сотрудник</option>
+                <option value="Контрагент">Контрагент</option>
+                <option value="Покупатель">Покупатель</option>
+            </select>
+        </div>
+
+        <div>
+            <label
+                class="block text-xs font-semibold text-neutral-700 uppercase tracking-wider mb-2"
+                >Сортировка</label
+            >
+            <div class="flex gap-2">
+                <select
+                    bind:value={sortBy}
+                    class="flex-1 px-3 py-2 border border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 focus:ring-1 focus:ring-neutral-900"
+                >
+                    <option value="name">По имени</option>
+                    <option value="date">По дате</option>
+                    <option value="income">По доходу</option>
+                    <option value="requests">По заявкам</option>
+                </select>
+                <button
+                    onclick={() =>
+                        (sortOrder = sortOrder === "asc" ? "desc" : "asc")}
+                    class="px-4 py-2 border border-neutral-300 hover:bg-neutral-100 transition-colors font-bold"
+                >
+                    {sortOrder === "asc" ? "↑" : "↓"}
+                </button>
+            </div>
+        </div>
+    </div>
+
+    {#if searchQuery || filterRole !== "Все"}
+        <div class="mt-3 text-sm text-neutral-600">
+            Найдено: <span class="font-semibold"
+                >{filteredAndSorted.length}</span
+            >
+            из {clients.length}
+        </div>
+    {/if}
+</div>
+
+<svelte:window on:click={closeContextMenu} />
+
+{#if filteredAndSorted.length > 0}
+    <div class="bg-white border border-neutral-300 shadow-sm overflow-x-auto">
+        <table class="w-full">
+            <thead class="bg-neutral-100 border-b-2 border-neutral-300">
+                <tr>
+                    <th class="px-4 py-3 w-10">
+                        <input
+                            type="checkbox"
+                            checked={selectedClients.size ===
+                                filteredAndSorted.length &&
+                                filteredAndSorted.length > 0}
+                            onchange={toggleSelectAll}
+                            class="w-4 h-4 border-2 border-neutral-400"
+                        />
+                    </th>
+                    <th
+                        class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                        >ID</th
+                    >
+                    <th
+                        class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                        >Статус</th
+                    >
+                    <th
+                        class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                        >ФИО</th
+                    >
+                    <th
+                        class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                        >Тип</th
+                    >
+                    <th
+                        class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                        >Контакты</th
+                    >
+                    <th
+                        class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                        >Адрес</th
+                    >
+                    <th
+                        class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                        >Регистрация</th
+                    >
+                    <th
+                        class="px-4 py-3 text-center text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                        >Заявки</th
+                    >
+                    <th
+                        class="px-4 py-3 text-right text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                        >Доход</th
+                    >
+                    <th
+                        class="px-4 py-3 text-center text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                        >Действия</th
+                    >
+                </tr>
+            </thead>
+            <tbody class="divide-y divide-neutral-200">
+                {#each filteredAndSorted as client (client.id)}
+                    <ClientTableRow
+                        {client}
+                        isSelected={selectedClients.has(client.id)}
+                        contextmenu={handleContextMenu}
+                        ontoggleselect={(clientId: string) =>
+                            toggleSelect(clientId)}
+                        onviewdetails={(client: ClientInfo) =>
+                            viewDetails(client)}
+                        onedit={(client: ClientInfo) => openEditModal(client)}
+                        ondelete={(client: string) => handleDelete(client)}
+                    />
+                {/each}
+            </tbody>
+        </table>
+    </div>
+{:else}
+    <div class="bg-white border-2 border-neutral-300 p-12 text-center">
+        <svg
+            class="w-16 h-16 mx-auto text-neutral-400 mb-4"
+            fill="none"
+            viewBox="0 0 24 24"
+            stroke="currentColor"
+            stroke-width="2"
+        >
+            <path
+                stroke-linecap="round"
+                stroke-linejoin="round"
+                d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
+            />
+        </svg>
+        <h2 class="text-lg font-bold text-neutral-900 mb-2 uppercase">
+            Нет результатов
+        </h2>
+        <p class="text-sm text-neutral-600">
+            Попробуйте изменить параметры поиска или фильтрации
+        </p>
+    </div>
+{/if}
+
+<!-- Context Menu -->
+{#if contextMenu}
+    <div
+        class="fixed bg-white border-2 border-neutral-300 shadow-lg z-50 py-1 min-w-[200px]"
+        style="left: {contextMenu.x}px; top: {contextMenu.y}px;"
+    >
+        <button
+            onclick={() => {
+                const client = clients.find(
+                    (c) => c.id === contextMenu?.clientId,
+                );
+                if (client) viewDetails(client);
+            }}
+            class="w-full px-4 py-2 text-left text-sm font-semibold hover:bg-neutral-100 flex items-center gap-2 uppercase"
+        >
+            <span>👁</span> Просмотр
+        </button>
+        <button
+            onclick={() => {
+                const client = clients.find(
+                    (c) => c.id === contextMenu?.clientId,
+                );
+                if (client) openEditModal(client);
+            }}
+            class="w-full px-4 py-2 text-left text-sm font-semibold hover:bg-neutral-100 flex items-center gap-2 uppercase"
+        >
+            <span>✎</span> Редактировать
+        </button>
+        <button
+            onclick={() => contextMenu && handleDelete(contextMenu.clientId)}
+            class="w-full px-4 py-2 text-left text-sm font-semibold hover:bg-red-50 text-red-700 flex items-center gap-2 uppercase"
+        >
+            <span>✕</span> Удалить
+        </button>
+        <hr class="my-1 border-neutral-300" />
+        <button
+            onclick={() => {
+                if (contextMenu)
+                    navigator.clipboard.writeText(contextMenu.clientId);
+                closeContextMenu();
+            }}
+            class="w-full px-4 py-2 text-left text-sm font-semibold hover:bg-neutral-100 flex items-center gap-2 uppercase"
+        >
+            <span>📋</span> Копировать ID
+        </button>
+    </div>
+{/if}

+ 21 - 0
src/routes/client/test/+page.ts

@@ -0,0 +1,21 @@
+import type { PageLoad } from "./$types";
+
+import { SERVER_API_PORT, SERVER_API_URL } from "$lib/api";
+import type { ClientInfo } from "$lib/types/client";
+
+export const load: PageLoad = async ({ fetch }) => {
+  const url = `${SERVER_API_URL}${SERVER_API_PORT}/v1/clients?offset=0&limit=-1`;
+  const res = await fetch(url);
+
+  if (!res.ok) {
+    console.error("Fetch error:", res.status);
+    return { clients: [] };
+  }
+
+  const clients: ClientInfo[] = await res.json();
+  console.log("Loaded clients:", clients);
+
+  return {
+    clients,
+  };
+};

+ 1853 - 0
src/routes/clients/+page.svelte

@@ -0,0 +1,1853 @@
+<script lang="ts">
+    import type { PageData } from "./$types";
+    import type { ClientInfo } from "$lib/types/client";
+    import { ClientRole } from "$lib/types/client";
+
+    export let data: PageData;
+
+    let clients: ClientInfo[] = data.clients;
+    let searchQuery = "";
+    let filterType: ClientRole | "Все" = "Все";
+    let sortBy: "name" | "date" | "income" | "requests" = "name";
+    let sortOrder: "asc" | "desc" = "asc";
+    let selectedClients = new Set<string>();
+    let contextMenu: { x: number; y: number; clientId: string } | null = null;
+
+    // Модальные окна
+    let showEditModal = false;
+    let showCreateModal = false;
+    let showDetailsModal = false;
+    let showActivityModal = false;
+    let editingClient: ClientInfo | null = null;
+    let selectedClient: ClientInfo | null = null;
+    let newRegDataKey = "";
+    let newRegDataValue = "";
+
+    // Статистика
+    $: stats = {
+        total: clients.length,
+        totalIncome: clients.reduce(
+            (sum, c) => sum + (c.income?.amount || 0),
+            0,
+        ),
+        totalRequests: clients.reduce(
+            (sum, c) => sum + (c.request_count || 0),
+            0,
+        ),
+    };
+
+    // Расширенная фильтрация
+    $: filteredClients = clients
+        .filter((client) => {
+            if (!searchQuery) {
+                return filterType === "Все";
+            }
+
+            const query = searchQuery.toLowerCase();
+            const matchesSearch =
+                client.id.toLowerCase().includes(query) ||
+                client.id2?.toLowerCase().includes(query) ||
+                client.full_name.toLowerCase().includes(query) ||
+                client.emails?.some((e) => e.toLowerCase().includes(query)) ||
+                client.phones?.some((p) => p.toLowerCase().includes(query)) ||
+                client.physical_address?.toLowerCase().includes(query) ||
+                client.legal_address?.toLowerCase().includes(query) ||
+                client.ad_channel?.toLowerCase().includes(query) ||
+                client.note?.toLowerCase().includes(query) ||
+                client.mark?.toLowerCase().includes(query);
+
+            const matchesType = filterType === "Все";
+            return matchesSearch && matchesType;
+        })
+        .sort((a, b) => {
+            let comparison = 0;
+            switch (sortBy) {
+                case "name":
+                    comparison = a.full_name.localeCompare(b.full_name);
+                    break;
+                case "date":
+                    comparison =
+                        new Date(a.registration_date).getTime() -
+                        new Date(b.registration_date).getTime();
+                    break;
+                case "income":
+                    comparison =
+                        (a.income?.amount || 0) - (b.income?.amount || 0);
+                    break;
+                case "requests":
+                    comparison =
+                        (a.request_count || 0) - (b.request_count || 0);
+                    break;
+            }
+            return sortOrder === "asc" ? comparison : -comparison;
+        });
+
+    function formatMoney(
+        money: { amount: number; currency: string } | null,
+    ): string {
+        if (!money || !money.currency) return "—";
+        try {
+            return new Intl.NumberFormat("ru-RU", {
+                style: "currency",
+                currency: money.currency,
+            }).format(money.amount);
+        } catch {
+            return `${money.amount} ${money.currency}`;
+        }
+    }
+
+    function formatDate(date: string): string {
+        if (!date) return "—";
+        return new Date(date).toLocaleDateString("ru-RU");
+    }
+
+    function handleContextMenu(e: MouseEvent, clientId: string) {
+        e.preventDefault();
+        contextMenu = { x: e.clientX, y: e.clientY, clientId };
+    }
+
+    function closeContextMenu() {
+        contextMenu = null;
+    }
+
+    function toggleSort(column: typeof sortBy) {
+        if (sortBy === column) {
+            sortOrder = sortOrder === "asc" ? "desc" : "asc";
+        } else {
+            sortBy = column;
+            sortOrder = "asc";
+        }
+    }
+
+    function toggleSelectAll() {
+        if (selectedClients.size === filteredClients.length) {
+            selectedClients.clear();
+        } else {
+            selectedClients = new Set(filteredClients.map((c) => c.id));
+        }
+        selectedClients = selectedClients;
+    }
+
+    function toggleSelect(id: string) {
+        if (selectedClients.has(id)) {
+            selectedClients.delete(id);
+        } else {
+            selectedClients.add(id);
+        }
+        selectedClients = selectedClients;
+    }
+
+    function openEditModal(client: ClientInfo) {
+        editingClient = structuredClone(client);
+        // Ensure reg_data exists
+        if (!editingClient.reg_data) {
+            editingClient.reg_data = {};
+        }
+        // Ensure emails array exists
+        if (!editingClient.emails) {
+            editingClient.emails = [];
+        }
+        // Ensure phones array exists
+        if (!editingClient.phones || editingClient.phones.length === 0) {
+            editingClient.phones = [""];
+        }
+        showEditModal = true;
+        closeContextMenu();
+    }
+
+    function openCreateModal() {
+        editingClient = {
+            id: crypto.randomUUID(),
+            id2: "",
+            mark: "",
+            full_name: "",
+            roles: [ClientRole.Individual],
+            phones: [""],
+            emails: [""],
+            legal_address: "",
+            physical_address: "",
+            registration_date: new Date().toISOString().split("T")[0],
+            ad_channel: "",
+            reg_data: {},
+            note: "",
+            request_count: 0,
+            birthday: "",
+            income: { amount: 0, currency: "RUB" },
+        };
+        showCreateModal = true;
+    }
+
+    function saveClient() {
+        if (!editingClient) return;
+
+        const index = clients.findIndex((c) => c.id === editingClient.id);
+        if (index !== -1) {
+            clients[index] = editingClient;
+        } else {
+            clients = [...clients, editingClient];
+        }
+
+        showEditModal = false;
+        showCreateModal = false;
+        editingClient = null;
+    }
+
+    function handleDelete(id: string) {
+        if (confirm("Удалить клиента?")) {
+            clients = clients.filter((c) => c.id !== id);
+        }
+        closeContextMenu();
+    }
+
+    function deleteSelected() {
+        if (confirm(`Удалить выбранных клиентов (${selectedClients.size})?`)) {
+            clients = clients.filter((c) => !selectedClients.has(c.id));
+            selectedClients.clear();
+            selectedClients = selectedClients;
+        }
+    }
+
+    function viewDetails(client: ClientInfo) {
+        selectedClient = client;
+        showDetailsModal = true;
+        closeContextMenu();
+    }
+
+    function addPhone() {
+        if (editingClient) {
+            editingClient.phones = [...editingClient.phones, ""];
+        }
+    }
+
+    function removePhone(index: number) {
+        if (editingClient) {
+            editingClient.phones = editingClient.phones.filter(
+                (_, i) => i !== index,
+            );
+        }
+    }
+
+    function addEmail() {
+        if (editingClient) {
+            editingClient.emails = [...editingClient.emails, ""];
+        }
+    }
+
+    function removeEmail(index: number) {
+        if (editingClient) {
+            editingClient.emails = editingClient.emails.filter(
+                (_, i) => i !== index,
+            );
+        }
+    }
+
+    function addRegData() {
+        if (editingClient && newRegDataKey && newRegDataValue) {
+            editingClient.reg_data = {
+                ...editingClient.reg_data,
+                [newRegDataKey]: newRegDataValue,
+            };
+            editingClient = editingClient; // Trigger reactivity
+            newRegDataKey = "";
+            newRegDataValue = "";
+        }
+    }
+
+    function removeRegData(key: string) {
+        if (editingClient) {
+            const { [key]: _, ...rest } = editingClient.reg_data;
+            editingClient.reg_data = rest;
+            editingClient = editingClient; // Trigger reactivity
+        }
+    }
+
+    function getTypeColor(type: ClientRole): string {
+        const colors: Record<ClientRole, string> = {
+            Физ: "bg-blue-100 text-blue-900 border-blue-300",
+            Юр: "bg-purple-100 text-purple-900 border-purple-300",
+            Поставщик: "bg-green-100 text-green-900 border-green-300",
+            Сотрудник: "bg-orange-100 text-orange-900 border-orange-300",
+            Контрагент: "bg-red-100 text-red-900 border-red-300",
+            Покупатель: "bg-teal-100 text-teal-900 border-teal-300",
+        };
+        return colors[type];
+    }
+
+    function exportToCSV() {
+        const headers = [
+            "ID",
+            "ФИО",
+            "Тип",
+            "Email",
+            "Телефоны",
+            "Адрес",
+            "Дата регистрации",
+            "Заявки",
+            "Доход",
+        ];
+        const rows = filteredClients.map((c) => [
+            c.id2 || c.id,
+            c.full_name,
+            c.roles?.join("; ") || "",
+            c.emails?.join("; ") || "",
+            c.phones.join("; ") || "",
+            c.physical_address || c.legal_address || "",
+            formatDate(c.registration_date),
+            c.request_count || 0,
+            c.income?.amount || 0,
+        ]);
+
+        const csv = [headers, ...rows]
+            .map((row) => row.map((cell) => `"${cell}"`).join(","))
+            .join("\n");
+        const blob = new Blob([csv], { type: "text/csv" });
+        const url = URL.createObjectURL(blob);
+        const a = document.createElement("a");
+        a.href = url;
+        a.download = `clients_${new Date().toISOString().split("T")[0]}.csv`;
+        a.click();
+    }
+</script>
+
+<svelte:window on:click={closeContextMenu} />
+
+<div class="min-h-screen bg-neutral-50">
+    <div class="max-w-[1800px] mx-auto px-8 py-8">
+        <!-- Header with Stats -->
+        <div class="mb-6 border-b border-neutral-300 pb-6">
+            <div class="flex items-center justify-between mb-4">
+                <h1
+                    class="text-2xl font-bold text-neutral-900 tracking-tight uppercase"
+                >
+                    Система управления клиентами
+                </h1>
+                <div class="flex gap-3">
+                    {#if selectedClients.size > 0}
+                        <button
+                            onclick={deleteSelected}
+                            class="px-4 py-2 bg-red-600 text-white text-sm font-semibold uppercase tracking-wide hover:bg-red-700 transition-colors border border-red-700"
+                        >
+                            Удалить ({selectedClients.size})
+                        </button>
+                    {/if}
+                    <button
+                        onclick={openCreateModal}
+                        class="px-4 py-2 bg-neutral-900 text-white text-sm font-semibold uppercase tracking-wide hover:bg-neutral-800 transition-colors border border-neutral-900"
+                    >
+                        + Новый клиент
+                    </button>
+                </div>
+            </div>
+
+            <!-- Stats Cards -->
+            <div class="grid grid-cols-5 gap-4">
+                <div class="bg-white border border-neutral-300 p-4">
+                    <div
+                        class="text-xs font-semibold text-neutral-600 uppercase tracking-wider mb-1"
+                    >
+                        Всего клиентов
+                    </div>
+                    <div class="text-2xl font-bold text-neutral-900">
+                        {stats.total}
+                    </div>
+                </div>
+                <div class="bg-white border border-neutral-300 p-4">
+                    <div
+                        class="text-xs font-semibold text-neutral-600 uppercase tracking-wider mb-1"
+                    >
+                        Физ. лица
+                    </div>
+                    <div class="text-2xl font-bold text-blue-700">
+                        <!-- {stats.physical} -->
+                    </div>
+                </div>
+                <div class="bg-white border border-neutral-300 p-4">
+                    <div
+                        class="text-xs font-semibold text-neutral-600 uppercase tracking-wider mb-1"
+                    >
+                        Юр. лица
+                    </div>
+                    <div class="text-2xl font-bold text-purple-700">
+                        <!-- {stats.legal} -->
+                    </div>
+                </div>
+                <div class="bg-white border border-neutral-300 p-4">
+                    <div
+                        class="text-xs font-semibold text-neutral-600 uppercase tracking-wider mb-1"
+                    >
+                        Контрагенты
+                    </div>
+                    <div class="text-2xl font-bold text-emerald-700">
+                        <!-- {clients.filter((c) => c.contractor).length} -->
+                    </div>
+                </div>
+                <div class="bg-white border border-neutral-300 p-4">
+                    <div
+                        class="text-xs font-semibold text-neutral-600 uppercase tracking-wider mb-1"
+                    >
+                        Общий доход
+                    </div>
+                    <div class="text-xl font-bold text-green-700">
+                        {formatMoney({
+                            amount: stats.totalIncome,
+                            currency: "RUB",
+                        })}
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- Filters & Search -->
+        <div class="mb-6 bg-white border border-neutral-300 p-4">
+            <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
+                <div>
+                    <label
+                        class="block text-xs font-semibold text-neutral-700 uppercase tracking-wider mb-2"
+                        >Глобальный поиск</label
+                    >
+                    <input
+                        type="text"
+                        bind:value={searchQuery}
+                        placeholder="ID, ФИО, email, телефон, адрес, канал..."
+                        class="w-full px-3 py-2 border border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 focus:ring-1 focus:ring-neutral-900"
+                    />
+                </div>
+
+                <div>
+                    <label
+                        class="block text-xs font-semibold text-neutral-700 uppercase tracking-wider mb-2"
+                        >Тип клиента</label
+                    >
+                    <select
+                        bind:value={filterType}
+                        class="w-full px-3 py-2 border border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 focus:ring-1 focus:ring-neutral-900"
+                    >
+                        <option value="Все">Все типы</option>
+                        <option value="Физ">Физ. лицо</option>
+                        <option value="Юр">Юр. лицо</option>
+                        <option value="Поставщик">Поставщик</option>
+                        <option value="Сотрудник">Сотрудник</option>
+                        <option value="Контрагент">Контрагент</option>
+                        <option value="Покупатель">Покупатель</option>
+                    </select>
+                </div>
+
+                <div>
+                    <label
+                        class="block text-xs font-semibold text-neutral-700 uppercase tracking-wider mb-2"
+                        >Сортировка</label
+                    >
+                    <div class="flex gap-2">
+                        <select
+                            bind:value={sortBy}
+                            class="flex-1 px-3 py-2 border border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 focus:ring-1 focus:ring-neutral-900"
+                        >
+                            <option value="name">По имени</option>
+                            <option value="date">По дате</option>
+                            <option value="income">По доходу</option>
+                            <option value="requests">По заявкам</option>
+                        </select>
+                        <button
+                            onclick={() =>
+                                (sortOrder =
+                                    sortOrder === "asc" ? "desc" : "asc")}
+                            class="px-4 py-2 border border-neutral-300 hover:bg-neutral-100 transition-colors font-bold"
+                        >
+                            {sortOrder === "asc" ? "↑" : "↓"}
+                        </button>
+                    </div>
+                </div>
+            </div>
+
+            {#if searchQuery || filterType !== "Все"}
+                <div class="mt-3 text-sm text-neutral-600">
+                    Найдено: <span class="font-semibold"
+                        >{filteredClients.length}</span
+                    >
+                    из {clients.length}
+                </div>
+            {/if}
+        </div>
+
+        {#if filteredClients.length > 0}
+            <div
+                class="bg-white border border-neutral-300 shadow-sm overflow-x-auto"
+            >
+                <table class="w-full">
+                    <thead class="bg-neutral-100 border-b-2 border-neutral-300">
+                        <tr>
+                            <th class="px-4 py-3 w-10">
+                                <input
+                                    type="checkbox"
+                                    checked={selectedClients.size ===
+                                        filteredClients.length &&
+                                        filteredClients.length > 0}
+                                    onchange={toggleSelectAll}
+                                    class="w-4 h-4 border-2 border-neutral-400"
+                                />
+                            </th>
+                            <th
+                                class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                                >ID</th
+                            >
+                            <th
+                                class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                                >Статус</th
+                            >
+                            <th
+                                class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider cursor-pointer hover:bg-neutral-200"
+                                onclick={() => toggleSort("name")}
+                            >
+                                ФИО {sortBy === "name"
+                                    ? sortOrder === "asc"
+                                        ? "↑"
+                                        : "↓"
+                                    : ""}
+                            </th>
+                            <th
+                                class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                                >Тип</th
+                            >
+                            <th
+                                class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                                >Контакты</th
+                            >
+                            <th
+                                class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                                >Адрес</th
+                            >
+                            <th
+                                class="px-4 py-3 text-left text-xs font-bold text-neutral-700 uppercase tracking-wider cursor-pointer hover:bg-neutral-200"
+                                onclick={() => toggleSort("date")}
+                            >
+                                Регистрация {sortBy === "date"
+                                    ? sortOrder === "asc"
+                                        ? "↑"
+                                        : "↓"
+                                    : ""}
+                            </th>
+                            <th
+                                class="px-4 py-3 text-center text-xs font-bold text-neutral-700 uppercase tracking-wider cursor-pointer hover:bg-neutral-200"
+                                onclick={() => toggleSort("requests")}
+                            >
+                                Заявки {sortBy === "requests"
+                                    ? sortOrder === "asc"
+                                        ? "↑"
+                                        : "↓"
+                                    : ""}
+                            </th>
+                            <th
+                                class="px-4 py-3 text-right text-xs font-bold text-neutral-700 uppercase tracking-wider cursor-pointer hover:bg-neutral-200"
+                                onclick={() => toggleSort("income")}
+                            >
+                                Доход {sortBy === "income"
+                                    ? sortOrder === "asc"
+                                        ? "↑"
+                                        : "↓"
+                                    : ""}
+                            </th>
+                            <th
+                                class="px-4 py-3 text-center text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                                >Действия</th
+                            >
+                        </tr>
+                    </thead>
+                    <tbody class="divide-y divide-neutral-200">
+                        {#each filteredClients as client}
+                            <tr
+                                class="hover:bg-neutral-50 transition-colors group"
+                                oncontextmenu={(e) =>
+                                    handleContextMenu(e, client.id)}
+                            >
+                                <td class="px-4 py-3">
+                                    <input
+                                        type="checkbox"
+                                        checked={selectedClients.has(client.id)}
+                                        onchange={() => toggleSelect(client.id)}
+                                        class="w-4 h-4 border-2 border-neutral-400"
+                                    />
+                                </td>
+                                <td
+                                    class="px-4 py-3 text-sm font-mono text-neutral-600"
+                                    >{client.id2 || client.id.slice(0, 8)}</td
+                                >
+                                <td class="px-4 py-3">
+                                    <div class="flex gap-2 items-center">
+                                        <!-- {#if client.contractor}
+                                            <span
+                                                class="inline-block px-2 py-1 text-xs font-bold bg-emerald-100 text-emerald-900 border-2 border-emerald-400 uppercase"
+                                                >Контрагент</span
+                                            >
+                                        {/if} -->
+                                        {#if client.mark}
+                                            <span
+                                                class="inline-block px-2 py-1 text-xs font-bold bg-amber-100 text-amber-900 border-2 border-amber-400 uppercase"
+                                                >{client.mark}</span
+                                            >
+                                        {/if}
+                                    </div>
+                                </td>
+                                <td class="px-4 py-3">
+                                    <button
+                                        onclick={() => viewDetails(client)}
+                                        class="text-left hover:text-blue-700 transition-colors"
+                                    >
+                                        <div
+                                            class="text-sm font-bold text-neutral-900"
+                                        >
+                                            {client.full_name}
+                                        </div>
+                                        {#if client.birthday}
+                                            <div
+                                                class="text-xs text-neutral-500"
+                                            >
+                                                ДР: {formatDate(
+                                                    client.birthday,
+                                                )}
+                                            </div>
+                                        {/if}
+                                    </button>
+                                </td>
+                                <td class="px-4 py-3">
+                                    <!-- <span
+                                        class="inline-block px-2 py-1 text-xs font-bold border {getTypeColor(
+                                            client.type,
+                                        )} uppercase">{client.type}</span
+                                    > -->
+                                </td>
+                                <td class="px-4 py-3 text-sm">
+                                    <div class="group/contact relative">
+                                        {#if client.phones && client.phones.length > 0}
+                                            <div
+                                                class="text-neutral-700 cursor-help font-medium"
+                                            >
+                                                {client.phones[0]}
+                                                {#if client.phones.length > 1}
+                                                    <span
+                                                        class="text-neutral-400 text-xs ml-1"
+                                                        >+{client.phones
+                                                            .length - 1}</span
+                                                    >
+                                                {/if}
+                                            </div>
+                                            {#if client.phones.length > 1}
+                                                <div
+                                                    class="absolute left-0 top-full mt-1 bg-white border-2 border-neutral-300 shadow-lg p-3 z-10 hidden group-hover/contact:block min-w-[200px]"
+                                                >
+                                                    <div
+                                                        class="text-xs font-bold text-neutral-600 uppercase mb-2"
+                                                    >
+                                                        Все телефоны:
+                                                    </div>
+                                                    {#each client.phones as phone}
+                                                        <div
+                                                            class="text-sm py-1 font-medium"
+                                                        >
+                                                            {phone}
+                                                        </div>
+                                                    {/each}
+                                                </div>
+                                            {/if}
+                                        {/if}
+                                        {#if client.emails && client.emails.length > 0}
+                                            <div
+                                                class="text-blue-700 cursor-help font-medium text-xs mt-1"
+                                            >
+                                                {client.emails[0]}
+                                                {#if client.emails.length > 1}
+                                                    <span
+                                                        class="text-neutral-400 text-xs ml-1"
+                                                        >+{client.emails
+                                                            .length - 1}</span
+                                                    >
+                                                {/if}
+                                            </div>
+                                            {#if client.emails.length > 1}
+                                                <div
+                                                    class="absolute left-0 top-full mt-1 bg-white border-2 border-neutral-300 shadow-lg p-3 z-10 hidden group-hover/contact:block min-w-[250px]"
+                                                >
+                                                    <div
+                                                        class="text-xs font-bold text-neutral-600 uppercase mb-2"
+                                                    >
+                                                        Все email:
+                                                    </div>
+                                                    {#each client.emails as email}
+                                                        <a
+                                                            href="mailto:{email}"
+                                                            class="text-sm py-1 block text-blue-700 hover:text-blue-900"
+                                                            >{email}</a
+                                                        >
+                                                    {/each}
+                                                </div>
+                                            {/if}
+                                        {/if}
+                                    </div>
+                                </td>
+                                <td
+                                    class="px-4 py-3 text-sm text-neutral-600 max-w-[200px]"
+                                >
+                                    {#if client.physical_address}
+                                        <div
+                                            class="truncate font-medium"
+                                            title={client.physical_address}
+                                        >
+                                            {client.physical_address}
+                                        </div>
+                                    {:else if client.legal_address}
+                                        <div
+                                            class="truncate text-neutral-500"
+                                            title={client.legal_address}
+                                        >
+                                            {client.legal_address}
+                                        </div>
+                                    {:else}
+                                        <span class="text-neutral-400">—</span>
+                                    {/if}
+                                </td>
+                                <td
+                                    class="px-4 py-3 text-sm text-neutral-700 font-medium"
+                                    >{formatDate(client.registration_date)}</td
+                                >
+                                <td class="px-4 py-3 text-center">
+                                    <span
+                                        class="inline-block px-3 py-1 text-sm font-bold bg-neutral-100 border border-neutral-300"
+                                        >{client.request_count || 0}</span
+                                    >
+                                </td>
+                                <td
+                                    class="px-4 py-3 text-right text-sm font-bold text-green-800"
+                                    >{formatMoney(client.income)}</td
+                                >
+                                <td class="px-4 py-3">
+                                    <div
+                                        class="flex gap-1 justify-center opacity-0 group-hover:opacity-100 transition-opacity"
+                                    >
+                                        <button
+                                            onclick={() =>
+                                                openEditModal(client)}
+                                            class="px-3 py-1 text-xs border-2 border-neutral-400 hover:bg-neutral-100 font-bold uppercase"
+                                            title="Редактировать"
+                                        >
+                                            Ред
+                                        </button>
+                                        <button
+                                            onclick={() =>
+                                                handleDelete(client.id)}
+                                            class="px-3 py-1 text-xs border-2 border-red-400 text-red-700 hover:bg-red-50 font-bold uppercase"
+                                            title="Удалить"
+                                        >
+                                            Удал
+                                        </button>
+                                    </div>
+                                </td>
+                            </tr>
+                        {/each}
+                    </tbody>
+                </table>
+            </div>
+        {:else}
+            <div class="bg-white border-2 border-neutral-300 p-12 text-center">
+                <svg
+                    class="w-16 h-16 mx-auto text-neutral-400 mb-4"
+                    fill="none"
+                    viewBox="0 0 24 24"
+                    stroke="currentColor"
+                    stroke-width="2"
+                >
+                    <path
+                        stroke-linecap="round"
+                        stroke-linejoin="round"
+                        d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
+                    />
+                </svg>
+                <h2 class="text-lg font-bold text-neutral-900 mb-2 uppercase">
+                    Нет результатов
+                </h2>
+                <p class="text-sm text-neutral-600">
+                    Попробуйте изменить параметры поиска или фильтрации
+                </p>
+            </div>
+        {/if}
+    </div>
+</div>
+
+<!-- Context Menu -->
+{#if contextMenu}
+    <div
+        class="fixed bg-white border-2 border-neutral-300 shadow-lg z-50 py-1 min-w-[200px]"
+        style="left: {contextMenu.x}px; top: {contextMenu.y}px;"
+    >
+        <button
+            onclick={() => {
+                const client = clients.find(
+                    (c) => c.id === contextMenu.clientId,
+                );
+                if (client) viewDetails(client);
+            }}
+            class="w-full px-4 py-2 text-left text-sm font-semibold hover:bg-neutral-100 flex items-center gap-2 uppercase"
+        >
+            <span>👁</span> Просмотр
+        </button>
+        <button
+            onclick={() => {
+                const client = clients.find(
+                    (c) => c.id === contextMenu.clientId,
+                );
+                if (client) openEditModal(client);
+            }}
+            class="w-full px-4 py-2 text-left text-sm font-semibold hover:bg-neutral-100 flex items-center gap-2 uppercase"
+        >
+            <span>✎</span> Редактировать
+        </button>
+        <button
+            onclick={() => handleDelete(contextMenu.clientId)}
+            class="w-full px-4 py-2 text-left text-sm font-semibold hover:bg-red-50 text-red-700 flex items-center gap-2 uppercase"
+        >
+            <span>✕</span> Удалить
+        </button>
+        <hr class="my-1 border-neutral-300" />
+        <button
+            onclick={() => {
+                navigator.clipboard.writeText(contextMenu.clientId);
+                closeContextMenu();
+            }}
+            class="w-full px-4 py-2 text-left text-sm font-semibold hover:bg-neutral-100 flex items-center gap-2 uppercase"
+        >
+            <span>📋</span> Копировать ID
+        </button>
+    </div>
+{/if}
+
+<!-- Edit/Create Modal -->
+{#if (showEditModal || showCreateModal) && editingClient}
+    <div class="fixed inset-0 flex items-center justify-center z-50 p-4">
+        <!-- Backdrop with blur -->
+        <div
+            class="absolute inset-0 bg-neutral-900/40 backdrop-blur-sm"
+            onclick={() => {
+                showEditModal = false;
+                showCreateModal = false;
+                editingClient = null;
+            }}
+        ></div>
+
+        <!-- Modal -->
+        <div
+            class="relative bg-white border-2 border-neutral-900 shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-y-auto"
+        >
+            <div
+                class="border-b-2 border-neutral-900 p-6 bg-neutral-100 sticky top-0 z-10"
+            >
+                <h2 class="text-xl font-bold text-neutral-900 uppercase">
+                    {showCreateModal
+                        ? "Создание нового клиента"
+                        : "Редактирование клиента"}
+                </h2>
+            </div>
+
+            <div class="p-6">
+                <div class="grid grid-cols-2 gap-6">
+                    <!-- Основная информация -->
+                    <div class="col-span-2">
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-4 border-b border-neutral-300 pb-2"
+                        >
+                            Основная информация
+                        </h3>
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >ФИО *</label
+                        >
+                        <input
+                            type="text"
+                            bind:value={editingClient.full_name}
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                            required
+                        />
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >Тип клиента *</label
+                        >
+                        <!-- bind:value={editingClient.type} -->
+                        <select
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                        >
+                            <option value="Физ">Физ. лицо</option>
+                            <option value="Юр">Юр. лицо</option>
+                            <option value="Поставщик">Поставщик</option>
+                            <option value="Сотрудник">Сотрудник</option>
+                            <option value="Контрагент">Контрагент</option>
+                            <option value="Покупатель">Покупатель</option>
+                        </select>
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >ID2</label
+                        >
+                        <input
+                            type="text"
+                            bind:value={editingClient.id2}
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                        />
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >Метка</label
+                        >
+                        <input
+                            type="text"
+                            bind:value={editingClient.mark}
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                        />
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >Email</label
+                        >
+                        <!-- bind:value={editingClient.email} -->
+                        <input
+                            type="email"
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                        />
+                    </div>
+
+                    <!-- Emails -->
+                    <div class="col-span-2">
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-4 border-b border-neutral-300 pb-2 mt-4"
+                        >
+                            Email адреса
+                        </h3>
+                        {#if editingClient.emails && editingClient.emails.length > 0}
+                            {#each editingClient.emails as email, i}
+                                <div class="flex gap-2 mb-2">
+                                    <input
+                                        type="email"
+                                        bind:value={editingClient.emails[i]}
+                                        placeholder="example@company.com"
+                                        class="flex-1 px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                                    />
+                                    {#if editingClient.emails.length > 1}
+                                        <button
+                                            type="button"
+                                            onclick={() => removeEmail(i)}
+                                            class="px-3 py-2 border-2 border-red-400 text-red-700 hover:bg-red-50 font-bold uppercase text-xs"
+                                        >
+                                            Удалить
+                                        </button>
+                                    {/if}
+                                </div>
+                            {/each}
+                        {:else}
+                            <div class="text-sm text-neutral-500 mb-2">
+                                Нет email адресов
+                            </div>
+                        {/if}
+                        <button
+                            type="button"
+                            onclick={addEmail}
+                            class="mt-2 px-3 py-2 border-2 border-neutral-300 hover:bg-neutral-100 font-bold uppercase text-xs"
+                        >
+                            + Добавить email
+                        </button>
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >День рождения</label
+                        >
+                        <input
+                            type="date"
+                            bind:value={editingClient.birthday}
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                        />
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-3"
+                            >Статус</label
+                        >
+                        <label
+                            class="flex items-center gap-3 cursor-pointer group"
+                        >
+                            <div class="relative">
+                                <!-- bind:checked={editingClient.contractor} -->
+                                <input type="checkbox" class="peer sr-only" />
+                                <div
+                                    class="w-11 h-6 bg-neutral-300 border-2 border-neutral-400 peer-checked:bg-emerald-500 peer-checked:border-emerald-600 transition-all"
+                                ></div>
+                                <div
+                                    class="absolute left-0.5 top-0.5 w-5 h-5 bg-white border-2 border-neutral-400 peer-checked:border-emerald-600 transition-transform peer-checked:translate-x-5"
+                                ></div>
+                            </div>
+                            <span
+                                class="text-sm font-bold text-neutral-700 uppercase tracking-wider group-hover:text-neutral-900"
+                                >Контрагент</span
+                            >
+                        </label>
+                    </div>
+
+                    <!-- Телефоны -->
+                    <div class="col-span-2">
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-4 border-b border-neutral-300 pb-2 mt-4"
+                        >
+                            Телефоны
+                        </h3>
+                        {#if editingClient.phones && editingClient.phones.length > 0}
+                            {#each editingClient.phones as phone, i}
+                                <div class="flex gap-2 mb-2">
+                                    <input
+                                        type="tel"
+                                        bind:value={editingClient.phones[i]}
+                                        placeholder="+7 (999) 123-45-67"
+                                        class="flex-1 px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                                    />
+                                    {#if editingClient.phones.length > 1}
+                                        <button
+                                            type="button"
+                                            onclick={() => removePhone(i)}
+                                            class="px-3 py-2 border-2 border-red-400 text-red-700 hover:bg-red-50 font-bold uppercase text-xs"
+                                        >
+                                            Удалить
+                                        </button>
+                                    {/if}
+                                </div>
+                            {/each}
+                        {:else}
+                            <div class="text-sm text-neutral-500 mb-2">
+                                Нет телефонов
+                            </div>
+                        {/if}
+                        <button
+                            type="button"
+                            onclick={addPhone}
+                            class="mt-2 px-3 py-2 border-2 border-neutral-300 hover:bg-neutral-100 font-bold uppercase text-xs"
+                        >
+                            + Добавить телефон
+                        </button>
+                    </div>
+
+                    <!-- Адреса -->
+                    <div class="col-span-2">
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-4 border-b border-neutral-300 pb-2 mt-4"
+                        >
+                            Адреса
+                        </h3>
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >Физический адрес</label
+                        >
+                        <textarea
+                            bind:value={editingClient.physical_address}
+                            rows="2"
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 resize-none"
+                        ></textarea>
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >Юридический адрес</label
+                        >
+                        <textarea
+                            bind:value={editingClient.legal_address}
+                            rows="2"
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 resize-none"
+                        ></textarea>
+                    </div>
+
+                    <!-- Дополнительная информация -->
+                    <div class="col-span-2">
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-4 border-b border-neutral-300 pb-2 mt-4"
+                        >
+                            Дополнительно
+                        </h3>
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >Дата регистрации</label
+                        >
+                        <input
+                            type="date"
+                            bind:value={editingClient.registration_date}
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                        />
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >Канал привлечения</label
+                        >
+                        <input
+                            type="text"
+                            bind:value={editingClient.ad_channel}
+                            placeholder="Реклама, рекомендация..."
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                        />
+                    </div>
+
+                    <div>
+                        <label class="flex items-center gap-2 cursor-pointer">
+                            <!-- bind:checked={editingClient.contractor} -->
+                            <input
+                                type="checkbox"
+                                class="w-4 h-4 border-2 border-neutral-400"
+                            />
+                            <span
+                                class="text-xs font-bold text-neutral-700 uppercase tracking-wider"
+                                >Контрагент</span
+                            >
+                        </label>
+                    </div>
+
+                    <!-- Custom Registration Data -->
+                    <div class="col-span-2">
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-4 border-b border-neutral-300 pb-2 mt-4"
+                        >
+                            Регистрационные данные
+                        </h3>
+
+                        {#if editingClient.reg_data && Object.keys(editingClient.reg_data).length > 0}
+                            <div class="mb-4 space-y-2">
+                                {#each Object.entries(editingClient.reg_data) as [key, value]}
+                                    <div
+                                        class="flex gap-2 items-center bg-neutral-50 border-2 border-neutral-200 p-3"
+                                    >
+                                        <div class="flex-1">
+                                            <div
+                                                class="text-xs text-neutral-600 font-bold uppercase mb-1"
+                                            >
+                                                {key}
+                                            </div>
+                                            <div
+                                                class="text-sm text-neutral-900 font-mono"
+                                            >
+                                                {value}
+                                            </div>
+                                        </div>
+                                        <button
+                                            type="button"
+                                            onclick={() => removeRegData(key)}
+                                            class="px-3 py-2 border-2 border-red-400 text-red-700 hover:bg-red-50 font-bold uppercase text-xs"
+                                        >
+                                            Удалить
+                                        </button>
+                                    </div>
+                                {/each}
+                            </div>
+                        {:else}
+                            <div class="text-sm text-neutral-500 mb-4">
+                                Нет регистрационных данных
+                            </div>
+                        {/if}
+
+                        <div class="flex gap-2">
+                            <input
+                                type="text"
+                                bind:value={newRegDataKey}
+                                placeholder="Ключ (напр. ИНН, ОГРН, Паспорт)"
+                                class="flex-1 px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                            />
+                            <input
+                                type="text"
+                                bind:value={newRegDataValue}
+                                placeholder="Значение"
+                                class="flex-1 px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                            />
+                            <button
+                                type="button"
+                                onclick={addRegData}
+                                disabled={!newRegDataKey || !newRegDataValue}
+                                class="px-4 py-2 border-2 border-neutral-300 hover:bg-neutral-100 disabled:opacity-50 disabled:cursor-not-allowed font-bold uppercase text-xs whitespace-nowrap"
+                            >
+                                + Добавить
+                            </button>
+                        </div>
+                    </div>
+
+                    <div class="col-span-2">
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >Примечания</label
+                        >
+                        <textarea
+                            bind:value={editingClient.note}
+                            rows="3"
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900 resize-none"
+                        ></textarea>
+                    </div>
+
+                    <!-- Доход -->
+                    <div class="col-span-2">
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-4 border-b border-neutral-300 pb-2 mt-4"
+                        >
+                            Финансы
+                        </h3>
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >Доход (сумма)</label
+                        >
+                        <input
+                            type="number"
+                            bind:value={editingClient.income.amount}
+                            step="0.01"
+                            min="0"
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                        />
+                    </div>
+
+                    <div>
+                        <label
+                            class="block text-xs font-bold text-neutral-700 uppercase tracking-wider mb-2"
+                            >Валюта</label
+                        >
+                        <select
+                            bind:value={editingClient.income.currency}
+                            class="w-full px-3 py-2 border-2 border-neutral-300 text-sm focus:outline-none focus:border-neutral-900"
+                        >
+                            <option value="RUB">RUB (₽)</option>
+                            <option value="USD">USD ($)</option>
+                            <option value="EUR">EUR (€)</option>
+                            <option value="KZT">KZT (₸)</option>
+                        </select>
+                    </div>
+                </div>
+            </div>
+
+            <div
+                class="border-t-2 border-neutral-900 p-6 bg-neutral-100 flex justify-end gap-3"
+            >
+                <button
+                    type="button"
+                    onclick={() => {
+                        showEditModal = false;
+                        showCreateModal = false;
+                        editingClient = null;
+                    }}
+                    class="px-6 py-2 border-2 border-neutral-400 hover:bg-neutral-200 font-bold uppercase text-sm tracking-wide"
+                >
+                    Отмена
+                </button>
+                <button
+                    type="button"
+                    onclick={saveClient}
+                    class="px-6 py-2 bg-neutral-900 text-white border-2 border-neutral-900 hover:bg-neutral-800 font-bold uppercase text-sm tracking-wide"
+                >
+                    {showCreateModal ? "Создать" : "Сохранить"}
+                </button>
+            </div>
+        </div>
+    </div>
+{/if}
+
+<!-- Activity Analytics Modal -->
+{#if showActivityModal}
+    <div class="fixed inset-0 flex items-center justify-center z-50 p-4">
+        <!-- Backdrop with blur -->
+        <div
+            class="absolute inset-0 bg-neutral-900/40 backdrop-blur-sm"
+            onclick={() => (showActivityModal = false)}
+        ></div>
+
+        <!-- Modal -->
+        <div
+            class="relative bg-white border-2 border-neutral-900 shadow-2xl max-w-5xl w-full max-h-[90vh] overflow-y-auto"
+        >
+            <div
+                class="border-b-2 border-neutral-900 p-6 bg-neutral-100 flex justify-between items-center sticky top-0 z-10"
+            >
+                <h2 class="text-xl font-bold text-neutral-900 uppercase">
+                    📈 Аналитика активности
+                </h2>
+                <button
+                    onclick={() => (showActivityModal = false)}
+                    class="text-2xl font-bold text-neutral-600 hover:text-neutral-900"
+                >
+                    ✕
+                </button>
+            </div>
+
+            <div class="p-6">
+                <!-- Quick Stats -->
+                <div class="grid grid-cols-4 gap-4 mb-6">
+                    <div
+                        class="bg-gradient-to-br from-blue-50 to-blue-100 border-2 border-blue-300 p-4"
+                    >
+                        <div
+                            class="text-xs font-bold text-blue-700 uppercase mb-1"
+                        >
+                            Средний доход
+                        </div>
+                        <div class="text-2xl font-bold text-blue-900">
+                            {formatMoney({
+                                amount: stats.totalIncome / stats.total || 0,
+                                currency: "RUB",
+                            })}
+                        </div>
+                    </div>
+                    <div
+                        class="bg-gradient-to-br from-green-50 to-green-100 border-2 border-green-300 p-4"
+                    >
+                        <div
+                            class="text-xs font-bold text-green-700 uppercase mb-1"
+                        >
+                            Ср. заявок
+                        </div>
+                        <div class="text-2xl font-bold text-green-900">
+                            {(stats.totalRequests / stats.total || 0).toFixed(
+                                1,
+                            )}
+                        </div>
+                    </div>
+                    <div
+                        class="bg-gradient-to-br from-purple-50 to-purple-100 border-2 border-purple-300 p-4"
+                    >
+                        <div
+                            class="text-xs font-bold text-purple-700 uppercase mb-1"
+                        >
+                            Конверсия
+                        </div>
+                        <div class="text-2xl font-bold text-purple-900">
+                            {(
+                                (clients.filter((c) => c.request_count > 0)
+                                    .length /
+                                    stats.total) *
+                                    100 || 0
+                            ).toFixed(1)}%
+                        </div>
+                    </div>
+                    <div
+                        class="bg-gradient-to-br from-amber-50 to-amber-100 border-2 border-amber-300 p-4"
+                    >
+                        <div
+                            class="text-xs font-bold text-amber-700 uppercase mb-1"
+                        >
+                            Активные
+                        </div>
+                        <div class="text-2xl font-bold text-amber-900">
+                            {clients.filter((c) => c.request_count > 0).length}
+                        </div>
+                    </div>
+                </div>
+
+                <!-- Top Clients by Income -->
+                <div class="mb-6">
+                    <h3
+                        class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-3 border-b-2 border-neutral-300 pb-2"
+                    >
+                        🏆 Топ-10 клиентов по доходу
+                    </h3>
+                    <div class="border-2 border-neutral-300">
+                        <table class="w-full">
+                            <thead class="bg-neutral-100">
+                                <tr>
+                                    <th
+                                        class="px-4 py-2 text-left text-xs font-bold text-neutral-700 uppercase"
+                                        >Место</th
+                                    >
+                                    <th
+                                        class="px-4 py-2 text-left text-xs font-bold text-neutral-700 uppercase"
+                                        >Клиент</th
+                                    >
+                                    <th
+                                        class="px-4 py-2 text-left text-xs font-bold text-neutral-700 uppercase"
+                                        >Тип</th
+                                    >
+                                    <th
+                                        class="px-4 py-2 text-right text-xs font-bold text-neutral-700 uppercase"
+                                        >Заявки</th
+                                    >
+                                    <th
+                                        class="px-4 py-2 text-right text-xs font-bold text-neutral-700 uppercase"
+                                        >Доход</th
+                                    >
+                                </tr>
+                            </thead>
+                            <tbody class="divide-y divide-neutral-200">
+                                {#each clients
+                                    .sort((a, b) => (b.income?.amount || 0) - (a.income?.amount || 0))
+                                    .slice(0, 10) as client, i}
+                                    <tr class="hover:bg-neutral-50">
+                                        <td class="px-4 py-2 text-center">
+                                            {#if i === 0}
+                                                <span class="text-2xl">🥇</span>
+                                            {:else if i === 1}
+                                                <span class="text-2xl">🥈</span>
+                                            {:else if i === 2}
+                                                <span class="text-2xl">🥉</span>
+                                            {:else}
+                                                <span
+                                                    class="text-sm font-bold text-neutral-600"
+                                                    >{i + 1}</span
+                                                >
+                                            {/if}
+                                        </td>
+                                        <td
+                                            class="px-4 py-2 text-sm font-bold text-neutral-900"
+                                            >{client.full_name}</td
+                                        >
+                                        <td class="px-4 py-2">
+                                            <!-- <span
+                                                class="inline-block px-2 py-1 text-xs font-bold border {getTypeColor(
+                                                    client.type,
+                                                )}">{client.type}</span
+                                            > -->
+                                        </td>
+                                        <td
+                                            class="px-4 py-2 text-right text-sm font-medium"
+                                            >{client.request_count || 0}</td
+                                        >
+                                        <td
+                                            class="px-4 py-2 text-right text-sm font-bold text-green-700"
+                                            >{formatMoney(client.income)}</td
+                                        >
+                                    </tr>
+                                {/each}
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+
+                <!-- Distribution by Type -->
+                <div>
+                    <h3
+                        class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-3 border-b-2 border-neutral-300 pb-2"
+                    >
+                        📊 Распределение по типам
+                    </h3>
+                    <div class="grid grid-cols-3 gap-4">
+                        {#each ["Физ", "Юр", "Поставщик", "Сотрудник", "Контрагент", "Покупатель"] as type}
+                            <!-- {@const count = clients.filter(
+                                (c) => c.type === type,
+                            ).length} -->
+                            <!-- {@const percentage = (
+                                (count / stats.total) *
+                                100
+                            ).toFixed(1)} -->
+                            <div class="border-2 border-neutral-300 p-4">
+                                <div
+                                    class="flex justify-between items-center mb-2"
+                                >
+                                    <!-- <span
+                                        class="inline-block px-2 py-1 text-xs font-bold border {getTypeColor(
+                                            type,
+                                        )}">{type}</span
+                                    >
+                                    <span
+                                        class="text-sm font-bold text-neutral-900"
+                                        >{count}</span
+                                    > -->
+                                </div>
+                                <div
+                                    class="w-full bg-neutral-200 h-2 border border-neutral-300"
+                                >
+                                    <!-- <div
+                                        class="bg-neutral-900 h-full"
+                                        style="width: {percentage}%"
+                                    ></div> -->
+                                </div>
+                                <!-- <div
+                                    class="text-xs text-neutral-600 mt-1 text-right font-bold"
+                                >
+                                    {percentage}%
+                                </div> -->
+                            </div>
+                        {/each}
+                    </div>
+                </div>
+            </div>
+
+            <div
+                class="border-t-2 border-neutral-900 p-6 bg-neutral-100 flex justify-end"
+            >
+                <button
+                    onclick={() => (showActivityModal = false)}
+                    class="px-6 py-2 bg-neutral-900 text-white border-2 border-neutral-900 hover:bg-neutral-800 font-bold uppercase text-sm tracking-wide"
+                >
+                    Закрыть
+                </button>
+            </div>
+        </div>
+    </div>
+{/if}
+
+<!-- Details Modal -->
+{#if showDetailsModal && selectedClient}
+    <div class="fixed inset-0 flex items-center justify-center z-50 p-4">
+        <!-- Backdrop with blur -->
+        <div
+            class="absolute inset-0 bg-neutral-900/40 backdrop-blur-sm"
+            onclick={() => (showDetailsModal = false)}
+        ></div>
+
+        <!-- Modal -->
+        <div
+            class="relative bg-white border-2 border-neutral-900 shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-y-auto"
+        >
+            <div
+                class="border-b-2 border-neutral-900 p-6 bg-neutral-100 flex justify-between items-center sticky top-0 z-10"
+            >
+                <h2 class="text-xl font-bold text-neutral-900 uppercase">
+                    Карточка клиента
+                </h2>
+                <button
+                    onclick={() => (showDetailsModal = false)}
+                    class="text-2xl font-bold text-neutral-600 hover:text-neutral-900"
+                >
+                    ✕
+                </button>
+            </div>
+
+            <div class="p-6">
+                <div class="grid grid-cols-2 gap-6">
+                    <!-- Основная информация -->
+                    <div class="col-span-2 flex items-start justify-between">
+                        <div>
+                            <h1
+                                class="text-2xl font-bold text-neutral-900 mb-2"
+                            >
+                                {selectedClient.full_name}
+                            </h1>
+                            <div class="flex gap-2 items-center flex-wrap">
+                                <!-- <span
+                                    class="inline-block px-3 py-1 text-sm font-bold border-2 {getTypeColor(
+                                        selectedClient.type,
+                                    )} uppercase">{selectedClient.type}</span
+                                > -->
+                                <!-- {#if selectedClient.contractor}
+                                    <span
+                                        class="inline-block px-3 py-1 text-sm font-bold bg-emerald-100 text-emerald-900 border-2 border-emerald-400 uppercase flex items-center gap-2"
+                                    >
+                                        <svg
+                                            class="w-4 h-4"
+                                            fill="none"
+                                            viewBox="0 0 24 24"
+                                            stroke="currentColor"
+                                            stroke-width="2"
+                                        >
+                                            <path
+                                                stroke-linecap="round"
+                                                stroke-linejoin="round"
+                                                d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
+                                            />
+                                        </svg>
+                                        Контрагент
+                                    </span>
+                                {/if} -->
+                                {#if selectedClient.mark}
+                                    <span
+                                        class="inline-block px-3 py-1 text-sm font-bold bg-amber-100 text-amber-900 border-2 border-amber-400 uppercase"
+                                        >{selectedClient.mark}</span
+                                    >
+                                {/if}
+                            </div>
+                        </div>
+                        <button
+                            onclick={() => {
+                                openEditModal(selectedClient);
+                                showDetailsModal = false;
+                            }}
+                            class="px-4 py-2 bg-neutral-900 text-white border-2 border-neutral-900 hover:bg-neutral-800 font-bold uppercase text-sm"
+                        >
+                            Редактировать
+                        </button>
+                    </div>
+
+                    <div
+                        class="col-span-2 border-t-2 border-neutral-300 mt-4 pt-4"
+                    ></div>
+
+                    <!-- ID -->
+                    <div>
+                        <div
+                            class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                        >
+                            ID системы
+                        </div>
+                        <div class="text-sm font-mono text-neutral-900">
+                            {selectedClient.id}
+                        </div>
+                    </div>
+
+                    {#if selectedClient.id2}
+                        <div>
+                            <div
+                                class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                            >
+                                ID2
+                            </div>
+                            <div class="text-sm font-mono text-neutral-900">
+                                {selectedClient.id2}
+                            </div>
+                        </div>
+                    {/if}
+
+                    <!-- Контакты -->
+                    <div
+                        class="col-span-2 border-t-2 border-neutral-300 mt-4 pt-4"
+                    >
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-3"
+                        >
+                            Контактная информация
+                        </h3>
+                    </div>
+
+                    <div>
+                        <div
+                            class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                        >
+                            Телефоны
+                        </div>
+                        {#if selectedClient.phones && selectedClient.phones.length > 0}
+                            {#each selectedClient.phones as phone}
+                                <div
+                                    class="text-sm text-neutral-900 font-medium mb-1"
+                                >
+                                    <a
+                                        href="tel:{phone}"
+                                        class="hover:text-blue-700">{phone}</a
+                                    >
+                                </div>
+                            {/each}
+                        {:else}
+                            <div class="text-sm text-neutral-400">
+                                Не указано
+                            </div>
+                        {/if}
+                    </div>
+
+                    <div>
+                        <div
+                            class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                        >
+                            Email
+                        </div>
+                        {#if selectedClient.emails && selectedClient.emails.length > 0}
+                            {#each selectedClient.emails as email}
+                                <a
+                                    href="mailto:{email}"
+                                    class="text-sm text-blue-700 hover:text-blue-900 font-medium block mb-1"
+                                    >{email}</a
+                                >
+                            {/each}
+                        {:else}
+                            <div class="text-sm text-neutral-400">
+                                Не указано
+                            </div>
+                        {/if}
+                    </div>
+
+                    <!-- Адреса -->
+                    <div
+                        class="col-span-2 border-t-2 border-neutral-300 mt-4 pt-4"
+                    >
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-3"
+                        >
+                            Адреса
+                        </h3>
+                    </div>
+
+                    <div>
+                        <div
+                            class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                        >
+                            Физический адрес
+                        </div>
+                        <div class="text-sm text-neutral-900">
+                            {selectedClient.physical_address || "Не указано"}
+                        </div>
+                    </div>
+
+                    <div>
+                        <div
+                            class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                        >
+                            Юридический адрес
+                        </div>
+                        <div class="text-sm text-neutral-900">
+                            {selectedClient.legal_address || "Не указано"}
+                        </div>
+                    </div>
+
+                    <!-- Даты -->
+                    <div
+                        class="col-span-2 border-t-2 border-neutral-300 mt-4 pt-4"
+                    >
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-3"
+                        >
+                            Даты
+                        </h3>
+                    </div>
+
+                    <div>
+                        <div
+                            class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                        >
+                            Дата регистрации
+                        </div>
+                        <div class="text-sm font-medium text-neutral-900">
+                            {formatDate(selectedClient.registration_date)}
+                        </div>
+                    </div>
+
+                    {#if selectedClient.birthday}
+                        <div>
+                            <div
+                                class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                            >
+                                День рождения
+                            </div>
+                            <div class="text-sm font-medium text-neutral-900">
+                                {formatDate(selectedClient.birthday)}
+                            </div>
+                        </div>
+                    {/if}
+
+                    <!-- Статистика -->
+                    <div
+                        class="col-span-2 border-t-2 border-neutral-300 mt-4 pt-4"
+                    >
+                        <h3
+                            class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-3"
+                        >
+                            Статистика
+                        </h3>
+                    </div>
+
+                    <div>
+                        <div
+                            class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                        >
+                            Количество заявок
+                        </div>
+                        <div class="text-2xl font-bold text-neutral-900">
+                            {selectedClient.request_count || 0}
+                        </div>
+                    </div>
+
+                    <div>
+                        <div
+                            class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                        >
+                            Общий доход
+                        </div>
+                        <div class="text-2xl font-bold text-green-700">
+                            {formatMoney(selectedClient.income)}
+                        </div>
+                    </div>
+
+                    <!-- Дополнительно -->
+                    {#if selectedClient.ad_channel || Object.keys(selectedClient.reg_data || {}).length > 0 || selectedClient.note}
+                        <div
+                            class="col-span-2 border-t-2 border-neutral-300 mt-4 pt-4"
+                        >
+                            <h3
+                                class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-3"
+                            >
+                                Дополнительная информация
+                            </h3>
+                        </div>
+
+                        {#if selectedClient.ad_channel}
+                            <div>
+                                <div
+                                    class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                                >
+                                    Канал привлечения
+                                </div>
+                                <div class="text-sm text-neutral-900">
+                                    {selectedClient.ad_channel}
+                                </div>
+                            </div>
+                        {/if}
+
+                        {#if Object.keys(selectedClient.reg_data || {}).length > 0}
+                            <div class="col-span-2">
+                                <div
+                                    class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-2"
+                                >
+                                    Регистрационные данные
+                                </div>
+                                <div
+                                    class="bg-neutral-50 border-2 border-neutral-200 p-3 space-y-2"
+                                >
+                                    {#each Object.entries(selectedClient.reg_data) as [key, value]}
+                                        <div
+                                            class="flex justify-between items-center border-b border-neutral-200 pb-2 last:border-b-0"
+                                        >
+                                            <span
+                                                class="text-xs font-bold text-neutral-600 uppercase"
+                                                >{key}:</span
+                                            >
+                                            <span
+                                                class="text-sm text-neutral-900 font-mono"
+                                                >{value}</span
+                                            >
+                                        </div>
+                                    {/each}
+                                </div>
+                            </div>
+                        {/if}
+
+                        {#if selectedClient.note}
+                            <div class="col-span-2">
+                                <div
+                                    class="text-xs font-bold text-neutral-600 uppercase tracking-wider mb-1"
+                                >
+                                    Примечания
+                                </div>
+                                <div
+                                    class="text-sm text-neutral-900 bg-neutral-50 border-2 border-neutral-200 p-3"
+                                >
+                                    {selectedClient.note}
+                                </div>
+                            </div>
+                        {/if}
+                    {/if}
+                </div>
+            </div>
+
+            <div
+                class="border-t-2 border-neutral-900 p-6 bg-neutral-100 flex justify-end"
+            >
+                <button
+                    onclick={() => (showDetailsModal = false)}
+                    class="px-6 py-2 bg-neutral-900 text-white border-2 border-neutral-900 hover:bg-neutral-800 font-bold uppercase text-sm tracking-wide"
+                >
+                    Закрыть
+                </button>
+            </div>
+        </div>
+    </div>
+{/if}

+ 21 - 0
src/routes/clients/+page.ts

@@ -0,0 +1,21 @@
+import type { PageLoad } from "./$types";
+
+import { SERVER_API_PORT, SERVER_API_URL } from "$lib/api";
+import type { ClientInfo } from "$lib/types/client";
+
+export const load: PageLoad = async ({ fetch }) => {
+  const url = `${SERVER_API_URL}${SERVER_API_PORT}/v1/clients?offset=0&limit=-1`;
+  const res = await fetch(url);
+
+  if (!res.ok) {
+    console.error("Fetch error:", res.status);
+    return { clients: [] };
+  }
+
+  const clients: ClientInfo[] = await res.json();
+  console.log("Loaded clients:", clients);
+
+  return {
+    clients,
+  };
+};

+ 1 - 0
src/routes/orders/+page.svelte

@@ -0,0 +1 @@
+<h1>Orders</h1>

+ 1 - 0
src/routes/products/+page.svelte

@@ -0,0 +1 @@
+<h1>Products</h1>

+ 20 - 0
src/routes/test_ui/+page.svelte

@@ -0,0 +1,20 @@
+<script lang="ts">
+    import List from "$lib/components/ui/List.svelte";
+    import Slider from "$lib/components/ui/Slider.svelte";
+    import Card from "$lib/components/ui/Card.svelte";
+    import Form from "$lib/components/ui/Form.svelte";
+    import Navbar from "$lib/components/ui/Navbar.svelte";
+    import Footer from "$lib/components/ui/Footer.svelte";
+    import Table from "$lib/components/ui/Table.svelte";
+    import ClientTable from "$lib/components/ui/ClientTable.svelte";
+</script>
+
+<Navbar />
+<button class="btn">Default</button>
+<Card title="Card1" description="Test..." />
+<List items={["Apple", "Banana", "Orange"]} />
+<Table />
+<ClientTable />
+<Slider />
+<Form name="Alex" email="alex@gmail.com" />
+<Footer />

+ 1 - 0
static/favicon.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="107" height="128" viewBox="0 0 107 128"><title>svelte-logo</title><path d="M94.157 22.819c-10.4-14.885-30.94-19.297-45.792-9.835L22.282 29.608A29.92 29.92 0 0 0 8.764 49.65a31.5 31.5 0 0 0 3.108 20.231 30 30 0 0 0-4.477 11.183 31.9 31.9 0 0 0 5.448 24.116c10.402 14.887 30.942 19.297 45.791 9.835l26.083-16.624A29.92 29.92 0 0 0 98.235 78.35a31.53 31.53 0 0 0-3.105-20.232 30 30 0 0 0 4.474-11.182 31.88 31.88 0 0 0-5.447-24.116" style="fill:#ff3e00"/><path d="M45.817 106.582a20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.503 18 18 0 0 1 .624-2.435l.49-1.498 1.337.981a33.6 33.6 0 0 0 10.203 5.098l.97.294-.09.968a5.85 5.85 0 0 0 1.052 3.878 6.24 6.24 0 0 0 6.695 2.485 5.8 5.8 0 0 0 1.603-.704L69.27 76.28a5.43 5.43 0 0 0 2.45-3.631 5.8 5.8 0 0 0-.987-4.371 6.24 6.24 0 0 0-6.698-2.487 5.7 5.7 0 0 0-1.6.704l-9.953 6.345a19 19 0 0 1-5.296 2.326 20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.502 17.99 17.99 0 0 1 8.13-12.052l26.081-16.623a19 19 0 0 1 5.3-2.329 20.72 20.72 0 0 1 22.237 8.243 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-.624 2.435l-.49 1.498-1.337-.98a33.6 33.6 0 0 0-10.203-5.1l-.97-.294.09-.968a5.86 5.86 0 0 0-1.052-3.878 6.24 6.24 0 0 0-6.696-2.485 5.8 5.8 0 0 0-1.602.704L37.73 51.72a5.42 5.42 0 0 0-2.449 3.63 5.79 5.79 0 0 0 .986 4.372 6.24 6.24 0 0 0 6.698 2.486 5.8 5.8 0 0 0 1.602-.704l9.952-6.342a19 19 0 0 1 5.295-2.328 20.72 20.72 0 0 1 22.237 8.242 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-8.13 12.053l-26.081 16.622a19 19 0 0 1-5.3 2.328" style="fill:#fff"/></svg>

二进制
static/test/test.png


二进制
static/test/test002.jpg


+ 18 - 0
svelte.config.js

@@ -0,0 +1,18 @@
+import adapter from '@sveltejs/adapter-auto';
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+	// Consult https://svelte.dev/docs/kit/integrations
+	// for more information about preprocessors
+	preprocess: vitePreprocess(),
+
+	kit: {
+		// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
+		// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
+		// See https://svelte.dev/docs/kit/adapters for more information about adapters.
+		adapter: adapter()
+	}
+};
+
+export default config;

+ 19 - 0
tsconfig.json

@@ -0,0 +1,19 @@
+{
+	"extends": "./.svelte-kit/tsconfig.json",
+	"compilerOptions": {
+		"allowJs": true,
+		"checkJs": true,
+		"esModuleInterop": true,
+		"forceConsistentCasingInFileNames": true,
+		"resolveJsonModule": true,
+		"skipLibCheck": true,
+		"sourceMap": true,
+		"strict": true,
+		"moduleResolution": "bundler"
+	}
+	// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
+	// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
+	//
+	// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
+	// from the referenced tsconfig.json - TypeScript does not merge them in
+}

+ 7 - 0
vite.config.ts

@@ -0,0 +1,7 @@
+import tailwindcss from '@tailwindcss/vite';
+import { sveltekit } from '@sveltejs/kit/vite';
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+	plugins: [tailwindcss(), sveltekit()]
+});