diff --git a/tailwindui-salient/salient b/tailwindui-salient/salient
new file mode 160000
index 0000000..da588a8
--- /dev/null
+++ b/tailwindui-salient/salient
@@ -0,0 +1 @@
+Subproject commit da588a8b210f99d7e4d8763ed05c73e02773b008
diff --git a/v2/component-library/.gitignore b/v2/component-library/.gitignore
new file mode 100644
index 0000000..a4d699a
--- /dev/null
+++ b/v2/component-library/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+dist
+*.local
+.DS_Store
diff --git a/v2/component-library/components.json b/v2/component-library/components.json
new file mode 100644
index 0000000..2186361
--- /dev/null
+++ b/v2/component-library/components.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": false,
+ "tsx": true,
+ "tailwind": {
+ "config": "",
+ "css": "src/styles/globals.css",
+ "baseColor": "slate",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "iconLibrary": "lucide",
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ }
+}
diff --git a/v2/component-library/index.html b/v2/component-library/index.html
new file mode 100644
index 0000000..34ffba0
--- /dev/null
+++ b/v2/component-library/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+ GebOS – Messdienstleistungen einfach gemacht
+
+
+
+
+
+
+
diff --git a/v2/component-library/package-lock.json b/v2/component-library/package-lock.json
new file mode 100644
index 0000000..b063773
--- /dev/null
+++ b/v2/component-library/package-lock.json
@@ -0,0 +1,3631 @@
+{
+ "name": "gebos-component-library",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "gebos-component-library",
+ "version": "0.1.0",
+ "dependencies": {
+ "@fontsource-variable/inter": "^5.2.5",
+ "@radix-ui/react-accordion": "^1.2.11",
+ "@radix-ui/react-checkbox": "^1.3.2",
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
+ "@radix-ui/react-label": "^2.1.7",
+ "@radix-ui/react-select": "^2.2.5",
+ "@radix-ui/react-separator": "^1.1.7",
+ "@radix-ui/react-slot": "^1.2.3",
+ "@radix-ui/react-tabs": "^1.1.12",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.539.0",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-router-dom": "^7.8.0",
+ "tailwind-merge": "^3.3.1",
+ "tw-animate-css": "^1.4.0"
+ },
+ "devDependencies": {
+ "@tailwindcss/vite": "^4.1.11",
+ "@types/node": "^24.2.0",
+ "@types/react": "^19.1.9",
+ "@types/react-dom": "^19.1.7",
+ "@vitejs/plugin-react": "^4.7.0",
+ "tailwindcss": "^4.1.11",
+ "typescript": "^5.9.2",
+ "vite": "^7.1.1"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helpers": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz",
+ "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.8",
+ "@babel/types": "^7.29.8",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
+ "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.8"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz",
+ "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz",
+ "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz",
+ "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.8",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.8",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.8",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
+ "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
+ "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz",
+ "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz",
+ "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz",
+ "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz",
+ "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz",
+ "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz",
+ "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz",
+ "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz",
+ "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz",
+ "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz",
+ "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz",
+ "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz",
+ "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz",
+ "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz",
+ "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz",
+ "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz",
+ "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz",
+ "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz",
+ "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz",
+ "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz",
+ "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz",
+ "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz",
+ "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz",
+ "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz",
+ "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz",
+ "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@floating-ui/core": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz",
+ "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.12"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz",
+ "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/core": "^1.8.0",
+ "@floating-ui/utils": "^0.2.12"
+ }
+ },
+ "node_modules/@floating-ui/react-dom": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz",
+ "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.8.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz",
+ "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
+ "license": "MIT"
+ },
+ "node_modules/@fontsource-variable/inter": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.3.0.tgz",
+ "integrity": "sha512-OupL48va4JNofb97w6NYeF9S7W/kHNKM0Er8Dem5nqi4jeOLrVJDoE8tZEpnMJmtkvNbB1EIPPwHcdkF6b1oUA==",
+ "license": "OFL-1.1",
+ "funding": {
+ "url": "https://github.com/sponsors/ayuhito"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@napi-rs/lzma-linux-x64-gnu": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz",
+ "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^22.20 || ^24.12 || >=25"
+ }
+ },
+ "node_modules/@radix-ui/number": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.3.tgz",
+ "integrity": "sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/primitive": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz",
+ "integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/react-accordion": {
+ "version": "1.2.20",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.20.tgz",
+ "integrity": "sha512-jDhG9FvAEnlhnjrsINbNXcUa4G+L1KqSkJSunkbKEzFRcAb52jvM0PjPxPRvhe1HNc5F5yc0yzzWeeqlH4yBIg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.7",
+ "@radix-ui/react-collapsible": "1.1.20",
+ "@radix-ui/react-collection": "1.1.15",
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-context": "1.2.2",
+ "@radix-ui/react-direction": "1.1.4",
+ "@radix-ui/react-id": "1.1.4",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-use-controllable-state": "1.2.6"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.15.tgz",
+ "integrity": "sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox": {
+ "version": "1.3.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.11.tgz",
+ "integrity": "sha512-Gnptr9pDDQxD3hgq2dtPbtrp/c2qH1mBwIzw3X/ivrMb2e1t0jMTi606fVEqFPaQR1ggXIVQWKj3P2WW9v7zGQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-context": "1.2.2",
+ "@radix-ui/react-presence": "1.1.10",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-use-controllable-state": "1.2.6",
+ "@radix-ui/react-use-size": "1.1.4"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-collapsible": {
+ "version": "1.1.20",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.20.tgz",
+ "integrity": "sha512-mcGesGplBnzN2sbvJETzpCNfSMyPnb29q1GRLU+Ib7bJrpIG2ywmRoh2V5VbA2uNvKikKUlVbAPks7JDjz4A8Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-context": "1.2.2",
+ "@radix-ui/react-id": "1.1.4",
+ "@radix-ui/react-presence": "1.1.10",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-use-controllable-state": "1.2.6",
+ "@radix-ui/react-use-layout-effect": "1.1.4"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-collection": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.15.tgz",
+ "integrity": "sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-context": "1.2.2",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-slot": "1.3.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz",
+ "integrity": "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-context": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.2.tgz",
+ "integrity": "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-direction": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.4.tgz",
+ "integrity": "sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.19",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz",
+ "integrity": "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-use-callback-ref": "1.1.4",
+ "@radix-ui/react-use-effect-event": "0.0.5"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dropdown-menu": {
+ "version": "2.1.24",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.24.tgz",
+ "integrity": "sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-context": "1.2.2",
+ "@radix-ui/react-id": "1.1.4",
+ "@radix-ui/react-menu": "2.1.24",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-use-controllable-state": "1.2.6"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-guards": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.6.tgz",
+ "integrity": "sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.16",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz",
+ "integrity": "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-use-callback-ref": "1.1.4"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-id": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.4.tgz",
+ "integrity": "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.4"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-label": {
+ "version": "2.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.15.tgz",
+ "integrity": "sha512-o/rdYEwZTTo5tjknnPeyQFU45kUC4i/XyeDPP+HGyi6XqpOP6Zf5Ya5vh/Yfe9Id5JiuWnnAx2XqIeD3UYZt0g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-menu": {
+ "version": "2.1.24",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.24.tgz",
+ "integrity": "sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.7",
+ "@radix-ui/react-collection": "1.1.15",
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-context": "1.2.2",
+ "@radix-ui/react-direction": "1.1.4",
+ "@radix-ui/react-dismissable-layer": "1.1.19",
+ "@radix-ui/react-focus-guards": "1.1.6",
+ "@radix-ui/react-focus-scope": "1.1.16",
+ "@radix-ui/react-id": "1.1.4",
+ "@radix-ui/react-popper": "1.3.7",
+ "@radix-ui/react-portal": "1.1.17",
+ "@radix-ui/react-presence": "1.1.10",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-roving-focus": "1.1.19",
+ "@radix-ui/react-slot": "1.3.3",
+ "@radix-ui/react-use-callback-ref": "1.1.4",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.7.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-popper": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.7.tgz",
+ "integrity": "sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.1.15",
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-context": "1.2.2",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-use-callback-ref": "1.1.4",
+ "@radix-ui/react-use-layout-effect": "1.1.4",
+ "@radix-ui/react-use-rect": "1.1.4",
+ "@radix-ui/react-use-size": "1.1.4",
+ "@radix-ui/rect": "1.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-portal": {
+ "version": "1.1.17",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.17.tgz",
+ "integrity": "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-use-layout-effect": "1.1.4"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-presence": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.10.tgz",
+ "integrity": "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.4"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.10",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.10.tgz",
+ "integrity": "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.3.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.19",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.19.tgz",
+ "integrity": "sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.7",
+ "@radix-ui/react-collection": "1.1.15",
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-context": "1.2.2",
+ "@radix-ui/react-direction": "1.1.4",
+ "@radix-ui/react-id": "1.1.4",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-use-callback-ref": "1.1.4",
+ "@radix-ui/react-use-controllable-state": "1.2.6",
+ "@radix-ui/react-use-is-hydrated": "0.1.3",
+ "@radix-ui/react-use-layout-effect": "1.1.4"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-select": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.3.7.tgz",
+ "integrity": "sha512-WFGImkmbzcfxeIwq/+4HvRN0pizBwbwQUED4I13ezQsDdfl38ZntN6TmR8XaSzPBqoCToe8rF75j6NPNDSzhbg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/number": "1.1.3",
+ "@radix-ui/primitive": "1.1.7",
+ "@radix-ui/react-collection": "1.1.15",
+ "@radix-ui/react-compose-refs": "1.1.5",
+ "@radix-ui/react-context": "1.2.2",
+ "@radix-ui/react-direction": "1.1.4",
+ "@radix-ui/react-dismissable-layer": "1.1.19",
+ "@radix-ui/react-focus-guards": "1.1.6",
+ "@radix-ui/react-focus-scope": "1.1.16",
+ "@radix-ui/react-id": "1.1.4",
+ "@radix-ui/react-popper": "1.3.7",
+ "@radix-ui/react-portal": "1.1.17",
+ "@radix-ui/react-presence": "1.1.10",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-slot": "1.3.3",
+ "@radix-ui/react-use-callback-ref": "1.1.4",
+ "@radix-ui/react-use-controllable-state": "1.2.6",
+ "@radix-ui/react-use-layout-effect": "1.1.4",
+ "@radix-ui/react-use-previous": "1.1.4",
+ "@radix-ui/react-visually-hidden": "1.2.11",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.7.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-separator": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.15.tgz",
+ "integrity": "sha512-jOLO4lssEzWpoDu7G+Ze4VjwMRUBt291pnZD0gmalREZipnTX3wadQo7Fy48GCTfe14/YRN6rw/rOJqrE85Wxw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slot": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.3.tgz",
+ "integrity": "sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.5"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-tabs": {
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.21.tgz",
+ "integrity": "sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.7",
+ "@radix-ui/react-context": "1.2.2",
+ "@radix-ui/react-direction": "1.1.4",
+ "@radix-ui/react-id": "1.1.4",
+ "@radix-ui/react-presence": "1.1.10",
+ "@radix-ui/react-primitive": "2.1.10",
+ "@radix-ui/react-roving-focus": "1.1.19",
+ "@radix-ui/react-use-controllable-state": "1.2.6"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-callback-ref": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.4.tgz",
+ "integrity": "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.6.tgz",
+ "integrity": "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.7",
+ "@radix-ui/react-use-effect-event": "0.0.5",
+ "@radix-ui/react-use-layout-effect": "1.1.4"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-effect-event": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz",
+ "integrity": "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.4"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-is-hydrated": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.3.tgz",
+ "integrity": "sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz",
+ "integrity": "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-previous": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.4.tgz",
+ "integrity": "sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-rect": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.4.tgz",
+ "integrity": "sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/rect": "1.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-size": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.4.tgz",
+ "integrity": "sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.4"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-visually-hidden": {
+ "version": "1.2.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.11.tgz",
+ "integrity": "sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/rect": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.3.tgz",
+ "integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==",
+ "license": "MIT"
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.4.tgz",
+ "integrity": "sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.4.tgz",
+ "integrity": "sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.4.tgz",
+ "integrity": "sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.4.tgz",
+ "integrity": "sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.4.tgz",
+ "integrity": "sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.4.tgz",
+ "integrity": "sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.4.tgz",
+ "integrity": "sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.4.tgz",
+ "integrity": "sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.4.tgz",
+ "integrity": "sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.4.tgz",
+ "integrity": "sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.4.tgz",
+ "integrity": "sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.4.tgz",
+ "integrity": "sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.4.tgz",
+ "integrity": "sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.4.tgz",
+ "integrity": "sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.4.tgz",
+ "integrity": "sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.4.tgz",
+ "integrity": "sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.4.tgz",
+ "integrity": "sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.4.tgz",
+ "integrity": "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.4.tgz",
+ "integrity": "sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.4.tgz",
+ "integrity": "sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.4.tgz",
+ "integrity": "sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.4.tgz",
+ "integrity": "sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.4.tgz",
+ "integrity": "sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.4.tgz",
+ "integrity": "sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.4.tgz",
+ "integrity": "sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz",
+ "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.5",
+ "enhanced-resolve": "^5.24.1",
+ "jiti": "^2.7.0",
+ "lightningcss": "1.32.0",
+ "magic-string": "^0.30.21",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz",
+ "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-x64": "4.3.3",
+ "@tailwindcss/oxide-freebsd-x64": "4.3.3",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-musl": "4.3.3",
+ "@tailwindcss/oxide-wasm32-wasi": "4.3.3",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz",
+ "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz",
+ "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz",
+ "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz",
+ "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz",
+ "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz",
+ "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz",
+ "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz",
+ "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz",
+ "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz",
+ "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.11.1",
+ "@emnapi/runtime": "^1.11.1",
+ "@emnapi/wasi-threads": "^1.2.2",
+ "@napi-rs/wasm-runtime": "^1.1.4",
+ "@tybys/wasm-util": "^0.10.2",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz",
+ "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz",
+ "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/vite": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz",
+ "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tailwindcss/node": "4.3.3",
+ "@tailwindcss/oxide": "4.3.3",
+ "tailwindcss": "4.3.3"
+ },
+ "peerDependencies": {
+ "vite": "^5.2.0 || ^6 || ^7 || ^8"
+ }
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "24.13.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
+ "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.18.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.18",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz",
+ "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.4",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz",
+ "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==",
+ "devOptional": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.17.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ }
+ },
+ "node_modules/aria-hidden": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
+ "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.11.13",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.13.tgz",
+ "integrity": "sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.8",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz",
+ "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.11.12",
+ "caniuse-lite": "^1.0.30001809",
+ "electron-to-chromium": "^1.5.402",
+ "node-releases": "^2.0.53",
+ "update-browserslist-db": "^1.3.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001809",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz",
+ "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/class-variance-authority": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+ "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "clsx": "^2.1.1"
+ },
+ "funding": {
+ "url": "https://polar.sh/cva"
+ }
+ },
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/detect-node-es": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
+ "license": "MIT"
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.405",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.405.tgz",
+ "integrity": "sha512-bNglH7lPH5l+yHOes7Zr4VqxhOy4BQ9ZBUX4VdoFgxMpzJk7W1ZoO3Vgd9Pxa9PyjQ76sfm2aKH/nzEcCNRlew==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.24.5",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz",
+ "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
+ "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.28.2",
+ "@esbuild/android-arm": "0.28.2",
+ "@esbuild/android-arm64": "0.28.2",
+ "@esbuild/android-x64": "0.28.2",
+ "@esbuild/darwin-arm64": "0.28.2",
+ "@esbuild/darwin-x64": "0.28.2",
+ "@esbuild/freebsd-arm64": "0.28.2",
+ "@esbuild/freebsd-x64": "0.28.2",
+ "@esbuild/linux-arm": "0.28.2",
+ "@esbuild/linux-arm64": "0.28.2",
+ "@esbuild/linux-ia32": "0.28.2",
+ "@esbuild/linux-loong64": "0.28.2",
+ "@esbuild/linux-mips64el": "0.28.2",
+ "@esbuild/linux-ppc64": "0.28.2",
+ "@esbuild/linux-riscv64": "0.28.2",
+ "@esbuild/linux-s390x": "0.28.2",
+ "@esbuild/linux-x64": "0.28.2",
+ "@esbuild/netbsd-arm64": "0.28.2",
+ "@esbuild/netbsd-x64": "0.28.2",
+ "@esbuild/openbsd-arm64": "0.28.2",
+ "@esbuild/openbsd-x64": "0.28.2",
+ "@esbuild/openharmony-arm64": "0.28.2",
+ "@esbuild/sunos-x64": "0.28.2",
+ "@esbuild/win32-arm64": "0.28.2",
+ "@esbuild/win32-ia32": "0.28.2",
+ "@esbuild/win32-x64": "0.28.2"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-nonce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/jiti": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
+ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/lucide-react": {
+ "version": "0.539.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.539.0.tgz",
+ "integrity": "sha512-VVISr+VF2krO91FeuCrm1rSOLACQUYVy7NQkzrOty52Y8TlTPcXcMdQFj9bYzBgXbWCiywlwSZ3Z8u6a+6bMlg==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/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,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.18",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
+ "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.53",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz",
+ "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.26",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz",
+ "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.17",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.2.8",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
+ "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.8",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz",
+ "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.8"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-remove-scroll": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz",
+ "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==",
+ "license": "MIT",
+ "dependencies": {
+ "react-remove-scroll-bar": "^2.3.7",
+ "react-style-singleton": "^2.2.3",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.3",
+ "use-sidecar": "^1.1.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-remove-scroll-bar": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
+ "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
+ "license": "MIT",
+ "dependencies": {
+ "react-style-singleton": "^2.2.2",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router": {
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.2.tgz",
+ "integrity": "sha512-aUVMjFm3GAPTTZL7oYr5E7ETiqfQCHRLH+B+5afnICvf0r7kkK4eR6SMuwbSTJw/7t+12khT/Kahij49fqOCIg==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.2.tgz",
+ "integrity": "sha512-AIKJ/jgGlFb3EbfCXk5Gzshiwt+l3mqbCrNjmEWMMjqQxNJ3svBa6bgzFyCC2Sw3RA0VWF1kg3uQf2OFhxb8hw==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.18.2"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/react-style-singleton": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
+ "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "get-nonce": "^1.0.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.62.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz",
+ "integrity": "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.9"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@napi-rs/lzma-linux-x64-gnu": "1.5.1",
+ "@rollup/rollup-android-arm-eabi": "4.62.4",
+ "@rollup/rollup-android-arm64": "4.62.4",
+ "@rollup/rollup-darwin-arm64": "4.62.4",
+ "@rollup/rollup-darwin-x64": "4.62.4",
+ "@rollup/rollup-freebsd-arm64": "4.62.4",
+ "@rollup/rollup-freebsd-x64": "4.62.4",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.62.4",
+ "@rollup/rollup-linux-arm-musleabihf": "4.62.4",
+ "@rollup/rollup-linux-arm64-gnu": "4.62.4",
+ "@rollup/rollup-linux-arm64-musl": "4.62.4",
+ "@rollup/rollup-linux-loong64-gnu": "4.62.4",
+ "@rollup/rollup-linux-loong64-musl": "4.62.4",
+ "@rollup/rollup-linux-ppc64-gnu": "4.62.4",
+ "@rollup/rollup-linux-ppc64-musl": "4.62.4",
+ "@rollup/rollup-linux-riscv64-gnu": "4.62.4",
+ "@rollup/rollup-linux-riscv64-musl": "4.62.4",
+ "@rollup/rollup-linux-s390x-gnu": "4.62.4",
+ "@rollup/rollup-linux-x64-gnu": "4.62.4",
+ "@rollup/rollup-linux-x64-musl": "4.62.4",
+ "@rollup/rollup-openbsd-x64": "4.62.4",
+ "@rollup/rollup-openharmony-arm64": "4.62.4",
+ "@rollup/rollup-win32-arm64-msvc": "4.62.4",
+ "@rollup/rollup-win32-ia32-msvc": "4.62.4",
+ "@rollup/rollup-win32-x64-gnu": "4.62.4",
+ "@rollup/rollup-win32-x64-msvc": "4.62.4",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tailwind-merge": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz",
+ "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz",
+ "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+ "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/tw-animate-css": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz",
+ "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Wombosvideo"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
+ "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz",
+ "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/use-callback-ref": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
+ "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/use-sidecar": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
+ "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "detect-node-es": "^1.1.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite": {
+ "version": "7.3.6",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz",
+ "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.27.0 || ^0.28.0",
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3",
+ "postcss": "^8.5.6",
+ "rollup": "^4.43.0",
+ "tinyglobby": "^0.2.15"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "lightningcss": "^1.21.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "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/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ }
+ }
+}
diff --git a/v2/component-library/package.json b/v2/component-library/package.json
new file mode 100644
index 0000000..1118d48
--- /dev/null
+++ b/v2/component-library/package.json
@@ -0,0 +1,43 @@
+{
+ "name": "gebos-component-library",
+ "private": true,
+ "version": "0.1.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@fontsource-variable/inter": "^5.2.5",
+ "@radix-ui/react-accordion": "^1.2.11",
+ "@radix-ui/react-checkbox": "^1.3.2",
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
+ "@radix-ui/react-label": "^2.1.7",
+ "@radix-ui/react-select": "^2.2.5",
+ "@radix-ui/react-separator": "^1.1.7",
+ "@radix-ui/react-slot": "^1.2.3",
+ "@radix-ui/react-tabs": "^1.1.12",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.539.0",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-router-dom": "^7.8.0",
+ "tailwind-merge": "^3.3.1",
+ "tw-animate-css": "^1.4.0"
+ },
+ "devDependencies": {
+ "@tailwindcss/vite": "^4.1.11",
+ "@types/node": "^24.2.0",
+ "@types/react": "^19.1.9",
+ "@types/react-dom": "^19.1.7",
+ "@vitejs/plugin-react": "^4.7.0",
+ "tailwindcss": "^4.1.11",
+ "typescript": "^5.9.2",
+ "vite": "^7.1.1"
+ },
+ "allowScripts": {
+ "esbuild@0.28.2": true
+ }
+}
diff --git a/v2/component-library/src/App.tsx b/v2/component-library/src/App.tsx
new file mode 100644
index 0000000..52448d5
--- /dev/null
+++ b/v2/component-library/src/App.tsx
@@ -0,0 +1,99 @@
+import { useEffect } from "react"
+import { BrowserRouter, Route, Routes, useLocation } from "react-router-dom"
+
+import { SiteFooter } from "@/components/gebos/site-footer"
+import { SiteHeader } from "@/components/gebos/site-header"
+import HauseigentuemerPage from "@/pages/audiences/hauseigentuemer"
+import HausverwaltungenPage from "@/pages/audiences/hausverwaltungen"
+import InstallateurePage from "@/pages/audiences/installateure"
+import MessdienstleisterPage from "@/pages/audiences/messdienstleister"
+import ConfiguratorPage from "@/pages/configurator"
+import ForWhomPage from "@/pages/for-whom"
+import HomePage from "@/pages/home"
+import HowItWorksPage from "@/pages/how-it-works"
+import KlarpreisPage from "@/pages/klarpreis"
+import { SimplePage } from "@/pages/placeholder"
+import SolutionsPage from "@/pages/solutions"
+
+function ScrollToTop() {
+ const { pathname } = useLocation()
+
+ useEffect(() => {
+ window.scrollTo(0, 0)
+ }, [pathname])
+
+ return null
+}
+
+export default function App() {
+ return (
+
+
+
+
+
+
+ } />
+ } />
+ } />
+ } />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ } />
+ } />
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+
+
+
+
+
+ )
+}
diff --git a/v2/component-library/src/assets/gebos/bar-chart.avif b/v2/component-library/src/assets/gebos/bar-chart.avif
new file mode 100644
index 0000000..e319e97
Binary files /dev/null and b/v2/component-library/src/assets/gebos/bar-chart.avif differ
diff --git a/v2/component-library/src/assets/gebos/bar-chart.webp b/v2/component-library/src/assets/gebos/bar-chart.webp
new file mode 100644
index 0000000..c48f923
Binary files /dev/null and b/v2/component-library/src/assets/gebos/bar-chart.webp differ
diff --git a/v2/component-library/src/assets/gebos/brand-cube-render.avif b/v2/component-library/src/assets/gebos/brand-cube-render.avif
new file mode 100644
index 0000000..ad77f11
Binary files /dev/null and b/v2/component-library/src/assets/gebos/brand-cube-render.avif differ
diff --git a/v2/component-library/src/assets/gebos/brand-cube-render.webp b/v2/component-library/src/assets/gebos/brand-cube-render.webp
new file mode 100644
index 0000000..db5f9a0
Binary files /dev/null and b/v2/component-library/src/assets/gebos/brand-cube-render.webp differ
diff --git a/v2/component-library/src/assets/gebos/brand-mark-3d-96.avif b/v2/component-library/src/assets/gebos/brand-mark-3d-96.avif
new file mode 100644
index 0000000..126d424
Binary files /dev/null and b/v2/component-library/src/assets/gebos/brand-mark-3d-96.avif differ
diff --git a/v2/component-library/src/assets/gebos/brand-mark-3d-96.webp b/v2/component-library/src/assets/gebos/brand-mark-3d-96.webp
new file mode 100644
index 0000000..e5948c3
Binary files /dev/null and b/v2/component-library/src/assets/gebos/brand-mark-3d-96.webp differ
diff --git a/v2/component-library/src/assets/gebos/brand-mark-3d.avif b/v2/component-library/src/assets/gebos/brand-mark-3d.avif
new file mode 100644
index 0000000..f337a4c
Binary files /dev/null and b/v2/component-library/src/assets/gebos/brand-mark-3d.avif differ
diff --git a/v2/component-library/src/assets/gebos/brand-mark-3d.webp b/v2/component-library/src/assets/gebos/brand-mark-3d.webp
new file mode 100644
index 0000000..29df102
Binary files /dev/null and b/v2/component-library/src/assets/gebos/brand-mark-3d.webp differ
diff --git a/v2/component-library/src/assets/gebos/brand-mark-flat.avif b/v2/component-library/src/assets/gebos/brand-mark-flat.avif
new file mode 100644
index 0000000..7c72a4c
Binary files /dev/null and b/v2/component-library/src/assets/gebos/brand-mark-flat.avif differ
diff --git a/v2/component-library/src/assets/gebos/brand-mark-flat.webp b/v2/component-library/src/assets/gebos/brand-mark-flat.webp
new file mode 100644
index 0000000..43b0038
Binary files /dev/null and b/v2/component-library/src/assets/gebos/brand-mark-flat.webp differ
diff --git a/v2/component-library/src/assets/gebos/building-alpha.avif b/v2/component-library/src/assets/gebos/building-alpha.avif
new file mode 100644
index 0000000..bc08f31
Binary files /dev/null and b/v2/component-library/src/assets/gebos/building-alpha.avif differ
diff --git a/v2/component-library/src/assets/gebos/building-alpha.webp b/v2/component-library/src/assets/gebos/building-alpha.webp
new file mode 100644
index 0000000..c0d3b9a
Binary files /dev/null and b/v2/component-library/src/assets/gebos/building-alpha.webp differ
diff --git a/v2/component-library/src/assets/gebos/building-iso.avif b/v2/component-library/src/assets/gebos/building-iso.avif
new file mode 100644
index 0000000..05d0fbd
Binary files /dev/null and b/v2/component-library/src/assets/gebos/building-iso.avif differ
diff --git a/v2/component-library/src/assets/gebos/building-iso.webp b/v2/component-library/src/assets/gebos/building-iso.webp
new file mode 100644
index 0000000..45fad13
Binary files /dev/null and b/v2/component-library/src/assets/gebos/building-iso.webp differ
diff --git a/v2/component-library/src/assets/gebos/building.avif b/v2/component-library/src/assets/gebos/building.avif
new file mode 100644
index 0000000..85ab5c4
Binary files /dev/null and b/v2/component-library/src/assets/gebos/building.avif differ
diff --git a/v2/component-library/src/assets/gebos/building.webp b/v2/component-library/src/assets/gebos/building.webp
new file mode 100644
index 0000000..dba0537
Binary files /dev/null and b/v2/component-library/src/assets/gebos/building.webp differ
diff --git a/v2/component-library/src/assets/gebos/check-orb.svg b/v2/component-library/src/assets/gebos/check-orb.svg
new file mode 100644
index 0000000..faf92da
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/check-orb.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/v2/component-library/src/assets/gebos/cloud-support.svg b/v2/component-library/src/assets/gebos/cloud-support.svg
new file mode 100644
index 0000000..23f714e
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/cloud-support.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/v2/component-library/src/assets/gebos/consumption-ring.svg b/v2/component-library/src/assets/gebos/consumption-ring.svg
new file mode 100644
index 0000000..1b8a2c0
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/consumption-ring.svg
@@ -0,0 +1,41 @@
+
+ GebOS segmented consumption ring
+ A substantial eight-part white, teal and translucent cyan ring in three-quarter perspective.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/v2/component-library/src/assets/gebos/cubes-round.avif b/v2/component-library/src/assets/gebos/cubes-round.avif
new file mode 100644
index 0000000..1f809d2
Binary files /dev/null and b/v2/component-library/src/assets/gebos/cubes-round.avif differ
diff --git a/v2/component-library/src/assets/gebos/cubes-round.webp b/v2/component-library/src/assets/gebos/cubes-round.webp
new file mode 100644
index 0000000..7bff0a6
Binary files /dev/null and b/v2/component-library/src/assets/gebos/cubes-round.webp differ
diff --git a/v2/component-library/src/assets/gebos/drill-tool.avif b/v2/component-library/src/assets/gebos/drill-tool.avif
new file mode 100644
index 0000000..e18c87a
Binary files /dev/null and b/v2/component-library/src/assets/gebos/drill-tool.avif differ
diff --git a/v2/component-library/src/assets/gebos/drill-tool.webp b/v2/component-library/src/assets/gebos/drill-tool.webp
new file mode 100644
index 0000000..bc0091d
Binary files /dev/null and b/v2/component-library/src/assets/gebos/drill-tool.webp differ
diff --git a/v2/component-library/src/assets/gebos/euro-orb.svg b/v2/component-library/src/assets/gebos/euro-orb.svg
new file mode 100644
index 0000000..ccd508d
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/euro-orb.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+ €
+
diff --git a/v2/component-library/src/assets/gebos/gateway.avif b/v2/component-library/src/assets/gebos/gateway.avif
new file mode 100644
index 0000000..1c3fbc2
Binary files /dev/null and b/v2/component-library/src/assets/gebos/gateway.avif differ
diff --git a/v2/component-library/src/assets/gebos/gateway.webp b/v2/component-library/src/assets/gebos/gateway.webp
new file mode 100644
index 0000000..f6112a5
Binary files /dev/null and b/v2/component-library/src/assets/gebos/gateway.webp differ
diff --git a/v2/component-library/src/assets/gebos/glass-cubes-stack.avif b/v2/component-library/src/assets/gebos/glass-cubes-stack.avif
new file mode 100644
index 0000000..3397652
Binary files /dev/null and b/v2/component-library/src/assets/gebos/glass-cubes-stack.avif differ
diff --git a/v2/component-library/src/assets/gebos/glass-cubes-stack.webp b/v2/component-library/src/assets/gebos/glass-cubes-stack.webp
new file mode 100644
index 0000000..85e62ce
Binary files /dev/null and b/v2/component-library/src/assets/gebos/glass-cubes-stack.webp differ
diff --git a/v2/component-library/src/assets/gebos/glass-cubes.svg b/v2/component-library/src/assets/gebos/glass-cubes.svg
new file mode 100644
index 0000000..b8da634
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/glass-cubes.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/v2/component-library/src/assets/gebos/heat-meter.avif b/v2/component-library/src/assets/gebos/heat-meter.avif
new file mode 100644
index 0000000..bd49b1c
Binary files /dev/null and b/v2/component-library/src/assets/gebos/heat-meter.avif differ
diff --git a/v2/component-library/src/assets/gebos/heat-meter.webp b/v2/component-library/src/assets/gebos/heat-meter.webp
new file mode 100644
index 0000000..88dca46
Binary files /dev/null and b/v2/component-library/src/assets/gebos/heat-meter.webp differ
diff --git a/v2/component-library/src/assets/gebos/icon-billing.svg b/v2/component-library/src/assets/gebos/icon-billing.svg
new file mode 100644
index 0000000..6d113ef
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/icon-billing.svg
@@ -0,0 +1 @@
+
diff --git a/v2/component-library/src/assets/gebos/icon-portal.svg b/v2/component-library/src/assets/gebos/icon-portal.svg
new file mode 100644
index 0000000..fd3a15d
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/icon-portal.svg
@@ -0,0 +1 @@
+
diff --git a/v2/component-library/src/assets/gebos/icon-radio.svg b/v2/component-library/src/assets/gebos/icon-radio.svg
new file mode 100644
index 0000000..51d2e85
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/icon-radio.svg
@@ -0,0 +1 @@
+
diff --git a/v2/component-library/src/assets/gebos/icon-smoke-alarm.svg b/v2/component-library/src/assets/gebos/icon-smoke-alarm.svg
new file mode 100644
index 0000000..fc835d5
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/icon-smoke-alarm.svg
@@ -0,0 +1 @@
+
diff --git a/v2/component-library/src/assets/gebos/icon-uvi.svg b/v2/component-library/src/assets/gebos/icon-uvi.svg
new file mode 100644
index 0000000..5c4269a
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/icon-uvi.svg
@@ -0,0 +1 @@
+
diff --git a/v2/component-library/src/assets/gebos/laptop-dashboard.avif b/v2/component-library/src/assets/gebos/laptop-dashboard.avif
new file mode 100644
index 0000000..180023d
Binary files /dev/null and b/v2/component-library/src/assets/gebos/laptop-dashboard.avif differ
diff --git a/v2/component-library/src/assets/gebos/laptop-dashboard.webp b/v2/component-library/src/assets/gebos/laptop-dashboard.webp
new file mode 100644
index 0000000..0a65dca
Binary files /dev/null and b/v2/component-library/src/assets/gebos/laptop-dashboard.webp differ
diff --git a/v2/component-library/src/assets/gebos/package-box.svg b/v2/component-library/src/assets/gebos/package-box.svg
new file mode 100644
index 0000000..7fb719c
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/package-box.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/v2/component-library/src/assets/gebos/shipping-box-closed.avif b/v2/component-library/src/assets/gebos/shipping-box-closed.avif
new file mode 100644
index 0000000..454dacc
Binary files /dev/null and b/v2/component-library/src/assets/gebos/shipping-box-closed.avif differ
diff --git a/v2/component-library/src/assets/gebos/shipping-box-closed.webp b/v2/component-library/src/assets/gebos/shipping-box-closed.webp
new file mode 100644
index 0000000..2e461dd
Binary files /dev/null and b/v2/component-library/src/assets/gebos/shipping-box-closed.webp differ
diff --git a/v2/component-library/src/assets/gebos/shipping-box-meters.avif b/v2/component-library/src/assets/gebos/shipping-box-meters.avif
new file mode 100644
index 0000000..fb3b499
Binary files /dev/null and b/v2/component-library/src/assets/gebos/shipping-box-meters.avif differ
diff --git a/v2/component-library/src/assets/gebos/shipping-box-meters.webp b/v2/component-library/src/assets/gebos/shipping-box-meters.webp
new file mode 100644
index 0000000..64038de
Binary files /dev/null and b/v2/component-library/src/assets/gebos/shipping-box-meters.webp differ
diff --git a/v2/component-library/src/assets/gebos/smoke-alarm.avif b/v2/component-library/src/assets/gebos/smoke-alarm.avif
new file mode 100644
index 0000000..b48da37
Binary files /dev/null and b/v2/component-library/src/assets/gebos/smoke-alarm.avif differ
diff --git a/v2/component-library/src/assets/gebos/smoke-alarm.webp b/v2/component-library/src/assets/gebos/smoke-alarm.webp
new file mode 100644
index 0000000..b204345
Binary files /dev/null and b/v2/component-library/src/assets/gebos/smoke-alarm.webp differ
diff --git a/v2/component-library/src/assets/gebos/teal-bars.svg b/v2/component-library/src/assets/gebos/teal-bars.svg
new file mode 100644
index 0000000..5a0f43a
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/teal-bars.svg
@@ -0,0 +1,18 @@
+
+ GebOS translucent data bars
+ Five translucent teal isometric bars of increasing height.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/v2/component-library/src/assets/gebos/uvi-badge.svg b/v2/component-library/src/assets/gebos/uvi-badge.svg
new file mode 100644
index 0000000..9e68439
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/uvi-badge.svg
@@ -0,0 +1,22 @@
+
+ GebOS UVI sensor badge
+ A white sensor with a teal consumption display and wireless symbol.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/v2/component-library/src/assets/gebos/wireless-orb.svg b/v2/component-library/src/assets/gebos/wireless-orb.svg
new file mode 100644
index 0000000..13be9de
--- /dev/null
+++ b/v2/component-library/src/assets/gebos/wireless-orb.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/v2/component-library/src/assets/gebos/wordmark-cubes-dark.avif b/v2/component-library/src/assets/gebos/wordmark-cubes-dark.avif
new file mode 100644
index 0000000..fe33fb8
Binary files /dev/null and b/v2/component-library/src/assets/gebos/wordmark-cubes-dark.avif differ
diff --git a/v2/component-library/src/assets/gebos/wordmark-cubes-dark.webp b/v2/component-library/src/assets/gebos/wordmark-cubes-dark.webp
new file mode 100644
index 0000000..74fec94
Binary files /dev/null and b/v2/component-library/src/assets/gebos/wordmark-cubes-dark.webp differ
diff --git a/v2/component-library/src/assets/gebos/wordmark-cubes-glow.avif b/v2/component-library/src/assets/gebos/wordmark-cubes-glow.avif
new file mode 100644
index 0000000..53d39b8
Binary files /dev/null and b/v2/component-library/src/assets/gebos/wordmark-cubes-glow.avif differ
diff --git a/v2/component-library/src/assets/gebos/wordmark-cubes-glow.webp b/v2/component-library/src/assets/gebos/wordmark-cubes-glow.webp
new file mode 100644
index 0000000..ce2a4a5
Binary files /dev/null and b/v2/component-library/src/assets/gebos/wordmark-cubes-glow.webp differ
diff --git a/v2/component-library/src/assets/gebos/worker-tablet.avif b/v2/component-library/src/assets/gebos/worker-tablet.avif
new file mode 100644
index 0000000..640ba96
Binary files /dev/null and b/v2/component-library/src/assets/gebos/worker-tablet.avif differ
diff --git a/v2/component-library/src/assets/gebos/worker-tablet.webp b/v2/component-library/src/assets/gebos/worker-tablet.webp
new file mode 100644
index 0000000..0e8c0d4
Binary files /dev/null and b/v2/component-library/src/assets/gebos/worker-tablet.webp differ
diff --git a/v2/component-library/src/components/gebos/checklist.tsx b/v2/component-library/src/components/gebos/checklist.tsx
new file mode 100644
index 0000000..5ed1bc1
--- /dev/null
+++ b/v2/component-library/src/components/gebos/checklist.tsx
@@ -0,0 +1,37 @@
+import * as React from "react"
+import { CircleCheck } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+function ChecklistItem({
+ children,
+ className,
+}: {
+ children: React.ReactNode
+ className?: string
+}) {
+ return (
+
+
+ {children}
+
+ )
+}
+
+function Checklist({
+ items,
+ className,
+}: {
+ items: React.ReactNode[]
+ className?: string
+}) {
+ return (
+
+ {items.map((item, i) => (
+ {item}
+ ))}
+
+ )
+}
+
+export { Checklist, ChecklistItem }
diff --git a/v2/component-library/src/components/gebos/cta-banner.tsx b/v2/component-library/src/components/gebos/cta-banner.tsx
new file mode 100644
index 0000000..5a6090d
--- /dev/null
+++ b/v2/component-library/src/components/gebos/cta-banner.tsx
@@ -0,0 +1,50 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+import { IconBadge } from "@/components/gebos/icon-tile"
+
+/**
+ * Teal gradient call-to-action band:
+ * glassy icon disc · bold white title + muted subline · actions right.
+ */
+function CtaBanner({
+ icon,
+ title,
+ description,
+ actions,
+ className,
+}: {
+ icon: React.ReactNode
+ title: React.ReactNode
+ description?: React.ReactNode
+ actions: React.ReactNode
+ className?: string
+}) {
+ return (
+
+
+ {icon}
+
+
+
+ {title}
+
+ {description ? (
+
+ {description}
+
+ ) : null}
+
+
+ {actions}
+
+
+ )
+}
+
+export { CtaBanner }
diff --git a/v2/component-library/src/components/gebos/hero-art.tsx b/v2/component-library/src/components/gebos/hero-art.tsx
new file mode 100644
index 0000000..9cd6df4
--- /dev/null
+++ b/v2/component-library/src/components/gebos/hero-art.tsx
@@ -0,0 +1,63 @@
+import { cn } from "@/lib/utils"
+
+import buildingAvif from "@/assets/gebos/building.avif"
+import buildingWebp from "@/assets/gebos/building.webp"
+import consumptionRing from "@/assets/gebos/consumption-ring.svg"
+import smokeAlarmAvif from "@/assets/gebos/smoke-alarm.avif"
+import smokeAlarmWebp from "@/assets/gebos/smoke-alarm.webp"
+import tealBars from "@/assets/gebos/teal-bars.svg"
+import uviBadge from "@/assets/gebos/uvi-badge.svg"
+
+/**
+ * Homepage hero composition from the GebOS visual asset kit:
+ * building render (white matte → mix-blend-multiply), smoke alarm,
+ * translucent data bars, UVI badge and consumption ring.
+ * Layout mirrors the kit's demo.html so proportions can be tuned
+ * without rerendering.
+ */
+function HeroArt({ className }: { className?: string }) {
+ return (
+
+ )
+}
+
+export { HeroArt }
diff --git a/v2/component-library/src/components/gebos/hero-visual.tsx b/v2/component-library/src/components/gebos/hero-visual.tsx
new file mode 100644
index 0000000..145fcc6
--- /dev/null
+++ b/v2/component-library/src/components/gebos/hero-visual.tsx
@@ -0,0 +1,84 @@
+import * as React from "react"
+import { CircleCheck, Wifi } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+import { IconBadge } from "@/components/gebos/icon-tile"
+import {
+ BuildingIllustration,
+ DonutIllustration,
+} from "@/components/gebos/illustrations"
+
+/**
+ * Floating status chip ("Inspektion OK · 06.05.2024") used on hero visuals.
+ */
+function StatusChip({
+ title,
+ sub,
+ className,
+}: {
+ title: React.ReactNode
+ sub?: React.ReactNode
+ className?: string
+}) {
+ return (
+
+
+
+
+
+
{title}
+ {sub ? (
+
{sub}
+ ) : null}
+
+
+ )
+}
+
+/**
+ * Reusable hero composition standing in for the 3D building renders:
+ * glow stage, building, floating status card, signal chip and donut.
+ * `media` swaps the centre illustration.
+ */
+function HeroVisual({
+ media,
+ chipTitle = "Inspektion OK",
+ chipSub = "Letzte Prüfung 06.05.2024",
+ className,
+}: {
+ media?: React.ReactNode
+ chipTitle?: React.ReactNode
+ chipSub?: React.ReactNode
+ className?: string
+}) {
+ return (
+
+ {/* stage */}
+
+
+ {media ?? }
+
+ {/* floating elements */}
+
+
+
+
+
+
+ )
+}
+
+export { HeroVisual, StatusChip }
diff --git a/v2/component-library/src/components/gebos/icon-tile.tsx b/v2/component-library/src/components/gebos/icon-tile.tsx
new file mode 100644
index 0000000..f88a7b6
--- /dev/null
+++ b/v2/component-library/src/components/gebos/icon-tile.tsx
@@ -0,0 +1,97 @@
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const iconBadgeVariants = cva(
+ "flex shrink-0 items-center justify-center [&_svg]:shrink-0",
+ {
+ variants: {
+ variant: {
+ /* soft teal disc */
+ soft: "bg-accent text-brand-700",
+ /* white disc with hairline + teal line icon (feature rows) */
+ outline: "border border-brand-100 bg-card text-primary shadow-pill",
+ solid: "bg-primary text-primary-foreground",
+ navy: "bg-navy text-white",
+ /* translucent white on gradient bands */
+ glass: "bg-white/15 text-white ring-1 ring-white/25",
+ },
+ size: {
+ sm: "size-9 [&_svg]:size-4",
+ md: "size-11 [&_svg]:size-5",
+ lg: "size-14 [&_svg]:size-6",
+ xl: "size-16 [&_svg]:size-7",
+ },
+ shape: {
+ circle: "rounded-full",
+ squircle: "rounded-xl",
+ },
+ },
+ defaultVariants: {
+ variant: "soft",
+ size: "md",
+ shape: "circle",
+ },
+ }
+)
+
+function IconBadge({
+ className,
+ variant,
+ size,
+ shape,
+ ...props
+}: React.ComponentProps<"div"> & VariantProps) {
+ return (
+
+ )
+}
+
+/**
+ * Icon-over-label tile used in the feature rows underneath heroes
+ * (UVI · Heizkostenabrechnung · Rauchwarnmelder · …).
+ */
+function FeatureTile({
+ icon,
+ media,
+ title,
+ sub,
+ align = "center",
+ className,
+}: {
+ icon?: React.ReactNode
+ /** self-contained visual (e.g. asset-kit icon) rendered without IconBadge */
+ media?: React.ReactNode
+ title: React.ReactNode
+ sub?: React.ReactNode
+ align?: "center" | "start"
+ className?: string
+}) {
+ return (
+
+ {media ?? (
+
+ {icon}
+
+ )}
+
{title}
+ {sub ? (
+
+ {sub}
+
+ ) : null}
+
+ )
+}
+
+export { IconBadge, iconBadgeVariants, FeatureTile }
diff --git a/v2/component-library/src/components/gebos/illustrations.tsx b/v2/component-library/src/components/gebos/illustrations.tsx
new file mode 100644
index 0000000..bbd42f0
--- /dev/null
+++ b/v2/component-library/src/components/gebos/illustrations.tsx
@@ -0,0 +1,154 @@
+import * as React from "react"
+
+/**
+ * Lightweight SVG stand-ins for the 3D renders in the designs.
+ * All of them draw exclusively from the chart/brand tokens.
+ */
+
+/** Smoke detector: white disc, vent ring, teal status LED. */
+function SmokeDetectorIllustration({ className }: { className?: string }) {
+ const vents = Array.from({ length: 12 }, (_, i) => {
+ const a = (i / 12) * Math.PI * 2
+ return (
+
+ )
+ })
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {vents}
+
+
+
+ )
+}
+
+/** Cluster of translucent isometric sensor cubes (UVI). */
+function SensorCubesIllustration({ className }: { className?: string }) {
+ const cube = (x: number, y: number, s: number, o: number) => (
+
+
+
+
+
+ )
+
+ return (
+
+
+ {cube(12, 12, 1.1, 0.55)}
+ {cube(58, 30, 1.0, 0.8)}
+ {cube(26, 56, 1.3, 1)}
+
+
+ )
+}
+
+/** Donut chart in brand tones (portfolio / reporting motif). */
+function DonutIllustration({ className }: { className?: string }) {
+ /* three segments: 55% teal, 25% light, 20% pale */
+ const C = 2 * Math.PI * 40
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+/** Stylised apartment building: white slabs, window grid, teal accents. */
+function BuildingIllustration({ className }: { className?: string }) {
+ const windows: React.ReactNode[] = []
+ for (let row = 0; row < 5; row++) {
+ for (let col = 0; col < 4; col++) {
+ windows.push(
+
+ )
+ }
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ {windows}
+ {/* balcony bands */}
+
+
+ {/* entrance */}
+
+
+ )
+}
+
+export {
+ SmokeDetectorIllustration,
+ SensorCubesIllustration,
+ DonutIllustration,
+ BuildingIllustration,
+}
diff --git a/v2/component-library/src/components/gebos/logo.tsx b/v2/component-library/src/components/gebos/logo.tsx
new file mode 100644
index 0000000..26262cc
--- /dev/null
+++ b/v2/component-library/src/components/gebos/logo.tsx
@@ -0,0 +1,98 @@
+import mark3dAvif from "@/assets/gebos/brand-mark-3d-96.avif"
+import mark3dWebp from "@/assets/gebos/brand-mark-3d-96.webp"
+
+import { cn } from "@/lib/utils"
+
+/**
+ * GebOS brand mark: isometric cube inside a hexagon, teal gradient stroke,
+ * followed by the two-tone wordmark ("Geb" navy / "OS" teal).
+ */
+function LogoMark({ className }: { className?: string }) {
+ return (
+
+
+
+
+
+
+
+
+ {/* top face */}
+
+ {/* hexagon silhouette */}
+
+ {/* inner cube edges */}
+
+
+ )
+}
+
+/** 3D glass brand mark (rendered asset, genuine alpha). */
+function LogoMark3d({ className }: { className?: string }) {
+ return (
+
+
+
+
+ )
+}
+
+function Logo({
+ className,
+ markClassName,
+ inverse = false,
+ mark = "line",
+}: {
+ className?: string
+ markClassName?: string
+ inverse?: boolean
+ /** "line" = flat SVG mark, "3d" = glass render */
+ mark?: "line" | "3d"
+}) {
+ return (
+
+ {mark === "3d" ? (
+
+ ) : (
+
+ )}
+
+ Geb
+ OS
+
+
+ )
+}
+
+export { Logo, LogoMark, LogoMark3d }
diff --git a/v2/component-library/src/components/gebos/page-breadcrumb.tsx b/v2/component-library/src/components/gebos/page-breadcrumb.tsx
new file mode 100644
index 0000000..797e17e
--- /dev/null
+++ b/v2/component-library/src/components/gebos/page-breadcrumb.tsx
@@ -0,0 +1,55 @@
+import { Fragment } from "react"
+import { Link } from "react-router-dom"
+
+import {
+ Breadcrumb,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbList,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+} from "@/components/ui/breadcrumb"
+
+export interface Crumb {
+ label: string
+ /** omit on the last crumb – it renders as the current page */
+ to?: string
+}
+
+/**
+ * Site-wide breadcrumb trail: parent chain → current page.
+ * Top-level pages start at "Startseite", audience pages at "Für wen?".
+ */
+function PageBreadcrumb({
+ items,
+ className,
+}: {
+ items: Crumb[]
+ className?: string
+}) {
+ return (
+
+
+ {items.map((item, i) => {
+ const last = i === items.length - 1
+ return (
+
+
+ {last || !item.to ? (
+ {item.label}
+ ) : (
+
+ {item.label}
+
+ )}
+
+ {last ? null : }
+
+ )
+ })}
+
+
+ )
+}
+
+export { PageBreadcrumb }
diff --git a/v2/component-library/src/components/gebos/page-hero.tsx b/v2/component-library/src/components/gebos/page-hero.tsx
new file mode 100644
index 0000000..9be6e4e
--- /dev/null
+++ b/v2/component-library/src/components/gebos/page-hero.tsx
@@ -0,0 +1,62 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+import { Container } from "@/components/gebos/section"
+
+/**
+ * Split hero: copy left (breadcrumb/eyebrow, H1, lead, CTAs, extra),
+ * visual right, soft radial glow behind.
+ */
+function PageHero({
+ breadcrumb,
+ title,
+ lead,
+ actions,
+ extra,
+ visual,
+ className,
+}: {
+ breadcrumb?: React.ReactNode
+ title: React.ReactNode
+ lead?: React.ReactNode
+ actions?: React.ReactNode
+ /** slot below the actions (e.g. hint pill) */
+ extra?: React.ReactNode
+ visual?: React.ReactNode
+ className?: string
+}) {
+ return (
+
+ {breadcrumb ? (
+
{breadcrumb}
+ ) : null}
+
+
+
+ {title}
+
+ {lead ? (
+
+ {lead}
+
+ ) : null}
+ {actions ? (
+
+ {actions}
+
+ ) : null}
+ {extra ?
{extra}
: null}
+
+ {visual ? {visual}
: null}
+
+
+ )
+}
+
+export { PageHero }
diff --git a/v2/component-library/src/components/gebos/price-card.tsx b/v2/component-library/src/components/gebos/price-card.tsx
new file mode 100644
index 0000000..de03319
--- /dev/null
+++ b/v2/component-library/src/components/gebos/price-card.tsx
@@ -0,0 +1,65 @@
+import * as React from "react"
+import { Ban, CircleCheck } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+import { Badge } from "@/components/ui/badge"
+import { Card } from "@/components/ui/card"
+import { Separator } from "@/components/ui/separator"
+
+/**
+ * Klarpreis pricing card:
+ * title · cadence pill · large price + unit · allocability pill ·
+ * divider · description. Optional media floats top-right.
+ */
+function PriceCard({
+ title,
+ cadence,
+ price,
+ unit,
+ allocation,
+ description,
+ media,
+ className,
+}: {
+ title: React.ReactNode
+ /** "Einmalig" | "Monatlich" pill under the title */
+ cadence: React.ReactNode
+ price: React.ReactNode
+ unit: React.ReactNode
+ /** umlagefähig? tone drives soft-teal vs. soft-red pill */
+ allocation: { label: React.ReactNode; tone: "positive" | "negative" }
+ description: React.ReactNode
+ media?: React.ReactNode
+ className?: string
+}) {
+ return (
+
+ {media ? (
+
+ {media}
+
+ ) : null}
+
+ {title}
+
+ {cadence}
+
+ {price}
+
+ {unit}
+
+ {allocation.tone === "positive" ? : }
+ {allocation.label}
+
+
+
+ {description}
+
+
+ )
+}
+
+export { PriceCard }
diff --git a/v2/component-library/src/components/gebos/process-steps.tsx b/v2/component-library/src/components/gebos/process-steps.tsx
new file mode 100644
index 0000000..1a1dfaa
--- /dev/null
+++ b/v2/component-library/src/components/gebos/process-steps.tsx
@@ -0,0 +1,97 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+import { IconBadge } from "@/components/gebos/icon-tile"
+
+export interface ProcessStep {
+ icon?: React.ReactNode
+ /** self-contained visual (asset render/vector) shown instead of IconBadge */
+ media?: React.ReactNode
+ title: React.ReactNode
+ description?: React.ReactNode
+}
+
+/**
+ * Numbered process row ("So funktioniert GebOS", steps 1–5):
+ * numbered chips joined by a dotted teal line, device icon, title, copy.
+ */
+function ProcessSteps({
+ steps,
+ className,
+}: {
+ steps: ProcessStep[]
+ className?: string
+}) {
+ return (
+ = 5 ? "lg:grid-cols-5" : "lg:grid-cols-4",
+ className
+ )}
+ >
+
+ {steps.map((step, i) => (
+
+
+ {i + 1}
+
+ {step.media ?? (
+
+ {step.icon}
+
+ )}
+ {step.title}
+ {step.description ? (
+
+ {step.description}
+
+ ) : null}
+
+ ))}
+
+ )
+}
+
+/**
+ * Vertical variant used by the Konfigurator overview (steps 1–4).
+ */
+function NumberedList({
+ steps,
+ className,
+}: {
+ steps: { title: React.ReactNode; description?: React.ReactNode }[]
+ className?: string
+}) {
+ return (
+
+
+ {steps.map((step, i) => (
+
+
+ {i + 1}
+
+
+
{step.title}
+ {step.description ? (
+
+ {step.description}
+
+ ) : null}
+
+
+ ))}
+
+ )
+}
+
+export { ProcessSteps, NumberedList }
diff --git a/v2/component-library/src/components/gebos/section.tsx b/v2/component-library/src/components/gebos/section.tsx
new file mode 100644
index 0000000..9eb07f6
--- /dev/null
+++ b/v2/component-library/src/components/gebos/section.tsx
@@ -0,0 +1,64 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Container({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function Section({ className, ...props }: React.ComponentProps<"section">) {
+ return (
+
+ )
+}
+
+/**
+ * Standard section intro: optional teal eyebrow, navy title, muted lead.
+ */
+function SectionHeading({
+ eyebrow,
+ title,
+ lead,
+ align = "left",
+ className,
+}: {
+ eyebrow?: React.ReactNode
+ title: React.ReactNode
+ lead?: React.ReactNode
+ align?: "left" | "center"
+ className?: string
+}) {
+ return (
+
+ {eyebrow ? (
+
+ {eyebrow}
+
+ ) : null}
+
+ {title}
+
+ {lead ? (
+
+ {lead}
+
+ ) : null}
+
+ )
+}
+
+export { Container, Section, SectionHeading }
diff --git a/v2/component-library/src/components/gebos/site-assets.tsx b/v2/component-library/src/components/gebos/site-assets.tsx
new file mode 100644
index 0000000..378719b
--- /dev/null
+++ b/v2/component-library/src/components/gebos/site-assets.tsx
@@ -0,0 +1,253 @@
+import { cn } from "@/lib/utils"
+
+import barChartAvif from "@/assets/gebos/bar-chart.avif"
+import barChartWebp from "@/assets/gebos/bar-chart.webp"
+import brandCubeAvif from "@/assets/gebos/brand-cube-render.avif"
+import brandCubeWebp from "@/assets/gebos/brand-cube-render.webp"
+import brandMark3dAvif from "@/assets/gebos/brand-mark-3d.avif"
+import brandMark3dWebp from "@/assets/gebos/brand-mark-3d.webp"
+import brandMarkFlatAvif from "@/assets/gebos/brand-mark-flat.avif"
+import brandMarkFlatWebp from "@/assets/gebos/brand-mark-flat.webp"
+import buildingAlphaAvif from "@/assets/gebos/building-alpha.avif"
+import buildingAlphaWebp from "@/assets/gebos/building-alpha.webp"
+import buildingIsoAvif from "@/assets/gebos/building-iso.avif"
+import buildingIsoWebp from "@/assets/gebos/building-iso.webp"
+import buildingAvif from "@/assets/gebos/building.avif"
+import buildingWebp from "@/assets/gebos/building.webp"
+import checkOrb from "@/assets/gebos/check-orb.svg"
+import cloudSupport from "@/assets/gebos/cloud-support.svg"
+import consumptionRing from "@/assets/gebos/consumption-ring.svg"
+import cubesRoundAvif from "@/assets/gebos/cubes-round.avif"
+import cubesRoundWebp from "@/assets/gebos/cubes-round.webp"
+import drillToolAvif from "@/assets/gebos/drill-tool.avif"
+import drillToolWebp from "@/assets/gebos/drill-tool.webp"
+import euroOrb from "@/assets/gebos/euro-orb.svg"
+import gatewayAvif from "@/assets/gebos/gateway.avif"
+import gatewayWebp from "@/assets/gebos/gateway.webp"
+import glassCubes from "@/assets/gebos/glass-cubes.svg"
+import glassCubesStackAvif from "@/assets/gebos/glass-cubes-stack.avif"
+import glassCubesStackWebp from "@/assets/gebos/glass-cubes-stack.webp"
+import heatMeterAvif from "@/assets/gebos/heat-meter.avif"
+import heatMeterWebp from "@/assets/gebos/heat-meter.webp"
+import iconBilling from "@/assets/gebos/icon-billing.svg"
+import iconPortal from "@/assets/gebos/icon-portal.svg"
+import iconRadio from "@/assets/gebos/icon-radio.svg"
+import iconSmokeAlarm from "@/assets/gebos/icon-smoke-alarm.svg"
+import iconUvi from "@/assets/gebos/icon-uvi.svg"
+import laptopAvif from "@/assets/gebos/laptop-dashboard.avif"
+import laptopWebp from "@/assets/gebos/laptop-dashboard.webp"
+import packageBox from "@/assets/gebos/package-box.svg"
+import shippingBoxClosedAvif from "@/assets/gebos/shipping-box-closed.avif"
+import shippingBoxClosedWebp from "@/assets/gebos/shipping-box-closed.webp"
+import shippingBoxMetersAvif from "@/assets/gebos/shipping-box-meters.avif"
+import shippingBoxMetersWebp from "@/assets/gebos/shipping-box-meters.webp"
+import smokeAlarmAvif from "@/assets/gebos/smoke-alarm.avif"
+import smokeAlarmWebp from "@/assets/gebos/smoke-alarm.webp"
+import tealBars from "@/assets/gebos/teal-bars.svg"
+import uviBadge from "@/assets/gebos/uvi-badge.svg"
+import wirelessOrb from "@/assets/gebos/wireless-orb.svg"
+import wordmarkDarkAvif from "@/assets/gebos/wordmark-cubes-dark.avif"
+import wordmarkDarkWebp from "@/assets/gebos/wordmark-cubes-dark.webp"
+import wordmarkGlowAvif from "@/assets/gebos/wordmark-cubes-glow.avif"
+import wordmarkGlowWebp from "@/assets/gebos/wordmark-cubes-glow.webp"
+import workerTabletAvif from "@/assets/gebos/worker-tablet.avif"
+import workerTabletWebp from "@/assets/gebos/worker-tablet.webp"
+
+export interface RenderAsset {
+ avif: string
+ webp: string
+ alt: string
+ /**
+ * "white" – pure-white matte, needs multiply blending to sit on light surfaces.
+ * "alpha" – genuine transparency, composited as-is.
+ */
+ matte: "white" | "alpha"
+}
+
+/**
+ * Photographic / 3D renders. Always draw through , which picks
+ * the right compositing mode for the asset's matte.
+ */
+const renders = {
+ /* --- site kit: white-matte masters --------------------------------- */
+ building: {
+ avif: buildingAvif,
+ webp: buildingWebp,
+ alt: "Modernes Mehrfamilienhaus",
+ matte: "white",
+ },
+ smokeAlarm: {
+ avif: smokeAlarmAvif,
+ webp: smokeAlarmWebp,
+ alt: "Rauchwarnmelder",
+ matte: "white",
+ },
+ gateway: {
+ avif: gatewayAvif,
+ webp: gatewayWebp,
+ alt: "GebOS Gateway",
+ matte: "white",
+ },
+ heatMeter: {
+ avif: heatMeterAvif,
+ webp: heatMeterWebp,
+ alt: "Wärmemengenzähler",
+ matte: "white",
+ },
+ laptopDashboard: {
+ avif: laptopAvif,
+ webp: laptopWebp,
+ alt: "GebOS Portal auf dem Laptop",
+ matte: "white",
+ },
+ brandCube: {
+ avif: brandCubeAvif,
+ webp: brandCubeWebp,
+ alt: "",
+ matte: "white",
+ },
+ shippingBoxMeters: {
+ avif: shippingBoxMetersAvif,
+ webp: shippingBoxMetersWebp,
+ alt: "Objektbezogen vorbereitete Hardware",
+ matte: "white",
+ },
+
+ /* --- transparent renders (free placement, any background) ---------- */
+ /** same subject as `building`, but with genuine alpha – safe on any surface */
+ buildingAlpha: {
+ avif: buildingAlphaAvif,
+ webp: buildingAlphaWebp,
+ alt: "Modernes Mehrfamilienhaus",
+ matte: "alpha",
+ },
+ /** isometric corner view of the same building type, genuine alpha */
+ buildingIso: {
+ avif: buildingIsoAvif,
+ webp: buildingIsoWebp,
+ alt: "Modernes Mehrfamilienhaus",
+ matte: "alpha",
+ },
+ brandMark3d: {
+ avif: brandMark3dAvif,
+ webp: brandMark3dWebp,
+ alt: "GebOS Markenzeichen",
+ matte: "alpha",
+ },
+ brandMarkFlat: {
+ avif: brandMarkFlatAvif,
+ webp: brandMarkFlatWebp,
+ alt: "GebOS Markenzeichen",
+ matte: "alpha",
+ },
+ glassCubesStack: {
+ avif: glassCubesStackAvif,
+ webp: glassCubesStackWebp,
+ alt: "",
+ matte: "alpha",
+ },
+ cubesRound: {
+ avif: cubesRoundAvif,
+ webp: cubesRoundWebp,
+ alt: "",
+ matte: "alpha",
+ },
+ barChart: {
+ avif: barChartAvif,
+ webp: barChartWebp,
+ alt: "",
+ matte: "alpha",
+ },
+ drillTool: {
+ avif: drillToolAvif,
+ webp: drillToolWebp,
+ alt: "",
+ matte: "alpha",
+ },
+ workerTablet: {
+ avif: workerTabletAvif,
+ webp: workerTabletWebp,
+ alt: "Monteur mit Tablet",
+ matte: "alpha",
+ },
+ shippingBoxClosed: {
+ avif: shippingBoxClosedAvif,
+ webp: shippingBoxClosedWebp,
+ alt: "Vorkonfigurierte Lieferung",
+ matte: "alpha",
+ },
+ /** baked light glow – use on white/near-white surfaces */
+ wordmarkGlow: {
+ avif: wordmarkGlowAvif,
+ webp: wordmarkGlowWebp,
+ alt: "GebOS",
+ matte: "alpha",
+ },
+ /** baked dark glow – use on navy/dark surfaces */
+ wordmarkDark: {
+ avif: wordmarkDarkAvif,
+ webp: wordmarkDarkWebp,
+ alt: "GebOS",
+ matte: "alpha",
+ },
+} satisfies Record
+
+/** Transparent brand vectors (decorative; render as plain ). */
+const vectors = {
+ tealBars,
+ uviBadge,
+ consumptionRing,
+ glassCubes,
+ checkOrb,
+ euroOrb,
+ cloudSupport,
+ packageBox,
+ wirelessOrb,
+}
+
+/** Feature icons with baked-in pale disc (use in FeatureTile `media`). */
+const icons = {
+ uvi: iconUvi,
+ billing: iconBilling,
+ smokeAlarm: iconSmokeAlarm,
+ radio: iconRadio,
+ portal: iconPortal,
+}
+
+/**
+ * Renders a kit asset as AVIF→WebP . White-matte masters get
+ * mix-blend-multiply so their matte disappears on light surfaces;
+ * transparent assets composite normally.
+ */
+function AssetRender({
+ render,
+ alt,
+ className,
+ imgClassName,
+ loading = "lazy",
+}: {
+ render: RenderAsset
+ /** override the registry alt (e.g. decorative usage) */
+ alt?: string
+ className?: string
+ imgClassName?: string
+ loading?: "lazy" | "eager"
+}) {
+ return (
+
+
+
+
+ )
+}
+
+export { AssetRender, icons, renders, vectors }
diff --git a/v2/component-library/src/components/gebos/site-footer.tsx b/v2/component-library/src/components/gebos/site-footer.tsx
new file mode 100644
index 0000000..749a498
--- /dev/null
+++ b/v2/component-library/src/components/gebos/site-footer.tsx
@@ -0,0 +1,76 @@
+import { Link } from "react-router-dom"
+
+import { Logo } from "@/components/gebos/logo"
+import { Container } from "@/components/gebos/section"
+
+const COLUMNS: { title: string; links: { to: string; label: string }[] }[] = [
+ {
+ title: "Produkt",
+ links: [
+ { to: "/loesungen", label: "Lösungen" },
+ { to: "/so-funktionierts", label: "So funktioniert’s" },
+ { to: "/konfigurator", label: "Konfigurator" },
+ { to: "/klarpreis", label: "GebOS Klarpreis" },
+ ],
+ },
+ {
+ title: "Für wen?",
+ links: [
+ { to: "/fuer-wen", label: "Übersicht" },
+ { to: "/fuer-wen/hauseigentuemer", label: "Hauseigentümer" },
+ { to: "/fuer-wen/hausverwaltungen", label: "Hausverwaltungen" },
+ { to: "/fuer-wen/messdienstleister", label: "Messdienstleister" },
+ { to: "/fuer-wen/installateure", label: "Installateure & Heizungsbauer" },
+ ],
+ },
+ {
+ title: "Unternehmen",
+ links: [
+ { to: "/unternehmen", label: "Über GebOS" },
+ { to: "/kontakt", label: "Kontakt" },
+ ],
+ },
+]
+
+function SiteFooter() {
+ return (
+
+ )
+}
+
+export { SiteFooter }
diff --git a/v2/component-library/src/components/gebos/site-header.tsx b/v2/component-library/src/components/gebos/site-header.tsx
new file mode 100644
index 0000000..c127f43
--- /dev/null
+++ b/v2/component-library/src/components/gebos/site-header.tsx
@@ -0,0 +1,148 @@
+import { ChevronDown, Menu } from "lucide-react"
+import { Link, NavLink, useLocation } from "react-router-dom"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+import { Logo } from "@/components/gebos/logo"
+import { Container } from "@/components/gebos/section"
+
+const AUDIENCES = [
+ { to: "/fuer-wen/hauseigentuemer", label: "Hauseigentümer" },
+ { to: "/fuer-wen/hausverwaltungen", label: "Hausverwaltungen" },
+ { to: "/fuer-wen/messdienstleister", label: "Messdienstleister" },
+ { to: "/fuer-wen/installateure", label: "Installateure & Heizungsbauer" },
+]
+
+const NAV_LINKS = [
+ { to: "/loesungen", label: "Lösungen" },
+ { to: "/so-funktionierts", label: "So funktioniert’s" },
+ /* "Für wen?" rendered separately as dropdown */
+ { to: "/konfigurator", label: "Konfigurator" },
+ { to: "/unternehmen", label: "Unternehmen" },
+ { to: "/kontakt", label: "Kontakt" },
+]
+
+const navItemClass = (active: boolean) =>
+ cn(
+ "rounded-full px-3 py-1.5 text-sm font-medium transition-colors",
+ active
+ ? "bg-accent font-semibold text-brand-800 ring-1 ring-brand-200"
+ : "text-foreground/70 hover:text-navy"
+ )
+
+function ForWhomMenu() {
+ const { pathname } = useLocation()
+ const active = pathname.startsWith("/fuer-wen")
+
+ return (
+
+
+ Für wen?
+
+
+
+
+ Übersicht
+
+
+ {AUDIENCES.map((a) => (
+
+ {a.label}
+
+ ))}
+
+
+ )
+}
+
+function MobileMenu() {
+ return (
+
+
+
+
+ Menü öffnen
+
+
+
+ {NAV_LINKS.slice(0, 2).map((l) => (
+
+ {l.label}
+
+ ))}
+
+ Für wen?
+
+ Übersicht
+
+ {AUDIENCES.map((a) => (
+
+ {a.label}
+
+ ))}
+
+ {NAV_LINKS.slice(2).map((l) => (
+
+ {l.label}
+
+ ))}
+
+
+ Klarpreis
+
+
+
+ )
+}
+
+function SiteHeader() {
+ return (
+
+ )
+}
+
+export { SiteHeader }
diff --git a/v2/component-library/src/components/ui/accordion.tsx b/v2/component-library/src/components/ui/accordion.tsx
new file mode 100644
index 0000000..920eca8
--- /dev/null
+++ b/v2/component-library/src/components/ui/accordion.tsx
@@ -0,0 +1,66 @@
+import * as React from "react"
+import * as AccordionPrimitive from "@radix-ui/react-accordion"
+import { ChevronDownIcon } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+function Accordion({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function AccordionItem({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AccordionTrigger({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ svg]:rotate-180",
+ className
+ )}
+ {...props}
+ >
+ {children}
+
+
+
+ )
+}
+
+function AccordionContent({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
diff --git a/v2/component-library/src/components/ui/badge.tsx b/v2/component-library/src/components/ui/badge.tsx
new file mode 100644
index 0000000..8cdcc16
--- /dev/null
+++ b/v2/component-library/src/components/ui/badge.tsx
@@ -0,0 +1,46 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const badgeVariants = cva(
+ "inline-flex w-fit shrink-0 items-center justify-center gap-1.5 rounded-full border px-3 py-1 text-xs font-semibold whitespace-nowrap transition-colors [&>svg]:pointer-events-none [&>svg]:size-3.5",
+ {
+ variants: {
+ variant: {
+ /* soft teal pill – "Monatlich", "Grundsätzlich umlagefähig" */
+ default: "border-transparent bg-accent text-accent-foreground",
+ /* solid teal pill */
+ solid: "border-transparent bg-primary text-primary-foreground",
+ /* soft red pill – "Nicht umlagefähig" */
+ destructive: "border-transparent bg-destructive/10 text-destructive",
+ outline: "border-border bg-card text-foreground shadow-pill",
+ muted: "border-transparent bg-muted text-muted-foreground",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+function Badge({
+ className,
+ variant,
+ asChild = false,
+ ...props
+}: React.ComponentProps<"span"> &
+ VariantProps & { asChild?: boolean }) {
+ const Comp = asChild ? Slot : "span"
+
+ return (
+
+ )
+}
+
+export { Badge, badgeVariants }
diff --git a/v2/component-library/src/components/ui/breadcrumb.tsx b/v2/component-library/src/components/ui/breadcrumb.tsx
new file mode 100644
index 0000000..845899e
--- /dev/null
+++ b/v2/component-library/src/components/ui/breadcrumb.tsx
@@ -0,0 +1,109 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { ChevronRight, MoreHorizontal } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
+ return
+}
+
+function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
+ return (
+
+ )
+}
+
+function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
+ return (
+
+ )
+}
+
+function BreadcrumbLink({
+ asChild,
+ className,
+ ...props
+}: React.ComponentProps<"a"> & {
+ asChild?: boolean
+}) {
+ const Comp = asChild ? Slot : "a"
+
+ return (
+
+ )
+}
+
+function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
+ return (
+
+ )
+}
+
+function BreadcrumbSeparator({
+ children,
+ className,
+ ...props
+}: React.ComponentProps<"li">) {
+ return (
+ svg]:size-3.5", className)}
+ {...props}
+ >
+ {children ?? }
+
+ )
+}
+
+function BreadcrumbEllipsis({
+ className,
+ ...props
+}: React.ComponentProps<"span">) {
+ return (
+
+
+ Mehr
+
+ )
+}
+
+export {
+ Breadcrumb,
+ BreadcrumbList,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+ BreadcrumbEllipsis,
+}
diff --git a/v2/component-library/src/components/ui/button.tsx b/v2/component-library/src/components/ui/button.tsx
new file mode 100644
index 0000000..80cc1f3
--- /dev/null
+++ b/v2/component-library/src/components/ui/button.tsx
@@ -0,0 +1,59 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const buttonVariants = cva(
+ "inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 rounded-lg text-sm font-semibold whitespace-nowrap transition-all outline-none focus-visible:ring-[3px] focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ {
+ variants: {
+ variant: {
+ default:
+ "bg-primary text-primary-foreground shadow-sm hover:bg-brand-700",
+ outline:
+ "border border-border bg-card text-foreground shadow-pill hover:border-brand-200 hover:bg-brand-50",
+ secondary: "bg-secondary text-secondary-foreground hover:bg-brand-100",
+ ghost: "text-foreground hover:bg-secondary",
+ link: "text-primary underline-offset-4 hover:underline",
+ /* white button sitting on the teal gradient band */
+ inverse: "bg-white text-brand-800 shadow-sm hover:bg-brand-50",
+ destructive:
+ "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
+ },
+ size: {
+ default: "h-10 px-5 py-2",
+ sm: "h-9 gap-1.5 px-4",
+ lg: "h-11 px-6 text-[15px]",
+ icon: "size-10",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+function Button({
+ className,
+ variant,
+ size,
+ asChild = false,
+ ...props
+}: React.ComponentProps<"button"> &
+ VariantProps & {
+ asChild?: boolean
+ }) {
+ const Comp = asChild ? Slot : "button"
+
+ return (
+
+ )
+}
+
+export { Button, buttonVariants }
diff --git a/v2/component-library/src/components/ui/card.tsx b/v2/component-library/src/components/ui/card.tsx
new file mode 100644
index 0000000..ee09649
--- /dev/null
+++ b/v2/component-library/src/components/ui/card.tsx
@@ -0,0 +1,89 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Card({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardAction({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardContent({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardAction,
+ CardDescription,
+ CardContent,
+}
diff --git a/v2/component-library/src/components/ui/checkbox.tsx b/v2/component-library/src/components/ui/checkbox.tsx
new file mode 100644
index 0000000..881fc1d
--- /dev/null
+++ b/v2/component-library/src/components/ui/checkbox.tsx
@@ -0,0 +1,30 @@
+import * as React from "react"
+import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
+import { CheckIcon } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+function Checkbox({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+ )
+}
+
+export { Checkbox }
diff --git a/v2/component-library/src/components/ui/dropdown-menu.tsx b/v2/component-library/src/components/ui/dropdown-menu.tsx
new file mode 100644
index 0000000..bdc47fd
--- /dev/null
+++ b/v2/component-library/src/components/ui/dropdown-menu.tsx
@@ -0,0 +1,255 @@
+import * as React from "react"
+import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
+import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+function DropdownMenu({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function DropdownMenuPortal({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuTrigger({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuContent({
+ className,
+ sideOffset = 8,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+function DropdownMenuGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuItem({
+ className,
+ inset,
+ variant = "default",
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+ variant?: "default" | "destructive"
+}) {
+ return (
+
+ )
+}
+
+function DropdownMenuCheckboxItem({
+ className,
+ children,
+ checked,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function DropdownMenuRadioGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuRadioItem({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function DropdownMenuLabel({
+ className,
+ inset,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
+ return (
+
+ )
+}
+
+function DropdownMenuSeparator({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuShortcut({
+ className,
+ ...props
+}: React.ComponentProps<"span">) {
+ return (
+
+ )
+}
+
+function DropdownMenuSub({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function DropdownMenuSubTrigger({
+ className,
+ inset,
+ children,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
+ return (
+
+ {children}
+
+
+ )
+}
+
+function DropdownMenuSubContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export {
+ DropdownMenu,
+ DropdownMenuPortal,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuLabel,
+ DropdownMenuItem,
+ DropdownMenuCheckboxItem,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubTrigger,
+ DropdownMenuSubContent,
+}
diff --git a/v2/component-library/src/components/ui/input.tsx b/v2/component-library/src/components/ui/input.tsx
new file mode 100644
index 0000000..df085ad
--- /dev/null
+++ b/v2/component-library/src/components/ui/input.tsx
@@ -0,0 +1,21 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Input({ className, type, ...props }: React.ComponentProps<"input">) {
+ return (
+
+ )
+}
+
+export { Input }
diff --git a/v2/component-library/src/components/ui/label.tsx b/v2/component-library/src/components/ui/label.tsx
new file mode 100644
index 0000000..b02e4c4
--- /dev/null
+++ b/v2/component-library/src/components/ui/label.tsx
@@ -0,0 +1,22 @@
+import * as React from "react"
+import * as LabelPrimitive from "@radix-ui/react-label"
+
+import { cn } from "@/lib/utils"
+
+function Label({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export { Label }
diff --git a/v2/component-library/src/components/ui/select.tsx b/v2/component-library/src/components/ui/select.tsx
new file mode 100644
index 0000000..d42ab58
--- /dev/null
+++ b/v2/component-library/src/components/ui/select.tsx
@@ -0,0 +1,186 @@
+import * as React from "react"
+import * as SelectPrimitive from "@radix-ui/react-select"
+import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+function Select({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function SelectGroup({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function SelectValue({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function SelectTrigger({
+ className,
+ size = "default",
+ children,
+ ...props
+}: React.ComponentProps & {
+ size?: "sm" | "default"
+}) {
+ return (
+
+ {children}
+
+
+
+
+ )
+}
+
+function SelectContent({
+ className,
+ children,
+ position = "popper",
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ )
+}
+
+function SelectLabel({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function SelectItem({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function SelectSeparator({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function SelectScrollUpButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+function SelectScrollDownButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+export {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+}
diff --git a/v2/component-library/src/components/ui/separator.tsx b/v2/component-library/src/components/ui/separator.tsx
new file mode 100644
index 0000000..46aa225
--- /dev/null
+++ b/v2/component-library/src/components/ui/separator.tsx
@@ -0,0 +1,26 @@
+import * as React from "react"
+import * as SeparatorPrimitive from "@radix-ui/react-separator"
+
+import { cn } from "@/lib/utils"
+
+function Separator({
+ className,
+ orientation = "horizontal",
+ decorative = true,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export { Separator }
diff --git a/v2/component-library/src/components/ui/table.tsx b/v2/component-library/src/components/ui/table.tsx
new file mode 100644
index 0000000..74e1971
--- /dev/null
+++ b/v2/component-library/src/components/ui/table.tsx
@@ -0,0 +1,114 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Table({ className, ...props }: React.ComponentProps<"table">) {
+ return (
+
+ )
+}
+
+function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
+ return (
+
+ )
+}
+
+function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
+ return (
+
+ )
+}
+
+function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
+ return (
+ tr]:last:border-b-0",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
+ return (
+
+ )
+}
+
+function TableHead({ className, ...props }: React.ComponentProps<"th">) {
+ return (
+
+ )
+}
+
+function TableCell({ className, ...props }: React.ComponentProps<"td">) {
+ return (
+
+ )
+}
+
+function TableCaption({
+ className,
+ ...props
+}: React.ComponentProps<"caption">) {
+ return (
+
+ )
+}
+
+export {
+ Table,
+ TableHeader,
+ TableBody,
+ TableFooter,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableCaption,
+}
diff --git a/v2/component-library/src/components/ui/tabs.tsx b/v2/component-library/src/components/ui/tabs.tsx
new file mode 100644
index 0000000..b68b8f0
--- /dev/null
+++ b/v2/component-library/src/components/ui/tabs.tsx
@@ -0,0 +1,67 @@
+import * as React from "react"
+import * as TabsPrimitive from "@radix-ui/react-tabs"
+
+import { cn } from "@/lib/utils"
+
+function Tabs({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function TabsList({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+/**
+ * Audience-switcher style triggers: white cards that fill teal when active
+ * (see "Für wen ist GebOS?" – Hauseigentümer / Hausverwaltungen / …).
+ */
+function TabsTrigger({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function TabsContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export { Tabs, TabsList, TabsTrigger, TabsContent }
diff --git a/v2/component-library/src/lib/utils.ts b/v2/component-library/src/lib/utils.ts
new file mode 100644
index 0000000..bd0c391
--- /dev/null
+++ b/v2/component-library/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/v2/component-library/src/main.tsx b/v2/component-library/src/main.tsx
new file mode 100644
index 0000000..595050b
--- /dev/null
+++ b/v2/component-library/src/main.tsx
@@ -0,0 +1,13 @@
+import { StrictMode } from "react"
+import { createRoot } from "react-dom/client"
+
+import "@fontsource-variable/inter"
+import "@/styles/globals.css"
+
+import App from "@/App"
+
+createRoot(document.getElementById("root")!).render(
+
+
+
+)
diff --git a/v2/component-library/src/pages/audiences/audience-page.tsx b/v2/component-library/src/pages/audiences/audience-page.tsx
new file mode 100644
index 0000000..3ac9701
--- /dev/null
+++ b/v2/component-library/src/pages/audiences/audience-page.tsx
@@ -0,0 +1,115 @@
+import * as React from "react"
+
+import { Container, Section, SectionHeading } from "@/components/gebos/section"
+import { PageBreadcrumb } from "@/components/gebos/page-breadcrumb"
+import { PageHero } from "@/components/gebos/page-hero"
+import { FeatureTile } from "@/components/gebos/icon-tile"
+
+type AudienceFeature = {
+ icon?: React.ReactNode
+ /** self-contained visual (asset-kit icon/vector) rendered without IconBadge */
+ media?: React.ReactNode
+ title: React.ReactNode
+ sub?: React.ReactNode
+}
+
+function AudienceBreadcrumb({ current }: { current: string }) {
+ return (
+
+ )
+}
+
+/**
+ * Shared audience page template (tiles 5–8):
+ * split PageHero with breadcrumb, feature tile row, closing slot
+ * (teal CtaBanner or slim repeat-CTA section).
+ */
+function AudiencePage({
+ breadcrumb,
+ title,
+ tagline,
+ lead,
+ actions,
+ visual,
+ features,
+ children,
+ closing,
+}: {
+ breadcrumb: string
+ title: React.ReactNode
+ /** short bold subline under the H1 (e.g. "Bestellen. Montieren. Fertig.") */
+ tagline?: React.ReactNode
+ lead?: React.ReactNode
+ actions?: React.ReactNode
+ visual?: React.ReactNode
+ features: AudienceFeature[]
+ /** additional full-width spec sections between feature row and closing */
+ children?: React.ReactNode
+ closing?: React.ReactNode
+}) {
+ return (
+ <>
+ }
+ title={title}
+ lead={
+ <>
+ {tagline ? (
+
+ {tagline}
+
+ ) : null}
+ {lead}
+ >
+ }
+ actions={actions}
+ visual={visual}
+ />
+
+
+
+ {features.map((feature, i) => (
+
+ ))}
+
+
+ {children}
+ {closing}
+
+ >
+ )
+}
+
+/**
+ * Slim closing section repeating the hero CTAs
+ * (tiles 7 and 8 close without a gradient band).
+ */
+function AudienceClosing({
+ title,
+ lead,
+ actions,
+}: {
+ title: React.ReactNode
+ lead?: React.ReactNode
+ actions: React.ReactNode
+}) {
+ return (
+
+ )
+}
+
+export { AudiencePage, AudienceClosing }
+export type { AudienceFeature }
diff --git a/v2/component-library/src/pages/audiences/hauseigentuemer.tsx b/v2/component-library/src/pages/audiences/hauseigentuemer.tsx
new file mode 100644
index 0000000..0e44a0c
--- /dev/null
+++ b/v2/component-library/src/pages/audiences/hauseigentuemer.tsx
@@ -0,0 +1,291 @@
+import { Link } from "react-router-dom"
+import { Euro, Handshake, ReceiptText, ShieldCheck, Wrench } from "lucide-react"
+
+import { Button } from "@/components/ui/button"
+import { Card } from "@/components/ui/card"
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+import { Section, SectionHeading } from "@/components/gebos/section"
+import { CtaBanner } from "@/components/gebos/cta-banner"
+import { NumberedList } from "@/components/gebos/process-steps"
+import { AssetRender, renders } from "@/components/gebos/site-assets"
+import { AudiencePage } from "@/pages/audiences/audience-page"
+
+/**
+ * Page-local hero composition (05-homeowners kit):
+ * building render on the right, smoke alarm top-left,
+ * detached check orb as accent between them.
+ */
+function HomeownerArt() {
+ return (
+
+ )
+}
+
+const SELF_INSTALL_STEPS = [
+ {
+ title: "Gebäude angeben",
+ description:
+ "Sie teilen uns die grundlegenden Informationen zum Gebäude und den Wohnungen mit.",
+ },
+ {
+ title: "Passende Ausstattung zusammenstellen",
+ description:
+ "Die benötigten Zähler, Kommunikationskomponenten und gegebenenfalls Rauchwarnmelder werden zusammengestellt.",
+ },
+ {
+ title: "Vorkonfiguriert erhalten",
+ description:
+ "Die Geräte werden bereits für Ihr Gebäude vorbereitet geliefert.",
+ },
+ {
+ title: "Montieren",
+ description:
+ "Sie selbst, Ihr Hausmeister oder Ihr Fachbetrieb installiert die Geräte.",
+ },
+ {
+ title: "GebOS übernimmt",
+ description:
+ "Nach der Inbetriebnahme laufen Datenerfassung und die gebuchten Dienstleistungen über GebOS.",
+ },
+]
+
+const WHY_GEBOS = [
+ {
+ title: "Kosten kontrollieren",
+ text: "Entscheiden Sie selbst, welche Arbeiten Sie übernehmen und welche Sie abgeben möchten.",
+ },
+ {
+ title: "Keine unnötige technische Komplexität",
+ text: "Die Hardware wird für das jeweilige Gebäude vorbereitet.",
+ },
+ {
+ title: "Bestehenden Handwerker nutzen",
+ text: "Sie benötigen keinen speziellen GebOS-Installateur.",
+ },
+ {
+ title: "Alles an einem Ort",
+ text: "UVI, Abrechnung, Geräte und weitere Gebäudedienstleistungen werden zentral verwaltet.",
+ },
+ {
+ title: "Weniger laufender Aufwand",
+ text: "Nach der Einrichtung werden Verbrauchsdaten automatisch erfasst und verarbeitet.",
+ },
+]
+
+const VARIANT_ROWS = [
+ ["Planung", "gemeinsam mit GebOS", "GebOS"],
+ ["Hardware", "GebOS", "GebOS"],
+ ["Installation", "Kunde / eigener Fachbetrieb", "organisiert durch GebOS"],
+ ["Softwareeinrichtung", "vorbereitet durch GebOS", "GebOS"],
+ ["Laufender Betrieb", "GebOS", "GebOS"],
+ ["Kosten", "möglichst niedrig", "höhere Planungssicherheit und Komfort"],
+]
+
+export default function HauseigentuemerPage() {
+ return (
+
+ Messdienstleistungen für Ihr Mehrfamilienhaus. Einfach organisiert.
+
+ }
+ lead="UVI, Heizkostenabrechnung und Rauchwarnmelder mit vorkonfigurierter Technik – selbst installieren oder als Komplettlösung beauftragen."
+ actions={
+
+ Preis für mein Gebäude berechnen
+
+ }
+ visual={ }
+ features={[
+ {
+ icon: ,
+ title: "Selbst installieren",
+ sub: "Kosten sparen, flexibel bleiben",
+ },
+ {
+ icon: ,
+ title: "Komplettlösung",
+ sub: "Wir kümmern uns um alles",
+ },
+ {
+ icon: ,
+ title: "Transparente Preise",
+ sub: "Keine versteckten Kosten",
+ },
+ {
+ icon: ,
+ title: "Bestehende Partner",
+ sub: "Ihre Handwerker bleiben",
+ },
+ ]}
+ closing={
+
+ }
+ title="Welche Lösung passt zu Ihrem Gebäude?"
+ description="Mit wenigen Angaben zur ersten Preisindikation – oder direkt die Komplettlösung anfragen."
+ actions={
+ <>
+
+
+ Preis für mein Gebäude berechnen
+
+
+
+ Komplettlösung anfragen
+
+ >
+ }
+ />
+
+ }
+ >
+
+
+
+
+
+
+ Selbst installieren
+
+
+ Sie möchten Kosten niedrig halten und können die Installation
+ selbst oder über einen vertrauten Heizungsbauer, Hausmeister
+ oder anderen Fachbetrieb organisieren? GebOS liefert die
+ benötigte Technik passend zu Ihrem Gebäude vorkonfiguriert.
+
+
+ Sie organisieren die Montage. GebOS übernimmt den digitalen
+ Betrieb.
+
+
+
+ Preis berechnen
+
+
+
+
+
+
+ Komplett installieren lassen
+
+
+ Sie möchten sich möglichst wenig mit Planung, Beschaffung und
+ Installation beschäftigen? GebOS organisiert die komplette
+ Umsetzung für Sie. Von der Ermittlung der benötigten Geräte
+ über die Installation bis zum laufenden Betrieb erhalten Sie
+ eine durchgängige Lösung.
+
+
+
+ Komplettlösung anfragen
+
+
+
+
+
+
+
+
+
+
+
+ {WHY_GEBOS.map((item) => (
+
+ {item.title}
+
+ {item.text}
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+ Selbst installieren
+ Komplettlösung
+
+
+
+ {VARIANT_ROWS.map(([label, self, full]) => (
+
+
+ {label}
+
+
+ {self}
+
+
+ {full}
+
+
+ ))}
+
+
+
+
+
+ )
+}
diff --git a/v2/component-library/src/pages/audiences/hausverwaltungen.tsx b/v2/component-library/src/pages/audiences/hausverwaltungen.tsx
new file mode 100644
index 0000000..bd34359
--- /dev/null
+++ b/v2/component-library/src/pages/audiences/hausverwaltungen.tsx
@@ -0,0 +1,348 @@
+import { Link } from "react-router-dom"
+import {
+ Ban,
+ Euro,
+ LayoutDashboard,
+ Package,
+ Timer,
+ TrendingUp,
+ Unlock,
+ X,
+} from "lucide-react"
+
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent } from "@/components/ui/card"
+import { Separator } from "@/components/ui/separator"
+import { Section, SectionHeading } from "@/components/gebos/section"
+import { CtaBanner } from "@/components/gebos/cta-banner"
+import { IconBadge } from "@/components/gebos/icon-tile"
+import { NumberedList } from "@/components/gebos/process-steps"
+import {
+ AssetRender,
+ renders,
+ vectors,
+} from "@/components/gebos/site-assets"
+import { AudiencePage } from "@/pages/audiences/audience-page"
+
+const deviceExamples = [
+ "Wärmemengenzähler",
+ "Warmwasserzähler",
+ "Kaltwasserzähler",
+ "Kommunikationsinfrastruktur",
+ "Rauchwarnmelder",
+]
+
+const rolloutSteps = [
+ {
+ title: "Portfolio und Objekte erfassen",
+ description:
+ "Bei der Auftragserstellung werden die betreffenden Gebäude, Wohnungen und die vorhandene beziehungsweise benötigte Ausstattung erfasst.",
+ },
+ {
+ title: "Gerätebedarf bestimmen",
+ description: (
+ <>
+ Für jedes Objekt wird festgelegt, welche Geräte benötigt werden.
+ Beispielsweise:
+
+ {deviceExamples.map((device) => (
+
+ {device}
+
+ ))}
+
+ >
+ ),
+ },
+ {
+ title: "GebOS bereitet den Rollout vor",
+ description:
+ "Gebäude und Wohnungen werden im System angelegt und die Hardware wird objektbezogen vorbereitet.",
+ },
+ {
+ title: "Installationsfertig liefern",
+ description:
+ "Die Geräte werden passend zum jeweiligen Gebäude beziehungsweise zur jeweiligen Nutzungseinheit ausgeliefert.",
+ },
+ {
+ title: "Bestehende Monteure installieren",
+ description:
+ "Eigene Mitarbeiter, Hausmeister oder bestehende Installationspartner können die Montage übernehmen. Eine umfangreiche Softwarekonfiguration vor Ort ist nicht erforderlich.",
+ },
+ {
+ title: "Bewohner einladen",
+ description:
+ "Nach der Einrichtung müssen im Wesentlichen noch die relevanten Bewohnerdaten ergänzt beziehungsweise Einladungen zum Mieterportal versendet werden.",
+ },
+]
+
+const noEffortItems = [
+ { icon: , title: "Keine aufwendige Gerätekonfiguration." },
+ { icon: , title: "Keine manuelle Anlage jedes einzelnen Gerätes." },
+ {
+ icon: ,
+ title: "Keine spezielle GebOS-Zertifizierung für den Installateur.",
+ },
+]
+
+const portfolioStats = [
+ { value: "48", label: "Gebäude" },
+ { value: "384", label: "Wohnungen" },
+ { value: "1.746", label: "Geräte" },
+]
+
+const statusInfos = [
+ "Auftrag angelegt",
+ "Hardware vorbereitet",
+ "Versendet",
+ "Installation begonnen",
+ "Installation vollständig",
+ "Geräte aktiv",
+ "Bewohner eingeladen",
+ "Handlungsbedarf",
+]
+
+const whyGebos = [
+ {
+ title: "Schneller Rollout",
+ sub: "Standardisierte Abläufe ermöglichen die parallele Umsetzung vieler Objekte.",
+ },
+ {
+ title: "Weniger Administration",
+ sub: "Gebäudedaten werden möglichst nur einmal erfasst und anschließend weiterverwendet.",
+ },
+ {
+ title: "Vorkonfigurierte Hardware",
+ sub: "Geräte werden bereits passend zu den jeweiligen Objekten vorbereitet.",
+ },
+ {
+ title: "Bestehende Installationspartner",
+ sub: "Eigene Hausmeister, technische Mitarbeiter oder externe Fachbetriebe können weiter eingesetzt werden.",
+ },
+ {
+ title: "Zentrale Portfolioübersicht",
+ sub: "Gebäude, Wohnungen und Geräte lassen sich gemeinsam betrachten.",
+ },
+ {
+ title: "Ein Ansprechpartner",
+ sub: "Technik und laufende digitale Dienstleistungen greifen ineinander.",
+ },
+]
+
+/** Portfolio/rollout hero per asset kit 06: building, teal bars, consumption ring. */
+function PortfolioHeroArt() {
+ return (
+
+
+
+
+
+ )
+}
+
+export default function HausverwaltungenPage() {
+ return (
+
+
+ Portfolio kalkulieren
+
+
+ Rollout besprechen
+
+ >
+ }
+ visual={ }
+ features={[
+ {
+ icon: ,
+ title: "Vorkonfigurierte Hardware",
+ },
+ {
+ icon: ,
+ title: "Wenig Aufwand vor Ort",
+ },
+ {
+ icon: ,
+ title: "Zentrale Übersicht",
+ },
+ {
+ icon: ,
+ title: "Skalierbar für wachsende Portfolios",
+ },
+ ]}
+ closing={
+
+ }
+ title="Wie sieht Ihr Portfolio aus?"
+ description="Erhalten Sie zunächst mit wenigen Angaben eine Preisindikation für mehrere Gebäude – oder sprechen Sie mit uns über vorhandene Messtechnik und den geplanten Rollout."
+ actions={
+ <>
+
+ Portfolio kalkulieren
+
+
+ Rollout besprechen
+
+ >
+ }
+ />
+
+ }
+ >
+
+
+
+
+
+ Objekte einmal erfassen. Geräte vorbereitet erhalten. Montieren.
+ Betreiben.
+
+
+
+
+
+
+
+
+
+
+ {noEffortItems.map((item, i) => (
+
+
+
+ {item.icon}
+
+
+ {item.title}
+
+
+
+ ))}
+
+
+ Damit können bestehende Installationsstrukturen weiter genutzt
+ werden.
+
+
+
+
+
+
+
+
+
+
+ Beispiel
+
+
+ Portfolio
+
+
+ {portfolioStats.map((stat) => (
+
+
+ {stat.value}
+
+
+ {stat.label}
+
+
+ ))}
+
+
+ 43 Gebäude aktiv
+ 3 in Installation
+ 2 mit Handlungsbedarf
+
+
+
+
+
+
+ Mögliche Statusinformationen
+
+
+ {statusInfos.map((status) => (
+
+ {status}
+
+ ))}
+
+
+
+
+
+
+
+
+ {whyGebos.map((item) => (
+
+
+ {item.title}
+
+ {item.sub}
+
+
+
+ ))}
+
+
+
+
+
+ )
+}
diff --git a/v2/component-library/src/pages/audiences/installateure.tsx b/v2/component-library/src/pages/audiences/installateure.tsx
new file mode 100644
index 0000000..4cebe98
--- /dev/null
+++ b/v2/component-library/src/pages/audiences/installateure.tsx
@@ -0,0 +1,327 @@
+import { Link } from "react-router-dom"
+import {
+ CircleCheck,
+ GraduationCap,
+ Package,
+ PackageX,
+ Unlock,
+ Users,
+ Wrench,
+} from "lucide-react"
+
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Card } from "@/components/ui/card"
+import { Checklist } from "@/components/gebos/checklist"
+import { IconBadge } from "@/components/gebos/icon-tile"
+import { ProcessSteps } from "@/components/gebos/process-steps"
+import { Section, SectionHeading } from "@/components/gebos/section"
+import { AssetRender, renders, vectors } from "@/components/gebos/site-assets"
+import { AudiencePage, AudienceClosing } from "@/pages/audiences/audience-page"
+
+const KUNDEN_BEDARFE = [
+ "UVI",
+ "Heizkostenabrechnung",
+ "fernauslesbare Messtechnik",
+ "Rauchwarnmelder",
+]
+
+const KEINE_HUERDEN = [
+ {
+ icon: ,
+ title: "Keine verpflichtende Partnerschaft",
+ },
+ {
+ icon: ,
+ title: "Keine Mindestabnahme",
+ },
+ {
+ icon: ,
+ title: "Keine verpflichtende GebOS-Vertriebsschulung",
+ },
+ {
+ icon: ,
+ title: "Keine komplizierte Softwareeinrichtung auf der Baustelle",
+ },
+]
+
+const GEBOS_BEREITET_VOR = [
+ "Gebäudestruktur",
+ "Wohnungen beziehungsweise Nutzungseinheiten",
+ "Gerätezuordnung",
+ "benötigte Hardware",
+ "Kommunikationsinfrastruktur",
+ "Softwarestruktur",
+]
+
+const SIE_UEBERNEHMEN = [
+ "fachgerechte Montage",
+ "gegebenenfalls Austausch vorhandener Geräte",
+ "Einbau der vorgesehenen Messtechnik",
+ "Abschluss der Installation",
+]
+
+export default function InstallateurePage() {
+ return (
+
+ Für Installateure &
+
+ Heizungsbauer
+ >
+ }
+ tagline="Bestellen. Montieren. Fertig."
+ lead="GebOS für Ihre Kunden installieren – ohne Partnerprogramm, verpflichtende Zertifizierung oder aufwendige Softwarekonfiguration."
+ actions={
+
+ Gebäude für meinen Kunden konfigurieren
+
+ }
+ visual={
+
+
+
+
+
+
+ }
+ features={[
+ {
+ icon: ,
+ title: "Keine Partnerpflichten",
+ sub: "Keine Mindestmengen",
+ },
+ {
+ icon: ,
+ title: "Vorkonfigurierte Hardware",
+ },
+ {
+ icon: ,
+ title: "Einfache Installation",
+ sub: "Keine Softwarekonfiguration",
+ },
+ {
+ icon: ,
+ title: "Ihre Kunden",
+ sub: "Bleiben Ihre Kunden",
+ },
+ ]}
+ closing={
+
+
+ Gebäude für meinen Kunden konfigurieren
+
+
+ }
+ />
+ }
+ >
+ {/* 1. Ihr Kunde braucht eine Messdienstlösung? */}
+
+
+
+ {KUNDEN_BEDARFE.map((bedarf) => (
+
+
+ {bedarf}
+
+ ))}
+
+
+ Dann können Sie GebOS einfach für das betreffende Gebäude einsetzen.{" "}
+
+ Sie müssen dafür nicht zunächst Teil eines Partnerprogramms werden.
+
+
+
+
+ {/* 2. So einfach soll die Installation sein */}
+
+
+
+ ),
+ title: "Gebäude erfassen",
+ description:
+ "Die benötigte Ausstattung wird für das konkrete Objekt zusammengestellt.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Geräte bestellen",
+ description:
+ "GebOS liefert die zum Gebäude passenden Geräte.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Vorkonfiguriert erhalten",
+ description:
+ "Die Hardware wird bereits objektbezogen vorbereitet.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Montieren",
+ description: "Sie übernehmen die fachgerechte Installation.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Fertig",
+ description:
+ "Die digitale Einrichtung und der laufende Betrieb werden von GebOS übernommen.",
+ },
+ ]}
+ />
+
+
+ {/* 3. Kein klassisches Partnerprogramm erforderlich */}
+
+
+
+ {KEINE_HUERDEN.map((item, i) => (
+
+
+ {item.icon}
+
+
+ {item.title}
+
+
+ ))}
+
+
+
+ Der Fachbetrieb bleibt der Fachbetrieb des Kunden.
+ {" "}
+ GebOS stellt das Produkt und die digitale Infrastruktur bereit.
+
+
+
+ {/* 4. Sie können bei Ihren bestehenden Kunden bleiben */}
+
+
+ GebOS ist besonders interessant, wenn ein Kunde Sie ohnehin mit
+ Arbeiten an Heizungs-, Wasser- oder Gebäudetechnik beauftragt und
+ zusätzlich eine Lösung für Messdienstleistungen benötigt. Sie
+ können die Installation übernehmen, ohne selbst einen
+ vollständigen Messdienst aufbauen zu müssen.
+ >
+ }
+ />
+
+
+ {/* 5. Was GebOS vorbereitet / Was Sie übernehmen */}
+
+
+
+
+ Was GebOS vorbereitet
+
+ Je nach Auftrag:
+
+
+ Damit soll vor Ort möglichst wenig zusätzliche digitale Arbeit
+ entstehen.
+
+
+
+
+ Was Sie übernehmen
+
+
+ Das Handwerk bleibt bei Ihnen:
+
+
+
+
+
+
+ {/* 6. Und wenn Sie regelmäßig GebOS installieren? */}
+
+
+
+ Und wenn Sie regelmäßig GebOS installieren?
+
+
+ Auch dann soll der Einstieg freiwillig bleiben. Für Fachbetriebe mit
+ größerem Volumen können später zusätzliche Konditionen oder
+ Leistungen angeboten werden. Das normale Installieren von GebOS
+ bleibt davon unabhängig.
+
+
+
+
+ )
+}
diff --git a/v2/component-library/src/pages/audiences/messdienstleister.tsx b/v2/component-library/src/pages/audiences/messdienstleister.tsx
new file mode 100644
index 0000000..0231e1b
--- /dev/null
+++ b/v2/component-library/src/pages/audiences/messdienstleister.tsx
@@ -0,0 +1,271 @@
+import { Link } from "react-router-dom"
+import { ArrowDown, Code2, Layers, ShieldCheck, Tag } from "lucide-react"
+
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent } from "@/components/ui/card"
+import { Section, SectionHeading } from "@/components/gebos/section"
+import { Checklist } from "@/components/gebos/checklist"
+import {
+ AssetRender,
+ renders,
+ vectors,
+} from "@/components/gebos/site-assets"
+import { AudiencePage, AudienceClosing } from "@/pages/audiences/audience-page"
+
+const platformRequirements = [
+ "kompatible Messtechnik",
+ "Kommunikationsinfrastruktur",
+ "Gateways",
+ "sichere Datenerfassung",
+ "Geräteverwaltung",
+ "Monitoring",
+ "Verbrauchsdatenverarbeitung",
+ "Nutzerportale",
+ "Schnittstellen",
+ "laufender technischer Betrieb",
+]
+
+const whiteLabelItems = [
+ "eigenes Branding",
+ "eigene Kundenbeziehung",
+ "mandantenfähige Verwaltung",
+ "Endkundenportale",
+ "APIs und Datenexporte",
+ "Geräteverwaltung",
+ "technischer Support",
+]
+
+const platformCapabilities = [
+ {
+ title: "Gerätekompatibilität",
+ sub: "Einbindung unterschiedlicher Zähler- und Gerätetypen auf Basis geeigneter Standards.",
+ },
+ {
+ title: "Gateway-Infrastruktur",
+ sub: "Zentrale Erfassung und sichere Übertragung der Gerätedaten.",
+ },
+ {
+ title: "Gerätemanagement",
+ sub: "Verwaltung großer Gerätebestände über Gebäude und Kunden hinweg.",
+ },
+ {
+ title: "Monitoring",
+ sub: "Probleme und Ausfälle erkennen, bevor daraus manueller Aufwand beim Kunden entsteht.",
+ },
+ {
+ title: "APIs und Integrationen",
+ sub: "Anbindung an eigene Systeme und bestehende Geschäftsprozesse.",
+ },
+ {
+ title: "Mandantenfähigkeit",
+ sub: "Kunden und Bestände getrennt innerhalb einer gemeinsamen Plattform verwalten.",
+ },
+ {
+ title: "White Label",
+ sub: "GebOS-Infrastruktur unter der Marke des Messdienstleisters einsetzen.",
+ },
+]
+
+const businessComponents = [
+ "Einkaufspreise für Hardware",
+ "Plattformgebühren",
+ "Mengenstaffeln",
+ "wiederkehrende Gebühren",
+ "White-Label-Konditionen",
+ "Support- und Servicelevel",
+ "mögliche Mindestmengen",
+]
+
+const stackFlow = ["Ihre Kunden", "Ihr Messdienst", "GebOS Plattform"]
+
+/** Platform hero per asset kit 07: laptop dashboard, glass cubes, cloud support. */
+function PlatformHeroArt() {
+ return (
+
+
+
+
+
+ )
+}
+
+export default function MessdienstleisterPage() {
+ return (
+
+
+ Plattform kennenlernen
+
+
+ Konditionen anfragen
+
+ >
+ }
+ visual={ }
+ features={[
+ {
+ icon: ,
+ title: "White Label",
+ sub: "Ihr Branding, Ihre Kunden",
+ },
+ {
+ icon: ,
+ title: "Offene APIs",
+ sub: "Einfach integrieren",
+ },
+ {
+ icon: ,
+ title: "Skalierbare Plattform",
+ sub: "Für jedes Geschäftsmodell",
+ },
+ {
+ icon: ,
+ title: "Zuverlässiger Betrieb",
+ sub: "Sicher und performant",
+ },
+ ]}
+ closing={
+
+
+ Plattform kennenlernen
+
+
+ Konditionen anfragen
+
+ >
+ }
+ />
+ }
+ >
+
+
+
+
+
+
+
+ GebOS stellt diese Infrastruktur als Plattform bereit.
+
+
+
+
+
+
+
+ {stackFlow.map((label) => (
+
+ ))}
+
+ Hardware · Datenerfassung · Software · Betrieb
+
+
+
+
+
+
+
+
+
+
+ {platformCapabilities.map((item) => (
+
+
+ {item.title}
+
+ {item.sub}
+
+
+
+ ))}
+
+
+
+
+
+
+
+ Mögliche Bestandteile
+
+
+ {businessComponents.map((component) => (
+
+ {component}
+
+ ))}
+
+
+ Die konkreten Konditionen werden nicht öffentlich auf der Website
+ dargestellt.
+
+
+
+
+
+
+ )
+}
diff --git a/v2/component-library/src/pages/configurator.tsx b/v2/component-library/src/pages/configurator.tsx
new file mode 100644
index 0000000..ac110b0
--- /dev/null
+++ b/v2/component-library/src/pages/configurator.tsx
@@ -0,0 +1,553 @@
+import * as React from "react"
+import { Link } from "react-router-dom"
+import { ArrowRight, Euro, Plus, X } from "lucide-react"
+
+import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Card } from "@/components/ui/card"
+import { Checkbox } from "@/components/ui/checkbox"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Separator } from "@/components/ui/separator"
+import { Checklist } from "@/components/gebos/checklist"
+import { DonutIllustration } from "@/components/gebos/illustrations"
+import { IconBadge } from "@/components/gebos/icon-tile"
+import { Container, Section, SectionHeading } from "@/components/gebos/section"
+import { PageBreadcrumb } from "@/components/gebos/page-breadcrumb"
+import { icons, vectors } from "@/components/gebos/site-assets"
+
+type Heat = "heizkoerper" | "fussbodenheizung" | "gemischt" | "unbekannt"
+
+type Building = {
+ id: number
+ adresse: string
+ heat: Heat
+ wohnungen: number
+ zimmer: number
+}
+
+const HEAT_OPTIONS: { value: Heat; label: string }[] = [
+ { value: "heizkoerper", label: "Heizkörper" },
+ { value: "fussbodenheizung", label: "Fußbodenheizung" },
+ { value: "gemischt", label: "Gemischt" },
+ { value: "unbekannt", label: "Weiß ich nicht" },
+]
+
+const INITIAL_BUILDINGS: Building[] = [
+ { id: 1, adresse: "", heat: "heizkoerper", wohnungen: 12, zimmer: 3 },
+ { id: 2, adresse: "", heat: "heizkoerper", wohnungen: 8, zimmer: 3 },
+ { id: 3, adresse: "", heat: "heizkoerper", wohnungen: 6, zimmer: 3 },
+]
+
+const UVI_MONTHLY = 10.5
+const INSPECTION_MONTHLY = 2.2
+const RWM_ONE_TIME = 42
+
+function formatEuro(value: number) {
+ return value.toLocaleString("de-DE", {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })
+}
+
+function StepCard({
+ step,
+ title,
+ children,
+}: {
+ step: number
+ title: string
+ children: React.ReactNode
+}) {
+ return (
+
+
+
+ {step}
+
+
+ {title}
+
+
+ {children}
+
+ )
+}
+
+export default function ConfiguratorPage() {
+ const [uvi, setUvi] = React.useState(true)
+ const [rwm, setRwm] = React.useState(true)
+ const [buildings, setBuildings] = React.useState(INITIAL_BUILDINGS)
+ const [email, setEmail] = React.useState("")
+ const nextId = React.useRef(INITIAL_BUILDINGS.length + 1)
+
+ const updateBuilding = (id: number, patch: Partial) => {
+ setBuildings((prev) => prev.map((b) => (b.id === id ? { ...b, ...patch } : b)))
+ }
+
+ const addBuilding = () => {
+ setBuildings((prev) => [
+ ...prev,
+ { id: nextId.current++, adresse: "", heat: "heizkoerper", wohnungen: 8, zimmer: 3 },
+ ])
+ }
+
+ const removeBuilding = (id: number) => {
+ setBuildings((prev) => (prev.length > 1 ? prev.filter((b) => b.id !== id) : prev))
+ }
+
+ const totalBuildings = buildings.length
+ const totalUnits = buildings.reduce((sum, b) => sum + (b.wohnungen || 0), 0)
+ const sensors = buildings.reduce(
+ (sum, b) => sum + Math.round((b.wohnungen || 0) * (b.zimmer || 0) * 0.92),
+ 0
+ )
+ const smokeDetectors = buildings.reduce(
+ (sum, b) => sum + Math.round((b.wohnungen || 0) * ((b.zimmer || 0) + 0.7)),
+ 0
+ )
+ const monthly =
+ (uvi ? UVI_MONTHLY : 0) + (uvi || rwm ? INSPECTION_MONTHLY : 0)
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Left column: steps */}
+
+
+
+
+ setUvi(v === true)}
+ className="mt-0.5"
+ />
+
+ UVI
+
+ Unterjährige Verbrauchsinformation inklusive Messtechnik
+
+
+
+
+ setRwm(v === true)}
+ className="mt-0.5"
+ />
+
+
+ Rauchwarnmelder
+
+
+ Rauchwarnmelder inklusive digitaler Dienstleistungen
+
+
+
+
+
+
+
+
+ {buildings.map((b, i) => (
+
+
+
+ Gebäude {i + 1}
+
+ {buildings.length > 1 ? (
+
removeBuilding(b.id)}
+ >
+
+
+ ) : null}
+
+
+
+
+ Adresse{" "}
+
+ (optional)
+
+
+
+ updateBuilding(b.id, { adresse: e.target.value })
+ }
+ />
+
+
+ Wärmeverteilung
+
+ updateBuilding(b.id, { heat: v as Heat })
+ }
+ >
+
+
+
+
+ {HEAT_OPTIONS.map((opt) => (
+
+ {opt.label}
+
+ ))}
+
+
+
+
+ Wohnungen
+
+ updateBuilding(b.id, {
+ wohnungen: Math.max(
+ 0,
+ Math.round(Number(e.target.value) || 0)
+ ),
+ })
+ }
+ />
+
+
+ Ø Zimmer
+
+ updateBuilding(b.id, {
+ zimmer: Math.max(0, Number(e.target.value) || 0),
+ })
+ }
+ />
+
+
+
+ ))}
+
+ Gebäude hinzufügen
+
+
+
+
+
+
+ Sofortige erste Preisindikation.
+
+
+
+
+ Wie wurde dieser Preis berechnet?
+
+
+
+ Für diese Schätzung gehen wir aufgrund Ihrer Angaben von
+ ungefähr{" "}
+
+ {sensors} Heizsensoren und {smokeDetectors}{" "}
+ Rauchwarnmeldern
+ {" "}
+ aus.
+
+
+ Bei Gebäuden mit durchschnittlich drei Zimmern verwenden
+ wir eine typische Geräteausstattung als
+ Berechnungsgrundlage.
+
+
+ Die endgültige Anzahl wird bei der detaillierten
+ Konfiguration der Wohnungen bestimmt und ersetzt diese
+ Schätzwerte.
+
+
+
+
+
+
+
+
+
+
+
+ Jetzt Preis berechnen
+
+ So funktioniert der Konfigurator
+
+
+
+
+ {/* Right column: sticky summary */}
+
+
+
+ Ihre vorläufige Konfiguration
+
+
+
+ {totalBuildings}{" "}
+ {totalBuildings === 1 ? "Gebäude" : "Gebäude"}
+
+
+ {totalUnits} {totalUnits === 1 ? "Wohnung" : "Wohnungen"}
+
+
+ {uvi || rwm ? (
+ <>
+
+
+ Voraussichtlich benötigt
+
+
+ {uvi ? (
+
+ ca. {sensors} Heizsensoren
+
+ ) : null}
+ {rwm ? (
+
+ ca. {smokeDetectors} Rauchwarnmelder
+
+ ) : null}
+
+ >
+ ) : null}
+
+
+
+
+
+ ca. {formatEuro(monthly)}{"\u00A0"}€
+
+
+ je Wohnung / Monat
+
+
+
+
+
+
+ {rwm ? (
+
+ + {formatEuro(RWM_ONE_TIME)}{"\u00A0"}€ je Wohnung einmalig
+ (RWM-Hardware)
+
+ ) : null}
+
+
+
+
+
+ Die erste Berechnung ist eine unverbindliche Preisindikation.
+ Der genaue Preis ergibt sich aus der vollständigen
+ Objektkonfiguration.
+
+
+
+
+
+
+
+ {/* Was ist in der Schätzung enthalten? */}
+
+
+
+
+
+
+
+ UVI
+
+
+
+
+
+
+
+
+ Rauchwarnmelder
+
+
+
+
+
+
+
+ {/* Stufe 2 – So geht es weiter */}
+
+
+
+
+
+ Geschätzt: 72 Heizsensoren
+
+
+
+ Konfiguriert: 68 Heizsensoren
+
+
+
+
+ Geschätzt: 96 Rauchwarnmelder
+
+
+
+ Konfiguriert: 103 Rauchwarnmelder
+
+
+
+
+
+
+ Finales Ergebnis
+
+
+ Ihre GebOS-Konfiguration
+
+
+ 3 Gebäude · 26 Wohnungen
+
+
+
+
+
UVI
+
+ 68 Heizsensoren / Messgeräte, weitere benötigte Messtechnik
+
+
+
+
Rauchwarnmelder
+ 103 Rauchwarnmelder
+
+
+
Infrastruktur
+
+ technisch ausgelegte Gateway- und Kommunikationsinfrastruktur
+
+
+
+
+
+ Ihr Preis ist dann keine grobe Hochrechnung auf Basis von
+ Durchschnittswerten mehr, sondern ein Preis auf Grundlage der
+ tatsächlichen Objektkonfiguration.
+
+
+ Angebot anfordern
+
+
+
+
+ Ihre Daten werden im gesamten Prozess weiterverwendet:
+ Preisschätzung → Konfiguration → Bestellung → Gerätevorbereitung →
+ Installation → laufender Betrieb.
+
+
+
+ )
+}
diff --git a/v2/component-library/src/pages/for-whom.tsx b/v2/component-library/src/pages/for-whom.tsx
new file mode 100644
index 0000000..5e6c3b6
--- /dev/null
+++ b/v2/component-library/src/pages/for-whom.tsx
@@ -0,0 +1,223 @@
+import * as React from "react"
+import { Link } from "react-router-dom"
+import { Building2, House, LineChart, Wrench } from "lucide-react"
+
+import { Button } from "@/components/ui/button"
+import { Card } from "@/components/ui/card"
+import { Label } from "@/components/ui/label"
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select"
+import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Checklist } from "@/components/gebos/checklist"
+import { Container, Section, SectionHeading } from "@/components/gebos/section"
+import { PageBreadcrumb } from "@/components/gebos/page-breadcrumb"
+import {
+ AssetRender,
+ renders,
+ vectors,
+} from "@/components/gebos/site-assets"
+
+type AudienceKey =
+ | "hauseigentuemer"
+ | "hausverwaltung"
+ | "messdienstleister"
+ | "installateur"
+
+const AUDIENCES: Record<
+ AudienceKey,
+ {
+ select: string
+ tab: string
+ tabIcon: React.ReactNode
+ headline: string
+ text: string
+ bullets: string[]
+ cta: string
+ href: string
+ }
+> = {
+ hauseigentuemer: {
+ select: "Hauseigentümer",
+ tab: "Hauseigentümer",
+ tabIcon: ,
+ headline: "Messdienstleistungen für Ihr Mehrfamilienhaus",
+ text: "Installieren Sie vorkonfigurierte Technik selbst beziehungsweise mit Ihrem bestehenden Fachbetrieb – oder überlassen Sie GebOS die komplette Umsetzung.",
+ bullets: [
+ "einfache Installation",
+ "transparente Kosten",
+ "zuverlässiger laufender Betrieb",
+ "eigene Fachbetriebe weiter nutzen",
+ "wahlweise Selbstinstallation oder Komplettlösung",
+ ],
+ cta: "GebOS für Hauseigentümer",
+ href: "/fuer-wen/hauseigentuemer",
+ },
+ hausverwaltung: {
+ select: "Hausverwaltung",
+ tab: "Hausverwaltungen",
+ tabIcon: ,
+ headline: "Viele Gebäude. Ein einfacher Rollout.",
+ text: "Erfassen Sie Ihre Objekte einmal, erhalten Sie vorkonfigurierte Hardware und nutzen Sie bestehende Mitarbeiter oder Installationspartner für die Montage.",
+ bullets: [
+ "standardisierter Rollout",
+ "vorkonfigurierte Geräte",
+ "wenig Softwarearbeit vor Ort",
+ "zentrale Portfolioverwaltung",
+ "geringer administrativer Aufwand",
+ "schnelle Erweiterung um weitere Gebäude",
+ ],
+ cta: "GebOS für Hausverwaltungen",
+ href: "/fuer-wen/hausverwaltungen",
+ },
+ messdienstleister: {
+ select: "Messdienstleister",
+ tab: "Messdienstleister",
+ tabIcon: ,
+ headline: "Ihre Messdienstleistung. Unsere Infrastruktur.",
+ text: "Nutzen Sie GebOS als technische Grundlage für Ihre eigenen Dienstleistungen – mit Hardware, Plattform, Gerätemanagement und optionalem White Label.",
+ bullets: [
+ "technische Plattform",
+ "Gerätekompatibilität",
+ "Skalierbarkeit",
+ "APIs und Integrationen",
+ "White Label",
+ "individuelles Geschäftsmodell",
+ ],
+ cta: "GebOS für Messdienstleister",
+ href: "/fuer-wen/messdienstleister",
+ },
+ installateur: {
+ select: "Installateur & Heizungsbauer",
+ tab: "Installateure",
+ tabIcon: ,
+ headline: "Bestellen. Montieren. Fertig.",
+ text: "Setzen Sie GebOS bei Ihren bestehenden Kunden ein, ohne zunächst ein Partnerprogramm durchlaufen zu müssen.",
+ bullets: [
+ "kein verpflichtender Partnerstatus",
+ "keine Mindestabnahme",
+ "vorkonfigurierte Hardware",
+ "keine aufwendige Softwarekonfiguration",
+ "bestehende Kundenbeziehung bleibt erhalten",
+ ],
+ cta: "GebOS für Installateure",
+ href: "/fuer-wen/installateure",
+ },
+}
+
+const AUDIENCE_KEYS = Object.keys(AUDIENCES) as AudienceKey[]
+
+/**
+ * Page-local hero composition (04-for-whom kit):
+ * building portfolio render, teal growth bars behind right,
+ * consumption ring in front at the lower left.
+ */
+function ForWhomArt() {
+ return (
+
+
+
+
+
+ )
+}
+
+export default function ForWhomPage() {
+ const [audience, setAudience] = React.useState("hausverwaltung")
+ const active = AUDIENCES[audience]
+
+ return (
+
+
+
+
+
+
+
+
+ Ich bin …
+
+ setAudience(value as AudienceKey)}
+ >
+
+
+
+
+ {AUDIENCE_KEYS.map((key) => (
+
+ {AUDIENCES[key].select}
+
+ ))}
+
+
+
+
+
+
+
+ {active.headline}
+
+
+ {active.text}
+
+
+ Besonders wichtig für Sie:
+
+
+
+
+ {active.cta}
+
+
+
+
+
+
+ setAudience(value as AudienceKey)}
+ className="mt-12"
+ >
+
+ {AUDIENCE_KEYS.map((key) => (
+
+ {AUDIENCES[key].tabIcon}
+ {AUDIENCES[key].tab}
+
+ ))}
+
+
+
+
+
+ )
+}
diff --git a/v2/component-library/src/pages/home.tsx b/v2/component-library/src/pages/home.tsx
new file mode 100644
index 0000000..4f31e0c
--- /dev/null
+++ b/v2/component-library/src/pages/home.tsx
@@ -0,0 +1,590 @@
+import { Link } from "react-router-dom"
+import {
+ ArrowRight,
+ Building2,
+ Calculator,
+ HardHat,
+ House,
+ Network,
+} from "lucide-react"
+
+import { Button } from "@/components/ui/button"
+import { Card, CardContent } from "@/components/ui/card"
+import { Container, Section, SectionHeading } from "@/components/gebos/section"
+import { PageHero } from "@/components/gebos/page-hero"
+import { HeroArt } from "@/components/gebos/hero-art"
+import { FeatureTile, IconBadge } from "@/components/gebos/icon-tile"
+import { ProcessSteps, NumberedList } from "@/components/gebos/process-steps"
+import { Checklist } from "@/components/gebos/checklist"
+import { CtaBanner } from "@/components/gebos/cta-banner"
+import {
+ AssetRender,
+ icons,
+ renders,
+ vectors,
+} from "@/components/gebos/site-assets"
+
+const features = [
+ {
+ media: ,
+ title: "UVI",
+ sub: "Monatliche Verbrauchsinformation",
+ },
+ {
+ media: (
+
+ ),
+ title: "Heizkosten\u00adabrechnung",
+ sub: "Jährlich korrekt abrechnen",
+ },
+ {
+ media: (
+
+ ),
+ title: "Rauchwarnmelder",
+ sub: "Sicher überwacht, zentral verwaltet",
+ },
+ {
+ media: ,
+ title: "Fernauslesbare Messtechnik",
+ sub: "Automatisch erfasst, sicher übertragen",
+ },
+ {
+ media: (
+
+ ),
+ title: "Portale & Verwaltung",
+ sub: "Alle Daten und Geräte im Blick",
+ },
+]
+
+const operationsScope = [
+ {
+ media: ,
+ title: "Unterjährige Verbrauchsinformation",
+ text: "Verbrauchsdaten werden automatisch erfasst und die regelmäßigen Verbrauchsinformationen für die Bewohner bereitgestellt.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Heizkostenabrechnung",
+ text: "Die erfassten Verbrauchsdaten bilden die Grundlage für die jährliche Heizkostenabrechnung.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Rauchwarnmelder",
+ text: "Rauchwarnmelder können gemeinsam mit der übrigen Gebäudetechnik geplant, installiert und zentral verwaltet werden.",
+ },
+ {
+ media: ,
+ title: "Fernauslesbare Messtechnik",
+ text: "Wärme- und Wasserverbrauch werden über kompatible Geräte automatisch erfasst.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Gateway und Datenübertragung",
+ text: "Die Messdaten werden zentral gesammelt und an GebOS übertragen.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Portale und Verwaltung",
+ text: "Gebäude, Wohnungen, Geräte und Verbrauchsdaten werden zentral verwaltet. Bewohner erhalten Zugriff auf die für sie vorgesehenen Informationen.",
+ },
+]
+
+function StepMedia({ src }: { src: string }) {
+ return (
+
+
+
+ )
+}
+
+const processSteps = [
+ {
+ media: ,
+ title: "Gebäude erfassen",
+ description: "Daten zum Gebäude und den Wohnungen erfassen.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Gerätebedarf bestimmen",
+ description: "GebOS ermittelt die benötigte Ausstattung automatisch.",
+ },
+ {
+ media: ,
+ title: "Vorkonfiguriert liefern",
+ description: "Hardware wird für Ihr Objekt vorbereitet geliefert.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Geräte montieren",
+ description: "Montage vor Ort – ohne aufwendige Softwarekonfiguration.",
+ },
+ {
+ media: ,
+ title: "Automatisch betreiben",
+ description: "GebOS übernimmt Daten, Services und laufenden Betrieb.",
+ },
+]
+
+const lessEffort = [
+ {
+ vector: vectors.packageBox,
+ title: "Vorkonfigurierte Hardware",
+ text: "Geräte werden passend zum jeweiligen Gebäude und zur vorgesehenen Nutzung vorbereitet.",
+ },
+ {
+ vector: vectors.checkOrb,
+ title: "Keine aufwendige Einrichtung auf der Baustelle",
+ text: "Der Installateur kann sich auf die fachgerechte Montage konzentrieren.",
+ },
+ {
+ vector: vectors.checkOrb,
+ title: "Bestehende Fachbetriebe nutzen",
+ text: "Kein spezieller GebOS-Partner erforderlich – eigene Hausmeister, Heizungsbauer oder bestehende Installationspartner können weiterhin eingesetzt werden.",
+ },
+ {
+ vector: vectors.checkOrb,
+ title: "Weniger doppelte Dateneingabe",
+ text: "Informationen aus Bestellung und Konfiguration werden für den späteren Betrieb weiterverwendet.",
+ },
+]
+
+const systemTasks = [
+ {
+ media: ,
+ title: "UVI",
+ text: "Regelmäßige Verbrauchsinformation für Bewohner.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Heizkostenabrechnung",
+ text: "Verbrauchsdaten strukturiert erfassen und für die jährliche Abrechnung nutzen.",
+ },
+ {
+ media: (
+
+ ),
+ title: "Rauchwarnmelder",
+ text: "Rauchwarnmelder gemeinsam mit der übrigen Gebäudetechnik planen und verwalten.",
+ },
+ {
+ media: ,
+ title: "Messtechnik und Infrastruktur",
+ text: "Fernauslesbare Zähler, Sensoren und Kommunikationsinfrastruktur für den laufenden Betrieb.",
+ },
+]
+
+const audiences = [
+ {
+ icon: ,
+ name: "Hauseigentümer",
+ headline: "Messdienstleistungen für Ihr Mehrfamilienhaus",
+ text: "Installieren Sie vorkonfigurierte Technik selbst beziehungsweise mit Ihrem bestehenden Fachbetrieb – oder überlassen Sie GebOS die komplette Umsetzung.",
+ points: [
+ "einfache Installation",
+ "transparente Kosten",
+ "zuverlässiger laufender Betrieb",
+ ],
+ cta: "GebOS für Hauseigentümer",
+ to: "/fuer-wen/hauseigentuemer",
+ },
+ {
+ icon: ,
+ name: "Hausverwaltungen",
+ headline: "Viele Gebäude. Ein einfacher Rollout.",
+ text: "Erfassen Sie Ihre Objekte einmal, erhalten Sie vorkonfigurierte Hardware und nutzen Sie bestehende Mitarbeiter oder Installationspartner für die Montage.",
+ points: [
+ "standardisierter Rollout",
+ "vorkonfigurierte Geräte",
+ "zentrale Portfolioverwaltung",
+ ],
+ cta: "GebOS für Hausverwaltungen",
+ to: "/fuer-wen/hausverwaltungen",
+ },
+ {
+ icon: ,
+ name: "Messdienstleister",
+ headline: "Ihre Messdienstleistung. Unsere Infrastruktur.",
+ text: "Nutzen Sie GebOS als technische Grundlage für Ihre eigenen Dienstleistungen – mit Hardware, Plattform, Gerätemanagement und optionalem White Label.",
+ points: ["technische Plattform", "Skalierbarkeit", "APIs und White Label"],
+ cta: "GebOS für Messdienstleister",
+ to: "/fuer-wen/messdienstleister",
+ },
+ {
+ icon: ,
+ name: "Installateure & Heizungsbauer",
+ headline: "Bestellen. Montieren. Fertig.",
+ text: "Setzen Sie GebOS bei Ihren bestehenden Kunden ein, ohne zunächst ein Partnerprogramm durchlaufen zu müssen.",
+ points: [
+ "kein verpflichtender Partnerstatus",
+ "keine Mindestabnahme",
+ "vorkonfigurierte Hardware",
+ ],
+ cta: "GebOS für Installateure",
+ to: "/fuer-wen/installateure",
+ },
+]
+
+const scaleFlows = [
+ {
+ vector: vectors.tealBars,
+ label: "1 Gebäude",
+ sub: "Ein Eigentümer kann ein Mehrfamilienhaus konfigurieren.",
+ steps: [
+ { title: "GebOS konfigurieren" },
+ { title: "Installieren" },
+ { title: "Betreiben" },
+ ],
+ },
+ {
+ vector: vectors.consumptionRing,
+ label: "50 Gebäude",
+ sub: "Eine Hausverwaltung kann denselben Prozess auf viele Gebäude übertragen.",
+ steps: [
+ { title: "Nach demselben Prozess konfigurieren" },
+ { title: "Rollout organisieren" },
+ { title: "Zentral betreiben" },
+ ],
+ },
+]
+
+const priceFlow = [
+ { title: "Wenige Angaben" },
+ { title: "Erste Preisindikation" },
+ { title: "Konfiguration speichern" },
+ { title: "Gebäude vollständig konfigurieren" },
+ { title: "Genauer Preis" },
+]
+
+export default function HomePage() {
+ return (
+ <>
+
+ Messdienstleistungen
+ {" "}
+ einfach gemacht.
+ >
+ }
+ lead="Unterjährige Verbrauchsinformation (UVI), Heizkostenabrechnung und Rauchwarnmelder – von der vorkonfigurierten Hardware bis zum laufenden Betrieb."
+ actions={
+ <>
+
+ Preis berechnen
+
+
+ So funktioniert GebOS
+
+ >
+ }
+ visual={ }
+ />
+
+
+
+
+
+ {features.map((feature) => (
+
+ ))}
+
+
+
+
+
+
+
+ {operationsScope.map((item) => (
+
+
+ {item.media}
+
+ {item.title}
+
+
+ {item.text}
+
+
+
+ ))}
+
+
+
+
+
+
+
+ „Bestellung, Konfiguration und Installation greifen ineinander.“
+
+
+
+ Preis für mein Gebäude berechnen
+
+
+
+
+
+
+
+ {lessEffort.map((item) => (
+
+
+
+
+ {item.title}
+
+
+ {item.text}
+
+
+
+ ))}
+
+
+
+
+
+
+ {systemTasks.map((task) => (
+
+ {task.media}
+
+
{task.title}
+
+ {task.text}
+
+
+
+
+ Mehr erfahren
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+ {scaleFlows.map((flow) => (
+
+
+
+
+
+ {flow.label}
+
+
+ {flow.sub}
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+ Dafür werden zunächst nur grundlegende Informationen benötigt,
+ beispielsweise:
+
+
+
+ Auf Basis dieser Angaben schätzt GebOS die voraussichtlich
+ benötigte Geräteanzahl und berechnet einen ungefähren Preis.
+
+
+ Erst schätzen. Dann genau konfigurieren.
+
+
+ Der Schnellkonfigurator arbeitet bewusst mit Annahmen. Für
+ einen genauen Preis können Sie die Konfiguration anschließend
+ speichern und Ihre Gebäude detailliert erfassen. Die bereits
+ eingegebenen Daten werden übernommen.
+
+
+ Preis berechnen
+
+
+
+
+
+
+
+
+ In fünf Schritten zum genauen Preis
+
+
+
+
+
+
+ Die erste Berechnung ist eine unverbindliche Preisindikation.
+ Die tatsächliche Ausstattung und der genaue Preis ergeben sich
+ aus der vollständigen Objektkonfiguration.
+
+
+
+
+
+
+
+
+ {audiences.map((audience) => (
+
+
+
+
+ {audience.icon}
+
+
+ {audience.name}
+
+
+
+ {audience.headline}
+
+
+ {audience.text}
+
+
+ Besonders wichtig für Sie
+
+
+
+ {audience.cta}
+
+
+
+ ))}
+
+
+
+
+ }
+ title="Messdienstleistungen müssen nicht kompliziert sein."
+ description="Gebäude erfassen, passende Technik erhalten, montieren und anschließend zentral betreiben."
+ actions={
+ <>
+
+ Preis berechnen
+
+
+ So funktioniert GebOS
+
+ >
+ }
+ />
+
+
+ >
+ )
+}
diff --git a/v2/component-library/src/pages/how-it-works.tsx b/v2/component-library/src/pages/how-it-works.tsx
new file mode 100644
index 0000000..350ac95
--- /dev/null
+++ b/v2/component-library/src/pages/how-it-works.tsx
@@ -0,0 +1,181 @@
+import type { ReactNode } from "react"
+import { Link } from "react-router-dom"
+import { Calculator, ChevronRight } from "lucide-react"
+
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Card } from "@/components/ui/card"
+import { CtaBanner } from "@/components/gebos/cta-banner"
+import { ProcessSteps } from "@/components/gebos/process-steps"
+import { Container, Section, SectionHeading } from "@/components/gebos/section"
+import { PageBreadcrumb } from "@/components/gebos/page-breadcrumb"
+import {
+ AssetRender,
+ renders,
+ vectors,
+} from "@/components/gebos/site-assets"
+
+function StepMedia({ children }: { children: ReactNode }) {
+ return (
+ {children}
+ )
+}
+
+const steps = [
+ {
+ media: (
+
+
+
+ ),
+ title: "Gebäude erfassen",
+ description:
+ "Bei der Konfiguration werden Gebäude, Wohnungen und die benötigten Leistungen erfasst.",
+ },
+ {
+ media: (
+
+
+
+ ),
+ title: "Gerätebedarf bestimmen",
+ description:
+ "Auf Basis der Gebäudedaten wird ermittelt, welche Messtechnik, Rauchwarnmelder und weiteren Komponenten benötigt werden.",
+ },
+ {
+ media: (
+
+
+
+ ),
+ title: "Vorkonfiguriert liefern",
+ description:
+ "Gebäude, Wohnungen und Geräte werden bereits vorbereitet. Die Hardware wird objektbezogen und installationsfertig geliefert.",
+ },
+ {
+ media: (
+
+
+
+
+ ),
+ title: "Geräte montieren",
+ description: (
+ <>
+ Die Geräte müssen vor Ort im Wesentlichen nur noch fachgerecht montiert
+ werden.{" "}
+
+ Keine aufwendige Softwarekonfiguration bei der Installation.
+
+ >
+ ),
+ },
+ {
+ media: (
+
+
+
+ ),
+ title: "Automatisch betreiben",
+ description:
+ "Nach der Installation übernimmt GebOS die laufende Datenerfassung und die gebuchten digitalen Dienstleistungen.",
+ },
+]
+
+const journey = [
+ "Besucher versteht GebOS",
+ "identifiziert seinen Anwendungsfall",
+ "berechnet einen ungefähren Preis",
+ "speichert seine Konfiguration",
+ "ergänzt die tatsächlichen Gebäudedaten",
+ "erhält den genauen Preis",
+ "erteilt den Auftrag",
+ "GebOS bereitet Gebäude und Geräte vor",
+ "vorkonfigurierte Hardware wird geliefert",
+ "Montage vor Ort",
+ "automatischer laufender Betrieb",
+]
+
+export default function HowItWorksPage() {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ „Bestellung, Konfiguration und Installation greifen ineinander.“
+
+
+
+
+
+
+
+
+ {journey.map((station, i) => (
+
+
+ {station}
+
+ {i < journey.length - 1 ? (
+
+ ) : null}
+
+ ))}
+
+
+
+ Der Konfigurator ist der Beginn des
+ GebOS-Bestell- und Rolloutprozesses.
+
+
+ Die einmal eingegebenen Gebäudedaten werden nicht erneut erfasst,
+ sondern durch den gesamten Prozess weiterverwendet.
+
+
+ Preisschätzung → Konfiguration → Bestellung → Gerätevorbereitung →
+ Installation → Betrieb
+
+
+
+
+
+
+ }
+ title="Was kostet GebOS für Ihr Gebäude?"
+ description="Mit wenigen Angaben erhalten Sie eine erste Preisindikation."
+ actions={
+
+ Preis berechnen
+
+ }
+ />
+
+
+ >
+ )
+}
diff --git a/v2/component-library/src/pages/klarpreis.tsx b/v2/component-library/src/pages/klarpreis.tsx
new file mode 100644
index 0000000..1d48f35
--- /dev/null
+++ b/v2/component-library/src/pages/klarpreis.tsx
@@ -0,0 +1,154 @@
+import { ClipboardCheck, Euro, House, ShieldCheck, Tag, Users2, Wifi } from "lucide-react"
+
+import { Separator } from "@/components/ui/separator"
+import { Container, Section } from "@/components/gebos/section"
+import { PageHero } from "@/components/gebos/page-hero"
+import { PageBreadcrumb } from "@/components/gebos/page-breadcrumb"
+import { HeroVisual } from "@/components/gebos/hero-visual"
+import { IconBadge } from "@/components/gebos/icon-tile"
+import { PriceCard } from "@/components/gebos/price-card"
+import {
+ SensorCubesIllustration,
+ SmokeDetectorIllustration,
+} from "@/components/gebos/illustrations"
+
+const trustItems = [
+ { icon: ClipboardCheck, label: ["Klare", "Vertragsstruktur"] },
+ { icon: ShieldCheck, label: ["Keine versteckten", "Gebühren"] },
+ { icon: Users2, label: ["Rabatte für", "große Objekte"] },
+] as const
+
+export default function KlarpreisPage() {
+ return (
+ <>
+
+ }
+ title={
+ <>
+ GebOS Klarpreis
+ >
+ }
+ lead="Drei sauber getrennte Leistungen. Einfache Preise. Keine Überraschungen."
+ extra={
+
+
+
+
+ Ideal für Wohngebäude, Hausverwaltungen und Bestandshalter.
+
+ }
+ visual={
+ }
+ chipTitle="Inspektion OK"
+ chipSub="Letzte Prüfung 06.05.2024"
+ />
+ }
+ />
+
+
+
+
+ }
+ />
+
+ UVI-Komplettbetrieb
+
+ }
+ cadence="Monatlich"
+ price="10,50 €"
+ unit="je Wohnung / Monat"
+ allocation={{ label: "Grundsätzlich umlagefähig", tone: "positive" }}
+ description="Sensoren, Daten, Portal und Verbrauchsinformation inklusive."
+ media={ }
+ />
+
+
+
+ {/* total band */}
+
+
+
+
+
+
+ Gesamtkosten laufend
+
+
+
+ 12,70 €
+
+
+ je Wohnung / Monat
+
+
+
+
+
+
+
+
+
+ Alle laufenden Leistungen klar gebündelt – ohne versteckte
+ Zusatzkosten.
+
+
+
+
+ {/* trust card */}
+
+ {trustItems.map(({ icon: Icon, label }) => (
+
+
+
+
+
+ {label[0]}
+
+ {label[1]}
+
+
+ ))}
+
+
+
+
+ >
+ )
+}
diff --git a/v2/component-library/src/pages/placeholder.tsx b/v2/component-library/src/pages/placeholder.tsx
new file mode 100644
index 0000000..6889858
--- /dev/null
+++ b/v2/component-library/src/pages/placeholder.tsx
@@ -0,0 +1,39 @@
+import type * as React from "react"
+
+import { Container, Section, SectionHeading } from "@/components/gebos/section"
+import {
+ PageBreadcrumb,
+ type Crumb,
+} from "@/components/gebos/page-breadcrumb"
+
+/**
+ * Minimal content page (Unternehmen / Kontakt) and stand-in while
+ * full pages are being built.
+ */
+function SimplePage({
+ title,
+ lead,
+ breadcrumb,
+ children,
+}: {
+ title: React.ReactNode
+ lead?: React.ReactNode
+ breadcrumb?: Crumb[]
+ children?: React.ReactNode
+}) {
+ return (
+
+
+
+ {breadcrumb ? (
+
+ ) : null}
+
+ {children}
+
+
+
+ )
+}
+
+export { SimplePage }
diff --git a/v2/component-library/src/pages/solutions.tsx b/v2/component-library/src/pages/solutions.tsx
new file mode 100644
index 0000000..9461e86
--- /dev/null
+++ b/v2/component-library/src/pages/solutions.tsx
@@ -0,0 +1,132 @@
+import { Link } from "react-router-dom"
+import { ArrowRight, Euro } from "lucide-react"
+
+import { Button } from "@/components/ui/button"
+import { Card } from "@/components/ui/card"
+import { CtaBanner } from "@/components/gebos/cta-banner"
+import { Container, Section, SectionHeading } from "@/components/gebos/section"
+import { PageBreadcrumb } from "@/components/gebos/page-breadcrumb"
+import {
+ AssetRender,
+ renders,
+ vectors,
+} from "@/components/gebos/site-assets"
+
+const solutions = [
+ {
+ title: "UVI",
+ sub: "Monatliche Verbrauchsinformation",
+ description:
+ "Verbrauchsdaten werden automatisch erfasst und die regelmäßigen Verbrauchsinformationen für die Bewohner bereitgestellt.",
+ illustration: (
+
+
+
+
+ ),
+ },
+ {
+ title: "Heizkostenabrechnung",
+ sub: "Verbrauchsdaten korrekt abrechnen",
+ description:
+ "Verbrauchsdaten strukturiert erfassen und für die jährliche Abrechnung nutzen.",
+ illustration: ,
+ },
+ {
+ title: "Rauchwarnmelder",
+ sub: "Sicher überwacht, zentral verwaltet",
+ description:
+ "Rauchwarnmelder gemeinsam mit der übrigen Gebäudetechnik planen und verwalten.",
+ illustration: ,
+ },
+]
+
+export default function SolutionsPage() {
+ return (
+ <>
+
+
+
+
+
+
+ {solutions.map((s) => (
+
+
+ {s.title}
+
+ {s.sub}
+
+ {s.illustration}
+
+
+ {s.description}
+
+
+
+ Mehr erfahren
+
+
+
+
+ ))}
+
+
+
+
+
+ Messtechnik und Infrastruktur
+
+
+ Fernauslesbare Zähler, Sensoren und
+ Kommunikationsinfrastruktur für den laufenden Betrieb.
+
+
+
+
+ Mehr erfahren
+
+
+
+
+
+
+
+
+
+ }
+ title="Jetzt Preis für Ihr Gebäude berechnen"
+ description="In wenigen Minuten zur ersten Preisindikation."
+ actions={
+
+ Preis berechnen
+
+ }
+ />
+
+
+ >
+ )
+}
diff --git a/v2/component-library/src/styles/globals.css b/v2/component-library/src/styles/globals.css
new file mode 100644
index 0000000..66fd927
--- /dev/null
+++ b/v2/component-library/src/styles/globals.css
@@ -0,0 +1,169 @@
+@import "tailwindcss";
+@import "tw-animate-css";
+
+/* ------------------------------------------------------------------ */
+/* GebOS design tokens */
+/* Sampled from the GebOS Klarpreis + landing page designs: */
+/* – teal brand, deep navy type, cool off-white surfaces, */
+/* soft shadows, generous radii, pill badges, gradient CTA bands. */
+/* ------------------------------------------------------------------ */
+
+:root {
+ /* surfaces */
+ --background: #f4f8f9;
+ --foreground: #071a3f;
+ --card: #ffffff;
+ --card-foreground: #071a3f;
+ --popover: #ffffff;
+ --popover-foreground: #071a3f;
+
+ /* brand */
+ --primary: #009b9a;
+ --primary-foreground: #ffffff;
+ --secondary: #eaf3f4;
+ --secondary-foreground: #071a3f;
+ --muted: #edf3f4;
+ --muted-foreground: #516078;
+ --accent: #e0f4f0;
+ --accent-foreground: #006c79;
+
+ /* feedback */
+ --destructive: #dc3439;
+ --destructive-foreground: #ffffff;
+
+ /* lines & focus */
+ --border: #e2eceb;
+ --input: #d7e3e4;
+ --ring: #009b9a;
+
+ /* charts (donut / bars in visuals) */
+ --chart-1: #009b9a;
+ --chart-2: #34e0d4;
+ --chart-3: #cdeee8;
+ --chart-4: #071a3f;
+ --chart-5: #94a9b8;
+
+ /* brand scale */
+ --brand-50: #eefaf7;
+ --brand-100: #d8f2ec;
+ --brand-200: #b5ece6;
+ --brand-300: #7ce0d6;
+ --brand-400: #34e0d4;
+ --brand-500: #03aaa4;
+ --brand-600: #009b9a;
+ --brand-700: #007d89;
+ --brand-800: #006c79;
+ --brand-900: #06474e;
+ --navy: #071a3f;
+
+ --radius: 0.75rem;
+}
+
+@theme inline {
+ --font-sans:
+ "Inter Variable", "Inter", ui-sans-serif, system-ui, -apple-system,
+ "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-destructive-foreground: var(--destructive-foreground);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --color-chart-1: var(--chart-1);
+ --color-chart-2: var(--chart-2);
+ --color-chart-3: var(--chart-3);
+ --color-chart-4: var(--chart-4);
+ --color-chart-5: var(--chart-5);
+
+ --color-brand-50: var(--brand-50);
+ --color-brand-100: var(--brand-100);
+ --color-brand-200: var(--brand-200);
+ --color-brand-300: var(--brand-300);
+ --color-brand-400: var(--brand-400);
+ --color-brand-500: var(--brand-500);
+ --color-brand-600: var(--brand-600);
+ --color-brand-700: var(--brand-700);
+ --color-brand-800: var(--brand-800);
+ --color-brand-900: var(--brand-900);
+ --color-navy: var(--navy);
+
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+
+ /* soft layered card shadows from the designs */
+ --shadow-card: 0 1px 2px rgb(19 41 60 / 0.04), 0 8px 24px rgb(19 41 60 / 0.06);
+ --shadow-card-lg:
+ 0 2px 4px rgb(19 41 60 / 0.04), 0 16px 48px rgb(19 41 60 / 0.1);
+ --shadow-band: 0 16px 40px rgb(10 100 89 / 0.28);
+ --shadow-pill: 0 1px 2px rgb(19 41 60 / 0.06);
+}
+
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
+ }
+
+ html {
+ scroll-behavior: smooth;
+ }
+
+ body {
+ @apply bg-background text-foreground font-sans antialiased;
+ font-feature-settings:
+ "liga" 1,
+ "calt" 1,
+ "cv05" 1;
+ }
+
+ ::selection {
+ @apply bg-brand-200 text-navy;
+ }
+}
+
+/* teal gradient band used for CTA banners and total-cost bar */
+@utility bg-brand-gradient {
+ background-image: linear-gradient(
+ 105deg,
+ var(--brand-800) 0%,
+ var(--brand-700) 35%,
+ var(--brand-600) 70%,
+ var(--brand-500) 100%
+ );
+}
+
+/* radial page glow behind heroes (subtle white vignette on cool bg) */
+@utility bg-hero-glow {
+ background-image:
+ radial-gradient(
+ 60rem 32rem at 85% -10%,
+ rgb(15 155 140 / 0.09),
+ transparent 60%
+ ),
+ radial-gradient(
+ 50rem 28rem at 10% 0%,
+ rgb(255 255 255 / 0.9),
+ transparent 65%
+ );
+}
+
+/* dotted connector line used by process steppers */
+@utility border-dotted-brand {
+ border-color: var(--brand-300);
+ border-style: dotted;
+}
diff --git a/v2/component-library/src/vite-env.d.ts b/v2/component-library/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/v2/component-library/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/v2/component-library/tsconfig.app.json b/v2/component-library/tsconfig.app.json
new file mode 100644
index 0000000..6d13264
--- /dev/null
+++ b/v2/component-library/tsconfig.app.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "ES2022",
+ "useDefineForClassFields": true,
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true,
+
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src"]
+}
diff --git a/v2/component-library/tsconfig.json b/v2/component-library/tsconfig.json
new file mode 100644
index 0000000..fec8c8e
--- /dev/null
+++ b/v2/component-library/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ],
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ }
+}
diff --git a/v2/component-library/tsconfig.node.json b/v2/component-library/tsconfig.node.json
new file mode 100644
index 0000000..b84ff16
--- /dev/null
+++ b/v2/component-library/tsconfig.node.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "target": "ES2023",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+ "types": ["node"],
+
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/v2/component-library/vite.config.ts b/v2/component-library/vite.config.ts
new file mode 100644
index 0000000..a949b57
--- /dev/null
+++ b/v2/component-library/vite.config.ts
@@ -0,0 +1,13 @@
+import path from "node:path"
+import tailwindcss from "@tailwindcss/vite"
+import react from "@vitejs/plugin-react"
+import { defineConfig } from "vite"
+
+export default defineConfig({
+ plugins: [react(), tailwindcss()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
+})
diff --git a/v2/gebos-site-assets/ASSET-MAP.md b/v2/gebos-site-assets/ASSET-MAP.md
new file mode 100644
index 0000000..50c4f16
--- /dev/null
+++ b/v2/gebos-site-assets/ASSET-MAP.md
@@ -0,0 +1,27 @@
+# GebOS visual asset map
+
+All page-specific folders contain an assembled preview and a short `assets.md`. Reusable masters live in `shared/` and should be referenced from there in production.
+
+| Page | Page-specific composition | Shared assets used |
+| --- | --- | --- |
+| 01 Homepage | `pages/01-homepage/hero.png` | Building, smoke alarm, teal bars, UVI badge, consumption ring, five feature icons |
+| 02 So funktioniert GebOS | `pages/02-process/steps.png` | UVI badge, building, glass cubes, package box, gateway, heat meter, wireless orb |
+| 03 Unsere Lösungen | `pages/03-solutions/cards.png` | Gateway, glass cubes, consumption ring, smoke alarm, euro orb |
+| 04 Für wen ist GebOS? | `pages/04-for-whom/hero.png` | Building, teal bars, consumption ring |
+| 05 Hauseigentümer | `pages/05-homeowners/hero.png` | Building, smoke alarm, check orb |
+| 06 Hausverwaltungen | `pages/06-property-management/hero.png` | Building, teal bars, consumption ring |
+| 07 Messdienstleister | `pages/07-metering-services/hero.png` | Laptop/dashboard, glass cubes, cloud/support |
+| 08 Installateure & Heizungsbauer | `pages/08-installers/hero.png` | Heat meter, gateway, glass cubes, check orb |
+| 09 Konfigurator | `pages/09-configurator/hero.png` | Euro orb, consumption ring |
+
+## Shared raster masters
+
+The building, smoke alarm, gateway, heat meter, and laptop use a clean pure-white matte. They are intended for the white or near-white backgrounds used throughout the concepts. WebP and AVIF derivatives are in `shared/raster/web/`.
+
+## Shared vectors
+
+The ring, bars, cubes, UVI badge, check orb, euro orb, cloud/support, package, and wireless badge are transparent editable SVGs. Their gradients use the same GebOS teal family and can be adjusted without rerendering.
+
+## Page previews
+
+Page composition PNGs are positioning references and quick drop-in images. For a responsive production website, compose the shared objects independently in HTML/CSS, using the page preview as the layout guide.
diff --git a/v2/gebos-site-assets/GENERATION-NOTES.md b/v2/gebos-site-assets/GENERATION-NOTES.md
new file mode 100644
index 0000000..fccde67
--- /dev/null
+++ b/v2/gebos-site-assets/GENERATION-NOTES.md
@@ -0,0 +1,21 @@
+# Raster generation notes
+
+The raster masters were generated with the built-in image workflow from the supplied GebOS concept board.
+
+## Shared prompt specification
+
+- Use case: product mockup / reusable website asset.
+- Style: premium high-key 3D product visualization matching the GebOS concept board.
+- Lighting: soft studio daylight from the upper left, cool-grey ambient shading and restrained reflections.
+- Background: uniform pure white.
+- Constraints: one isolated subject, generous padding, no brand text, no watermark, no unrelated floating elements.
+
+## Per-asset subjects
+
+- Building: modern white apartment building with glass balconies and sparse greenery, elevated three-quarter view.
+- Smoke alarm: white circular detector with perimeter vents, central test button and tiny teal status LED.
+- Gateway: softly rounded white square IoT enclosure with one teal status LED.
+- Heat meter: white cylindrical calculator head on a compact brass threaded flow body.
+- Laptop/dashboard: silver laptop with a navy/teal metering dashboard containing cards, bar chart and donut chart.
+
+The vectors were authored directly as SVG rather than generated as raster images.
diff --git a/v2/gebos-site-assets/README.md b/v2/gebos-site-assets/README.md
new file mode 100644
index 0000000..9a29927
--- /dev/null
+++ b/v2/gebos-site-assets/README.md
@@ -0,0 +1,34 @@
+# GebOS website visual assets
+
+This package contains the complete first-pass visual kit for all nine concept pages.
+
+Start with:
+
+1. `previews/all-pages-contact-sheet.png` for the overall visual inventory.
+2. `ASSET-MAP.md` for page-to-asset mappings.
+3. `pages//assets.md` for page-specific usage notes.
+4. `shared/` for reusable production masters.
+
+## Folder structure
+
+```text
+shared/
+ raster/source/ lossless PNG masters
+ raster/web/ WebP and AVIF derivatives
+ vector/ editable transparent SVG plus 2× PNG previews
+ icons/ small homepage feature icons
+pages/
+ 01-homepage/ ... 09-configurator/
+previews/
+ all-pages-contact-sheet.png
+```
+
+Each page composition is supplied as PNG and WebP. These compositions are convenient drop-ins and positioning references. For the responsive production site, compose the shared assets independently with CSS.
+
+## Important raster note
+
+The generated building and device renders use a pure-white matte. This is intentional for the white visual environment in the supplied concepts and avoids low-quality artificial alpha edges around white and translucent surfaces. The SVG assets have genuine transparency.
+
+## Rebuilding previews
+
+`build-previews.sh` deterministically rebuilds the page compositions from the shared assets using ImageMagick.
diff --git a/v2/gebos-site-assets/build-previews.sh b/v2/gebos-site-assets/build-previews.sh
new file mode 100755
index 0000000..38397cd
--- /dev/null
+++ b/v2/gebos-site-assets/build-previews.sh
@@ -0,0 +1,82 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+ROOT="$(cd "$(dirname "$0")" && pwd)"
+R="$ROOT/shared/raster/source"
+V="$ROOT/shared/vector"
+
+convert -size 1400x900 xc:white \
+ \( "$V/teal-bars@2x.png" -resize 390x330 \) -geometry +965+175 -composite \
+ \( "$R/building-master.png" -resize 900x680 \) -geometry +330+95 -compose multiply -composite \
+ \( "$R/smoke-alarm-master.png" -resize 190x190 \) -geometry +265+105 -compose multiply -composite \
+ \( "$V/uvi-badge@2x.png" -resize 145x175 \) -geometry +345+505 -compose over -composite \
+ \( "$V/consumption-ring@2x.png" -resize 430x270 \) -geometry +930+610 -compose over -composite \
+ "$ROOT/pages/01-homepage/hero.png"
+
+convert -size 1800x520 xc:white \
+ -stroke '#dce9eb' -strokewidth 3 -fill '#fbfdfd' \
+ -draw 'roundrectangle 30,60 330,470 24,24 roundrectangle 390,60 690,470 24,24 roundrectangle 750,60 1050,470 24,24 roundrectangle 1110,60 1410,470 24,24 roundrectangle 1470,60 1770,470 24,24' \
+ \( "$V/uvi-badge@2x.png" -resize 180x225 \) -geometry +90+155 -compose over -composite \
+ \( "$R/building-master.png" -resize 260x200 \) -geometry +402+180 -compose multiply -composite \
+ \( "$V/glass-cubes@2x.png" -resize 120x100 \) -geometry +555+315 -compose over -composite \
+ \( "$V/package-box@2x.png" -resize 205x190 \) -geometry +780+175 -compose over -composite \
+ \( "$R/gateway-master.png" -resize 100x100 \) -geometry +925+310 -compose multiply -composite \
+ \( "$R/heat-meter-master.png" -resize 170x170 \) -geometry +1125+210 -compose multiply -composite \
+ \( "$R/gateway-master.png" -resize 125x125 \) -geometry +1260+260 -compose multiply -composite \
+ \( "$V/wireless-orb@2x.png" -resize 165x165 \) -geometry +1510+160 -compose over -composite \
+ \( "$R/smoke-alarm-master.png" -resize 145x145 \) -geometry +1600+285 -compose multiply -composite \
+ "$ROOT/pages/02-process/steps.png"
+
+convert -size 1500x560 xc:white \
+ -stroke '#e0ebed' -strokewidth 3 -fill '#fbfdfd' \
+ -draw 'roundrectangle 30,40 470,520 28,28 roundrectangle 530,40 970,520 28,28 roundrectangle 1030,40 1470,520 28,28' \
+ \( "$R/gateway-master.png" -resize 270x270 \) -geometry +70+130 -compose multiply -composite \
+ \( "$V/glass-cubes@2x.png" -resize 220x185 \) -geometry +245+235 -compose over -composite \
+ \( "$V/consumption-ring@2x.png" -resize 400x255 \) -geometry +550+180 -compose over -composite \
+ \( "$R/smoke-alarm-master.png" -resize 310x310 \) -geometry +1095+130 -compose multiply -composite \
+ "$ROOT/pages/03-solutions/cards.png"
+
+convert -size 1400x850 xc:white \
+ \( "$V/teal-bars@2x.png" -resize 440x370 \) -geometry +930+150 -compose over -composite \
+ \( "$R/building-master.png" -resize 900x680 \) -geometry +300+75 -compose multiply -composite \
+ \( "$V/consumption-ring@2x.png" -resize 450x285 \) -geometry +875+570 -compose over -composite \
+ "$ROOT/pages/04-for-whom/hero.png"
+
+convert -size 1400x850 xc:white \
+ \( "$R/building-master.png" -resize 900x680 \) -geometry +420+75 -compose multiply -composite \
+ \( "$R/smoke-alarm-master.png" -resize 235x235 \) -geometry +245+125 -compose multiply -composite \
+ \( "$V/check-orb@2x.png" -resize 190x190 \) -geometry +360+430 -compose over -composite \
+ "$ROOT/pages/05-homeowners/hero.png"
+
+convert -size 1400x850 xc:white \
+ \( "$V/teal-bars@2x.png" -resize 440x370 \) -geometry +930+145 -compose over -composite \
+ \( "$R/building-master.png" -resize 900x680 \) -geometry +350+70 -compose multiply -composite \
+ \( "$V/consumption-ring@2x.png" -resize 420x265 \) -geometry +240+575 -compose over -composite \
+ "$ROOT/pages/06-property-management/hero.png"
+
+convert -size 1400x850 xc:white \
+ \( "$V/glass-cubes@2x.png" -resize 330x275 \) -geometry +160+495 -compose over -composite \
+ \( "$R/laptop-dashboard-master.png" -resize 900x600 \) -geometry +280+145 -compose multiply -composite \
+ \( "$V/cloud-support@2x.png" -resize 360x290 \) -geometry +990+50 -compose over -composite \
+ \( "$V/glass-cubes@2x.png" -resize 260x215 \) -geometry +1040+545 -compose over -composite \
+ "$ROOT/pages/07-metering-services/hero.png"
+
+convert -size 1400x850 xc:white \
+ \( "$R/heat-meter-master.png" -resize 430x430 \) -geometry +190+220 -compose multiply -composite \
+ \( "$R/gateway-master.png" -resize 470x470 \) -geometry +580+170 -compose multiply -composite \
+ \( "$V/glass-cubes@2x.png" -resize 350x290 \) -geometry +900+410 -compose over -composite \
+ \( "$V/check-orb@2x.png" -resize 190x190 \) -geometry +950+105 -compose over -composite \
+ "$ROOT/pages/08-installers/hero.png"
+
+convert -size 1400x850 xc:white \
+ \( "$V/euro-orb@2x.png" -resize 470x470 \) -geometry +250+180 -compose over -composite \
+ \( "$V/consumption-ring@2x.png" -resize 550x350 \) -geometry +700+335 -compose over -composite \
+ "$ROOT/pages/09-configurator/hero.png"
+
+montage \
+ "$ROOT/pages/01-homepage/hero.png" "$ROOT/pages/02-process/steps.png" "$ROOT/pages/03-solutions/cards.png" \
+ "$ROOT/pages/04-for-whom/hero.png" "$ROOT/pages/05-homeowners/hero.png" "$ROOT/pages/06-property-management/hero.png" \
+ "$ROOT/pages/07-metering-services/hero.png" "$ROOT/pages/08-installers/hero.png" "$ROOT/pages/09-configurator/hero.png" \
+ -thumbnail 560x340 -tile 3x3 -geometry +24+24 -background '#eef4f5' "$ROOT/previews/all-pages-contact-sheet.png"
+
+for img in "$ROOT"/pages/*/*.png; do convert "$img" -strip -quality 88 "${img%.png}.webp"; done
diff --git a/v2/gebos-site-assets/pages/01-homepage/assets.md b/v2/gebos-site-assets/pages/01-homepage/assets.md
new file mode 100644
index 0000000..bf8e7d0
--- /dev/null
+++ b/v2/gebos-site-assets/pages/01-homepage/assets.md
@@ -0,0 +1,7 @@
+# Homepage
+
+- `hero.png`: ready composition.
+- Shared: `building`, `smoke-alarm`, `teal-bars`, `uvi-badge`, `consumption-ring`.
+- Lower feature strip: all SVGs in `shared/icons/`.
+
+This is the same visual family as the previously delivered first-run kit.
diff --git a/v2/gebos-site-assets/pages/01-homepage/hero.png b/v2/gebos-site-assets/pages/01-homepage/hero.png
new file mode 100644
index 0000000..f21b366
Binary files /dev/null and b/v2/gebos-site-assets/pages/01-homepage/hero.png differ
diff --git a/v2/gebos-site-assets/pages/01-homepage/hero.webp b/v2/gebos-site-assets/pages/01-homepage/hero.webp
new file mode 100644
index 0000000..77f48b0
Binary files /dev/null and b/v2/gebos-site-assets/pages/01-homepage/hero.webp differ
diff --git a/v2/gebos-site-assets/pages/02-process/assets.md b/v2/gebos-site-assets/pages/02-process/assets.md
new file mode 100644
index 0000000..2b7a1ff
--- /dev/null
+++ b/v2/gebos-site-assets/pages/02-process/assets.md
@@ -0,0 +1,8 @@
+# So funktioniert GebOS
+
+- `steps.png`: five-step visual strip.
+- Step 1: `uvi-badge.svg` — building/data capture.
+- Step 2: `building` + `glass-cubes.svg` — determine equipment requirement.
+- Step 3: `package-box.svg` + `gateway` — preconfigured delivery.
+- Step 4: `gateway` + `heat-meter` — installation.
+- Step 5: `wireless-orb.svg` + `smoke-alarm` — automatic operation.
diff --git a/v2/gebos-site-assets/pages/02-process/steps.png b/v2/gebos-site-assets/pages/02-process/steps.png
new file mode 100644
index 0000000..81c83a7
Binary files /dev/null and b/v2/gebos-site-assets/pages/02-process/steps.png differ
diff --git a/v2/gebos-site-assets/pages/02-process/steps.webp b/v2/gebos-site-assets/pages/02-process/steps.webp
new file mode 100644
index 0000000..7e02be6
Binary files /dev/null and b/v2/gebos-site-assets/pages/02-process/steps.webp differ
diff --git a/v2/gebos-site-assets/pages/03-solutions/assets.md b/v2/gebos-site-assets/pages/03-solutions/assets.md
new file mode 100644
index 0000000..ec6c99e
--- /dev/null
+++ b/v2/gebos-site-assets/pages/03-solutions/assets.md
@@ -0,0 +1,7 @@
+# Unsere Lösungen
+
+- `cards.png`: three solution illustrations.
+- UVI: `gateway` + `glass-cubes.svg`.
+- Heizkostenabrechnung: `consumption-ring.svg`.
+- Rauchwarnmelder: `smoke-alarm`.
+- CTA price visual: `euro-orb.svg`.
diff --git a/v2/gebos-site-assets/pages/03-solutions/cards.png b/v2/gebos-site-assets/pages/03-solutions/cards.png
new file mode 100644
index 0000000..e347cfb
Binary files /dev/null and b/v2/gebos-site-assets/pages/03-solutions/cards.png differ
diff --git a/v2/gebos-site-assets/pages/03-solutions/cards.webp b/v2/gebos-site-assets/pages/03-solutions/cards.webp
new file mode 100644
index 0000000..75f6986
Binary files /dev/null and b/v2/gebos-site-assets/pages/03-solutions/cards.webp differ
diff --git a/v2/gebos-site-assets/pages/04-for-whom/assets.md b/v2/gebos-site-assets/pages/04-for-whom/assets.md
new file mode 100644
index 0000000..c430366
--- /dev/null
+++ b/v2/gebos-site-assets/pages/04-for-whom/assets.md
@@ -0,0 +1,5 @@
+# Für wen ist GebOS?
+
+- `hero.png`: building portfolio composition.
+- Shared: `building`, `teal-bars.svg`, `consumption-ring.svg`.
+- Reuse the audience/navigation icons from the site UI; they are not baked into the hero.
diff --git a/v2/gebos-site-assets/pages/04-for-whom/hero.png b/v2/gebos-site-assets/pages/04-for-whom/hero.png
new file mode 100644
index 0000000..2a5bdac
Binary files /dev/null and b/v2/gebos-site-assets/pages/04-for-whom/hero.png differ
diff --git a/v2/gebos-site-assets/pages/04-for-whom/hero.webp b/v2/gebos-site-assets/pages/04-for-whom/hero.webp
new file mode 100644
index 0000000..322d8f8
Binary files /dev/null and b/v2/gebos-site-assets/pages/04-for-whom/hero.webp differ
diff --git a/v2/gebos-site-assets/pages/05-homeowners/assets.md b/v2/gebos-site-assets/pages/05-homeowners/assets.md
new file mode 100644
index 0000000..db19a12
--- /dev/null
+++ b/v2/gebos-site-assets/pages/05-homeowners/assets.md
@@ -0,0 +1,5 @@
+# Für Hauseigentümer
+
+- `hero.png`: homeowner hero composition.
+- Shared: `building`, `smoke-alarm`, `check-orb.svg`.
+- The detached check badge can be positioned or animated independently.
diff --git a/v2/gebos-site-assets/pages/05-homeowners/hero.png b/v2/gebos-site-assets/pages/05-homeowners/hero.png
new file mode 100644
index 0000000..047154e
Binary files /dev/null and b/v2/gebos-site-assets/pages/05-homeowners/hero.png differ
diff --git a/v2/gebos-site-assets/pages/05-homeowners/hero.webp b/v2/gebos-site-assets/pages/05-homeowners/hero.webp
new file mode 100644
index 0000000..6bac23c
Binary files /dev/null and b/v2/gebos-site-assets/pages/05-homeowners/hero.webp differ
diff --git a/v2/gebos-site-assets/pages/06-property-management/assets.md b/v2/gebos-site-assets/pages/06-property-management/assets.md
new file mode 100644
index 0000000..27fe3a1
--- /dev/null
+++ b/v2/gebos-site-assets/pages/06-property-management/assets.md
@@ -0,0 +1,5 @@
+# Für Hausverwaltungen
+
+- `hero.png`: portfolio/rollout hero composition.
+- Shared: `building`, `teal-bars.svg`, `consumption-ring.svg`.
+- This deliberately reuses the same canonical building as the homepage and audience selector.
diff --git a/v2/gebos-site-assets/pages/06-property-management/hero.png b/v2/gebos-site-assets/pages/06-property-management/hero.png
new file mode 100644
index 0000000..e77de20
Binary files /dev/null and b/v2/gebos-site-assets/pages/06-property-management/hero.png differ
diff --git a/v2/gebos-site-assets/pages/06-property-management/hero.webp b/v2/gebos-site-assets/pages/06-property-management/hero.webp
new file mode 100644
index 0000000..344880a
Binary files /dev/null and b/v2/gebos-site-assets/pages/06-property-management/hero.webp differ
diff --git a/v2/gebos-site-assets/pages/07-metering-services/assets.md b/v2/gebos-site-assets/pages/07-metering-services/assets.md
new file mode 100644
index 0000000..88860d5
--- /dev/null
+++ b/v2/gebos-site-assets/pages/07-metering-services/assets.md
@@ -0,0 +1,5 @@
+# Für Messdienstleister
+
+- `hero.png`: platform hero composition.
+- Shared: `laptop-dashboard`, `glass-cubes.svg`, `cloud-support.svg`.
+- The screen is baked into the laptop master for this first run. Replace it later with a real product screenshot if needed.
diff --git a/v2/gebos-site-assets/pages/07-metering-services/hero.png b/v2/gebos-site-assets/pages/07-metering-services/hero.png
new file mode 100644
index 0000000..97218f6
Binary files /dev/null and b/v2/gebos-site-assets/pages/07-metering-services/hero.png differ
diff --git a/v2/gebos-site-assets/pages/07-metering-services/hero.webp b/v2/gebos-site-assets/pages/07-metering-services/hero.webp
new file mode 100644
index 0000000..6ffbde8
Binary files /dev/null and b/v2/gebos-site-assets/pages/07-metering-services/hero.webp differ
diff --git a/v2/gebos-site-assets/pages/08-installers/assets.md b/v2/gebos-site-assets/pages/08-installers/assets.md
new file mode 100644
index 0000000..9fc03ae
--- /dev/null
+++ b/v2/gebos-site-assets/pages/08-installers/assets.md
@@ -0,0 +1,5 @@
+# Für Installateure & Heizungsbauer
+
+- `hero.png`: installer product composition.
+- Shared: `heat-meter`, `gateway`, `glass-cubes.svg`, `check-orb.svg`.
+- Both device renders are independent so their spacing can adapt at smaller breakpoints.
diff --git a/v2/gebos-site-assets/pages/08-installers/hero.png b/v2/gebos-site-assets/pages/08-installers/hero.png
new file mode 100644
index 0000000..89f520f
Binary files /dev/null and b/v2/gebos-site-assets/pages/08-installers/hero.png differ
diff --git a/v2/gebos-site-assets/pages/08-installers/hero.webp b/v2/gebos-site-assets/pages/08-installers/hero.webp
new file mode 100644
index 0000000..19999b1
Binary files /dev/null and b/v2/gebos-site-assets/pages/08-installers/hero.webp differ
diff --git a/v2/gebos-site-assets/pages/09-configurator/assets.md b/v2/gebos-site-assets/pages/09-configurator/assets.md
new file mode 100644
index 0000000..4ac2b11
--- /dev/null
+++ b/v2/gebos-site-assets/pages/09-configurator/assets.md
@@ -0,0 +1,5 @@
+# Konfigurator
+
+- `hero.png`: price/configuration accent composition.
+- Shared: `euro-orb.svg`, `consumption-ring.svg`.
+- Both are true transparent SVG and suitable for subtle CSS motion.
diff --git a/v2/gebos-site-assets/pages/09-configurator/hero.png b/v2/gebos-site-assets/pages/09-configurator/hero.png
new file mode 100644
index 0000000..3d20226
Binary files /dev/null and b/v2/gebos-site-assets/pages/09-configurator/hero.png differ
diff --git a/v2/gebos-site-assets/pages/09-configurator/hero.webp b/v2/gebos-site-assets/pages/09-configurator/hero.webp
new file mode 100644
index 0000000..ebf7d5f
Binary files /dev/null and b/v2/gebos-site-assets/pages/09-configurator/hero.webp differ
diff --git a/v2/gebos-site-assets/previews/all-pages-contact-sheet.png b/v2/gebos-site-assets/previews/all-pages-contact-sheet.png
new file mode 100644
index 0000000..bb2e50d
Binary files /dev/null and b/v2/gebos-site-assets/previews/all-pages-contact-sheet.png differ
diff --git a/v2/gebos-site-assets/shared/icons/icon-billing.svg b/v2/gebos-site-assets/shared/icons/icon-billing.svg
new file mode 100644
index 0000000..6d113ef
--- /dev/null
+++ b/v2/gebos-site-assets/shared/icons/icon-billing.svg
@@ -0,0 +1 @@
+
diff --git a/v2/gebos-site-assets/shared/icons/icon-portal.svg b/v2/gebos-site-assets/shared/icons/icon-portal.svg
new file mode 100644
index 0000000..fd3a15d
--- /dev/null
+++ b/v2/gebos-site-assets/shared/icons/icon-portal.svg
@@ -0,0 +1 @@
+
diff --git a/v2/gebos-site-assets/shared/icons/icon-radio.svg b/v2/gebos-site-assets/shared/icons/icon-radio.svg
new file mode 100644
index 0000000..51d2e85
--- /dev/null
+++ b/v2/gebos-site-assets/shared/icons/icon-radio.svg
@@ -0,0 +1 @@
+
diff --git a/v2/gebos-site-assets/shared/icons/icon-smoke-alarm.svg b/v2/gebos-site-assets/shared/icons/icon-smoke-alarm.svg
new file mode 100644
index 0000000..fc835d5
--- /dev/null
+++ b/v2/gebos-site-assets/shared/icons/icon-smoke-alarm.svg
@@ -0,0 +1 @@
+
diff --git a/v2/gebos-site-assets/shared/icons/icon-uvi.svg b/v2/gebos-site-assets/shared/icons/icon-uvi.svg
new file mode 100644
index 0000000..5c4269a
--- /dev/null
+++ b/v2/gebos-site-assets/shared/icons/icon-uvi.svg
@@ -0,0 +1 @@
+
diff --git a/v2/gebos-site-assets/shared/raster/source/building-master.png b/v2/gebos-site-assets/shared/raster/source/building-master.png
new file mode 100644
index 0000000..4ad801f
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/source/building-master.png differ
diff --git a/v2/gebos-site-assets/shared/raster/source/gateway-master.png b/v2/gebos-site-assets/shared/raster/source/gateway-master.png
new file mode 100644
index 0000000..0affb56
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/source/gateway-master.png differ
diff --git a/v2/gebos-site-assets/shared/raster/source/heat-meter-master.png b/v2/gebos-site-assets/shared/raster/source/heat-meter-master.png
new file mode 100644
index 0000000..c8dc2ac
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/source/heat-meter-master.png differ
diff --git a/v2/gebos-site-assets/shared/raster/source/laptop-dashboard-master.png b/v2/gebos-site-assets/shared/raster/source/laptop-dashboard-master.png
new file mode 100644
index 0000000..e67fa81
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/source/laptop-dashboard-master.png differ
diff --git a/v2/gebos-site-assets/shared/raster/source/smoke-alarm-master.png b/v2/gebos-site-assets/shared/raster/source/smoke-alarm-master.png
new file mode 100644
index 0000000..2b120e0
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/source/smoke-alarm-master.png differ
diff --git a/v2/gebos-site-assets/shared/raster/web/building.avif b/v2/gebos-site-assets/shared/raster/web/building.avif
new file mode 100644
index 0000000..85ab5c4
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/web/building.avif differ
diff --git a/v2/gebos-site-assets/shared/raster/web/building.webp b/v2/gebos-site-assets/shared/raster/web/building.webp
new file mode 100644
index 0000000..dba0537
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/web/building.webp differ
diff --git a/v2/gebos-site-assets/shared/raster/web/gateway.avif b/v2/gebos-site-assets/shared/raster/web/gateway.avif
new file mode 100644
index 0000000..1c3fbc2
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/web/gateway.avif differ
diff --git a/v2/gebos-site-assets/shared/raster/web/gateway.webp b/v2/gebos-site-assets/shared/raster/web/gateway.webp
new file mode 100644
index 0000000..f6112a5
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/web/gateway.webp differ
diff --git a/v2/gebos-site-assets/shared/raster/web/heat-meter.avif b/v2/gebos-site-assets/shared/raster/web/heat-meter.avif
new file mode 100644
index 0000000..bd49b1c
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/web/heat-meter.avif differ
diff --git a/v2/gebos-site-assets/shared/raster/web/heat-meter.webp b/v2/gebos-site-assets/shared/raster/web/heat-meter.webp
new file mode 100644
index 0000000..88dca46
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/web/heat-meter.webp differ
diff --git a/v2/gebos-site-assets/shared/raster/web/laptop-dashboard.avif b/v2/gebos-site-assets/shared/raster/web/laptop-dashboard.avif
new file mode 100644
index 0000000..180023d
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/web/laptop-dashboard.avif differ
diff --git a/v2/gebos-site-assets/shared/raster/web/laptop-dashboard.webp b/v2/gebos-site-assets/shared/raster/web/laptop-dashboard.webp
new file mode 100644
index 0000000..0a65dca
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/web/laptop-dashboard.webp differ
diff --git a/v2/gebos-site-assets/shared/raster/web/smoke-alarm.avif b/v2/gebos-site-assets/shared/raster/web/smoke-alarm.avif
new file mode 100644
index 0000000..b48da37
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/web/smoke-alarm.avif differ
diff --git a/v2/gebos-site-assets/shared/raster/web/smoke-alarm.webp b/v2/gebos-site-assets/shared/raster/web/smoke-alarm.webp
new file mode 100644
index 0000000..b204345
Binary files /dev/null and b/v2/gebos-site-assets/shared/raster/web/smoke-alarm.webp differ
diff --git a/v2/gebos-site-assets/shared/vector/check-orb.svg b/v2/gebos-site-assets/shared/vector/check-orb.svg
new file mode 100644
index 0000000..faf92da
--- /dev/null
+++ b/v2/gebos-site-assets/shared/vector/check-orb.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/v2/gebos-site-assets/shared/vector/check-orb@2x.png b/v2/gebos-site-assets/shared/vector/check-orb@2x.png
new file mode 100644
index 0000000..5985dfc
Binary files /dev/null and b/v2/gebos-site-assets/shared/vector/check-orb@2x.png differ
diff --git a/v2/gebos-site-assets/shared/vector/cloud-support.svg b/v2/gebos-site-assets/shared/vector/cloud-support.svg
new file mode 100644
index 0000000..23f714e
--- /dev/null
+++ b/v2/gebos-site-assets/shared/vector/cloud-support.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/v2/gebos-site-assets/shared/vector/cloud-support@2x.png b/v2/gebos-site-assets/shared/vector/cloud-support@2x.png
new file mode 100644
index 0000000..c5cf2f2
Binary files /dev/null and b/v2/gebos-site-assets/shared/vector/cloud-support@2x.png differ
diff --git a/v2/gebos-site-assets/shared/vector/consumption-ring.svg b/v2/gebos-site-assets/shared/vector/consumption-ring.svg
new file mode 100644
index 0000000..1b8a2c0
--- /dev/null
+++ b/v2/gebos-site-assets/shared/vector/consumption-ring.svg
@@ -0,0 +1,41 @@
+
+ GebOS segmented consumption ring
+ A substantial eight-part white, teal and translucent cyan ring in three-quarter perspective.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/v2/gebos-site-assets/shared/vector/consumption-ring@2x.png b/v2/gebos-site-assets/shared/vector/consumption-ring@2x.png
new file mode 100644
index 0000000..6ef5f49
Binary files /dev/null and b/v2/gebos-site-assets/shared/vector/consumption-ring@2x.png differ
diff --git a/v2/gebos-site-assets/shared/vector/euro-orb.svg b/v2/gebos-site-assets/shared/vector/euro-orb.svg
new file mode 100644
index 0000000..ccd508d
--- /dev/null
+++ b/v2/gebos-site-assets/shared/vector/euro-orb.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+ €
+
diff --git a/v2/gebos-site-assets/shared/vector/euro-orb@2x.png b/v2/gebos-site-assets/shared/vector/euro-orb@2x.png
new file mode 100644
index 0000000..1d1c8b6
Binary files /dev/null and b/v2/gebos-site-assets/shared/vector/euro-orb@2x.png differ
diff --git a/v2/gebos-site-assets/shared/vector/glass-cubes.svg b/v2/gebos-site-assets/shared/vector/glass-cubes.svg
new file mode 100644
index 0000000..b8da634
--- /dev/null
+++ b/v2/gebos-site-assets/shared/vector/glass-cubes.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/v2/gebos-site-assets/shared/vector/glass-cubes@2x.png b/v2/gebos-site-assets/shared/vector/glass-cubes@2x.png
new file mode 100644
index 0000000..89dc9ac
Binary files /dev/null and b/v2/gebos-site-assets/shared/vector/glass-cubes@2x.png differ
diff --git a/v2/gebos-site-assets/shared/vector/package-box.svg b/v2/gebos-site-assets/shared/vector/package-box.svg
new file mode 100644
index 0000000..7fb719c
--- /dev/null
+++ b/v2/gebos-site-assets/shared/vector/package-box.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/v2/gebos-site-assets/shared/vector/package-box@2x.png b/v2/gebos-site-assets/shared/vector/package-box@2x.png
new file mode 100644
index 0000000..dd567e8
Binary files /dev/null and b/v2/gebos-site-assets/shared/vector/package-box@2x.png differ
diff --git a/v2/gebos-site-assets/shared/vector/teal-bars.svg b/v2/gebos-site-assets/shared/vector/teal-bars.svg
new file mode 100644
index 0000000..5a0f43a
--- /dev/null
+++ b/v2/gebos-site-assets/shared/vector/teal-bars.svg
@@ -0,0 +1,18 @@
+
+ GebOS translucent data bars
+ Five translucent teal isometric bars of increasing height.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/v2/gebos-site-assets/shared/vector/teal-bars@2x.png b/v2/gebos-site-assets/shared/vector/teal-bars@2x.png
new file mode 100644
index 0000000..9a69d3c
Binary files /dev/null and b/v2/gebos-site-assets/shared/vector/teal-bars@2x.png differ
diff --git a/v2/gebos-site-assets/shared/vector/uvi-badge.svg b/v2/gebos-site-assets/shared/vector/uvi-badge.svg
new file mode 100644
index 0000000..9e68439
--- /dev/null
+++ b/v2/gebos-site-assets/shared/vector/uvi-badge.svg
@@ -0,0 +1,22 @@
+
+ GebOS UVI sensor badge
+ A white sensor with a teal consumption display and wireless symbol.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/v2/gebos-site-assets/shared/vector/uvi-badge@2x.png b/v2/gebos-site-assets/shared/vector/uvi-badge@2x.png
new file mode 100644
index 0000000..b5abbf9
Binary files /dev/null and b/v2/gebos-site-assets/shared/vector/uvi-badge@2x.png differ
diff --git a/v2/gebos-site-assets/shared/vector/wireless-orb.svg b/v2/gebos-site-assets/shared/vector/wireless-orb.svg
new file mode 100644
index 0000000..13be9de
--- /dev/null
+++ b/v2/gebos-site-assets/shared/vector/wireless-orb.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/v2/gebos-site-assets/shared/vector/wireless-orb@2x.png b/v2/gebos-site-assets/shared/vector/wireless-orb@2x.png
new file mode 100644
index 0000000..e33052a
Binary files /dev/null and b/v2/gebos-site-assets/shared/vector/wireless-orb@2x.png differ