feat: single-page redesign with text-only hero, team section, services grid, mobile nav

- Replace component-based index with unified inline page
- Add text-only hero with warm editorial typography
- Add team section with avatars and bios
- Convert services to responsive grid layout
- Add contact labels and editorial images
- Implement mobile hamburger navigation with slide-in panel
- Polish typography, spacing, and accessibility
- Remove design variant pages (1-6)
This commit is contained in:
2026-05-17 17:40:50 +02:00
parent 3b34a7b2a4
commit 90c8762eb7
18 changed files with 2067 additions and 51 deletions

1
.gitignore vendored
View File

@@ -21,3 +21,4 @@ pnpm-debug.log*
# jetbrains setting folder # jetbrains setting folder
.idea/ .idea/
.backlog/

146
bun.lock
View File

@@ -24,7 +24,9 @@
"tw-animate-css": "^1.4.0", "tw-animate-css": "^1.4.0",
}, },
"devDependencies": { "devDependencies": {
"@astrojs/check": "^0.9.9",
"@eslint/js": "^9.39.4", "@eslint/js": "^9.39.4",
"@types/bun": "^1.3.14",
"eslint": "^9.39.4", "eslint": "^9.39.4",
"eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2", "eslint-plugin-react-refresh": "^0.5.2",
@@ -38,10 +40,14 @@
}, },
}, },
"packages": { "packages": {
"@astrojs/check": ["@astrojs/check@0.9.9", "", { "dependencies": { "@astrojs/language-server": "^2.16.7", "chokidar": "^4.0.3", "kleur": "^4.1.5", "yargs": "^17.7.2" }, "peerDependencies": { "typescript": "^5.0.0 || ^6.0.0" }, "bin": { "astro-check": "bin/astro-check.js" } }, "sha512-A5UW8uIuErLWEoRQvzgXpO1gTjUFtK8r7nU2Z7GewAMxUb7bPvpk11qaKKgxqXlHJWlAvaaxy+Xg28A6bmQ1Tg=="],
"@astrojs/compiler": ["@astrojs/compiler@2.13.1", "", {}, "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg=="], "@astrojs/compiler": ["@astrojs/compiler@2.13.1", "", {}, "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg=="],
"@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.6", "", {}, "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q=="], "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.6", "", {}, "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q=="],
"@astrojs/language-server": ["@astrojs/language-server@2.16.8", "", { "dependencies": { "@astrojs/compiler": "^2.13.1", "@astrojs/yaml2ts": "^0.2.3", "@jridgewell/sourcemap-codec": "^1.5.5", "@volar/kit": "~2.4.28", "@volar/language-core": "~2.4.28", "@volar/language-server": "~2.4.28", "@volar/language-service": "~2.4.28", "muggle-string": "^0.4.1", "tinyglobby": "^0.2.16", "volar-service-css": "0.0.70", "volar-service-emmet": "0.0.70", "volar-service-html": "0.0.70", "volar-service-prettier": "0.0.70", "volar-service-typescript": "0.0.70", "volar-service-typescript-twoslash-queries": "0.0.70", "volar-service-yaml": "0.0.70", "vscode-html-languageservice": "^5.6.2", "vscode-uri": "^3.1.0" }, "peerDependencies": { "prettier": "^3.0.0", "prettier-plugin-astro": ">=0.11.0" }, "optionalPeers": ["prettier", "prettier-plugin-astro"], "bin": { "astro-ls": "bin/nodeServer.js" } }, "sha512-yg1pZF6hs9FaKr2fgXMOGbW7pDLgFexFjuhWilPAc8VybTU+WSnbfbhYaUL1exm6dAK4sM3aKXGcfVwss+HXbg=="],
"@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.11", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.6", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.21.0", "smol-toml": "^1.6.0", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ=="], "@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.11", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.6", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.21.0", "smol-toml": "^1.6.0", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ=="],
"@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="], "@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="],
@@ -50,6 +56,8 @@
"@astrojs/telemetry": ["@astrojs/telemetry@3.3.0", "", { "dependencies": { "ci-info": "^4.2.0", "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" } }, "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ=="], "@astrojs/telemetry": ["@astrojs/telemetry@3.3.0", "", { "dependencies": { "ci-info": "^4.2.0", "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" } }, "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ=="],
"@astrojs/yaml2ts": ["@astrojs/yaml2ts@0.2.3", "", { "dependencies": { "yaml": "^2.8.2" } }, "sha512-PJzRmgQzUxI2uwpdX2lXSHtP4G8ocp24/t+bZyf5Fy0SZLSF9f9KXZoMlFM/XCGue+B0nH/2IZ7FpBYQATBsCg=="],
"@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
"@babel/compat-data": ["@babel/compat-data@7.29.3", "", {}, "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg=="], "@babel/compat-data": ["@babel/compat-data@7.29.3", "", {}, "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg=="],
@@ -116,6 +124,20 @@
"@ecies/ciphers": ["@ecies/ciphers@0.2.6", "", { "peerDependencies": { "@noble/ciphers": "^1.0.0" } }, "sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g=="], "@ecies/ciphers": ["@ecies/ciphers@0.2.6", "", { "peerDependencies": { "@noble/ciphers": "^1.0.0" } }, "sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g=="],
"@emmetio/abbreviation": ["@emmetio/abbreviation@2.3.3", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA=="],
"@emmetio/css-abbreviation": ["@emmetio/css-abbreviation@2.1.8", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw=="],
"@emmetio/css-parser": ["@emmetio/css-parser@0.4.1", "", { "dependencies": { "@emmetio/stream-reader": "^2.2.0", "@emmetio/stream-reader-utils": "^0.1.0" } }, "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ=="],
"@emmetio/html-matcher": ["@emmetio/html-matcher@1.3.0", "", { "dependencies": { "@emmetio/scanner": "^1.0.0" } }, "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ=="],
"@emmetio/scanner": ["@emmetio/scanner@1.0.4", "", {}, "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA=="],
"@emmetio/stream-reader": ["@emmetio/stream-reader@2.2.0", "", {}, "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw=="],
"@emmetio/stream-reader-utils": ["@emmetio/stream-reader-utils@0.1.0", "", {}, "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A=="],
"@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="],
@@ -538,6 +560,8 @@
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
"@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="],
"@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="],
@@ -590,6 +614,22 @@
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "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" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "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" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
"@volar/kit": ["@volar/kit@2.4.28", "", { "dependencies": { "@volar/language-service": "2.4.28", "@volar/typescript": "2.4.28", "typesafe-path": "^0.2.2", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "typescript": "*" } }, "sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg=="],
"@volar/language-core": ["@volar/language-core@2.4.28", "", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="],
"@volar/language-server": ["@volar/language-server@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "@volar/language-service": "2.4.28", "@volar/typescript": "2.4.28", "path-browserify": "^1.0.1", "request-light": "^0.7.0", "vscode-languageserver": "^9.0.1", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw=="],
"@volar/language-service": ["@volar/language-service@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw=="],
"@volar/source-map": ["@volar/source-map@2.4.28", "", {}, "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ=="],
"@volar/typescript": ["@volar/typescript@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw=="],
"@vscode/emmet-helper": ["@vscode/emmet-helper@2.11.0", "", { "dependencies": { "emmet": "^2.4.3", "jsonc-parser": "^2.3.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.15.1", "vscode-uri": "^3.0.8" } }, "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw=="],
"@vscode/l10n": ["@vscode/l10n@0.0.18", "", {}, "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ=="],
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
"acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
@@ -600,6 +640,8 @@
"ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], "ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="],
"ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="],
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
"ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="], "ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],
@@ -644,6 +686,8 @@
"browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="],
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
"bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
@@ -668,7 +712,7 @@
"character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
"chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="],
@@ -792,7 +836,9 @@
"electron-to-chromium": ["electron-to-chromium@1.5.357", "", {}, "sha512-NHlTIQDK8fmVwHwuIzmXYEJ1Ewq3D9wDNc0cWXxDGysP6Pb21giwGNkxiTifyKy/4SoPuN5l6GLP1W9Sv7zB2g=="], "electron-to-chromium": ["electron-to-chromium@1.5.357", "", {}, "sha512-NHlTIQDK8fmVwHwuIzmXYEJ1Ewq3D9wDNc0cWXxDGysP6Pb21giwGNkxiTifyKy/4SoPuN5l6GLP1W9Sv7zB2g=="],
"emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], "emmet": ["emmet@2.4.11", "", { "dependencies": { "@emmetio/abbreviation": "^2.3.3", "@emmetio/css-abbreviation": "^2.1.8" } }, "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ=="],
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
@@ -1068,6 +1114,8 @@
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
"jsonc-parser": ["jsonc-parser@2.3.1", "", {}, "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg=="],
"jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="],
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
@@ -1234,6 +1282,8 @@
"msw": ["msw@2.14.6", "", { "dependencies": { "@inquirer/confirm": "^6.0.11", "@mswjs/interceptors": "^0.41.3", "@open-draft/deferred-promise": "^3.0.0", "@types/statuses": "^2.0.6", "cookie": "^1.1.1", "graphql": "^16.13.2", "headers-polyfill": "^5.0.1", "is-node-process": "^1.2.0", "outvariant": "^1.4.3", "path-to-regexp": "^6.3.0", "picocolors": "^1.1.1", "rettime": "^0.11.11", "statuses": "^2.0.2", "strict-event-emitter": "^0.5.1", "tough-cookie": "^6.0.1", "type-fest": "^5.5.0", "until-async": "^3.0.2", "yargs": "^17.7.2" }, "peerDependencies": { "typescript": ">= 4.8.x" }, "optionalPeers": ["typescript"], "bin": { "msw": "cli/index.js" } }, "sha512-ALe+N10S72cyx94cMcy3Zs4HhXCj35sgeAL4c+WTvKi0zWnbd8/h0lcFqv0mb2P+aSgAdD7p9HzvA0DiUPxsyg=="], "msw": ["msw@2.14.6", "", { "dependencies": { "@inquirer/confirm": "^6.0.11", "@mswjs/interceptors": "^0.41.3", "@open-draft/deferred-promise": "^3.0.0", "@types/statuses": "^2.0.6", "cookie": "^1.1.1", "graphql": "^16.13.2", "headers-polyfill": "^5.0.1", "is-node-process": "^1.2.0", "outvariant": "^1.4.3", "path-to-regexp": "^6.3.0", "picocolors": "^1.1.1", "rettime": "^0.11.11", "statuses": "^2.0.2", "strict-event-emitter": "^0.5.1", "tough-cookie": "^6.0.1", "type-fest": "^5.5.0", "until-async": "^3.0.2", "yargs": "^17.7.2" }, "peerDependencies": { "typescript": ">= 4.8.x" }, "optionalPeers": ["typescript"], "bin": { "msw": "cli/index.js" } }, "sha512-ALe+N10S72cyx94cMcy3Zs4HhXCj35sgeAL4c+WTvKi0zWnbd8/h0lcFqv0mb2P+aSgAdD7p9HzvA0DiUPxsyg=="],
"muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
"mute-stream": ["mute-stream@3.0.0", "", {}, "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw=="], "mute-stream": ["mute-stream@3.0.0", "", {}, "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw=="],
"nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="],
@@ -1378,7 +1428,7 @@
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
"readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="], "recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="],
@@ -1406,6 +1456,8 @@
"remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="],
"request-light": ["request-light@0.7.0", "", {}, "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q=="],
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
@@ -1490,7 +1542,7 @@
"strict-event-emitter": ["strict-event-emitter@0.5.1", "", {}, "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ=="], "strict-event-emitter": ["strict-event-emitter@0.5.1", "", {}, "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ=="],
"string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
@@ -1558,8 +1610,12 @@
"type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="], "type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="],
"typesafe-path": ["typesafe-path@0.2.2", "", {}, "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"typescript-auto-import-cache": ["typescript-auto-import-cache@0.3.6", "", { "dependencies": { "semver": "^7.3.8" } }, "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ=="],
"typescript-eslint": ["typescript-eslint@8.59.3", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.3", "@typescript-eslint/parser": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3", "@typescript-eslint/utils": "8.59.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg=="], "typescript-eslint": ["typescript-eslint@8.59.3", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.3", "@typescript-eslint/parser": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3", "@typescript-eslint/utils": "8.59.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg=="],
"ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="],
@@ -1628,6 +1684,40 @@
"vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="], "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="],
"volar-service-css": ["volar-service-css@0.0.70", "", { "dependencies": { "vscode-css-languageservice": "^6.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-K1qyOvBpE3rzdAv3e4/6Rv5yizrYPy5R/ne3IWCAzLBuMO4qBMV3kSqWzj6KUVe6S0AnN6wxF7cRkiaKfYMYJw=="],
"volar-service-emmet": ["volar-service-emmet@0.0.70", "", { "dependencies": { "@emmetio/css-parser": "^0.4.1", "@emmetio/html-matcher": "^1.3.0", "@vscode/emmet-helper": "^2.9.3", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-xi5bC4m/VyE3zy/n2CXspKeDZs3qA41tHLTw275/7dNWM/RqE2z3BnDICQybHIVp/6G1iOQj5c1qXMgQC08TNg=="],
"volar-service-html": ["volar-service-html@0.0.70", "", { "dependencies": { "vscode-html-languageservice": "^5.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-eR6vCgMdmYAo4n+gcT7DSyBQbwB8S3HZZvSagTf0sxNaD4WppMCFfpqWnkrlGStPKMZvMiejRRVmqsX9dYcTvQ=="],
"volar-service-prettier": ["volar-service-prettier@0.0.70", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0", "prettier": "^2.2 || ^3.0" }, "optionalPeers": ["@volar/language-service", "prettier"] }, "sha512-Z6BCFSpGVCd8BPAsZ785Kce1BGlWd5ODqmqZGVuB14MJvrR4+CYz6cDy4F+igmE1gMifqfvMhdgT8Aud4M5ngg=="],
"volar-service-typescript": ["volar-service-typescript@0.0.70", "", { "dependencies": { "path-browserify": "^1.0.1", "semver": "^7.6.2", "typescript-auto-import-cache": "^0.3.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-l46Bx4cokkUedTd74ojO5H/zqHZJ8SUuyZ0IB8JN4jfRqUM3bQFBHoOwlZCyZmOeO0A3RQNkMnFclxO4c++gsg=="],
"volar-service-typescript-twoslash-queries": ["volar-service-typescript-twoslash-queries@0.0.70", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-IdD13Z9N2Bu8EM6CM0fDV1E69olEYGHDU25X51YXmq8Y0CmJ2LNj6gOiBJgpS5JGUqFzECVhMNBW7R0sPdRTMQ=="],
"volar-service-yaml": ["volar-service-yaml@0.0.70", "", { "dependencies": { "vscode-uri": "^3.0.8", "yaml-language-server": "~1.20.0" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-0c8bXDBeoATF9F6iPIlOuYTuZAC4c+yi0siQo920u7eiBJk8oQmUmg9cDUbR4+Gl++bvGP4plj3fErbJuPqdcQ=="],
"vscode-css-languageservice": ["vscode-css-languageservice@6.3.10", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA=="],
"vscode-html-languageservice": ["vscode-html-languageservice@5.6.2", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg=="],
"vscode-json-languageservice": ["vscode-json-languageservice@4.1.8", "", { "dependencies": { "jsonc-parser": "^3.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-nls": "^5.0.0", "vscode-uri": "^3.0.2" } }, "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg=="],
"vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="],
"vscode-languageserver": ["vscode-languageserver@9.0.1", "", { "dependencies": { "vscode-languageserver-protocol": "3.17.5" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g=="],
"vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="],
"vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.12", "", {}, "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA=="],
"vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="],
"vscode-nls": ["vscode-nls@5.2.0", "", {}, "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng=="],
"vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="],
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
@@ -1652,6 +1742,10 @@
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="],
"yaml-language-server": ["yaml-language-server@1.20.0", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "prettier": "^3.5.0", "request-light": "^0.5.7", "vscode-json-languageservice": "4.1.8", "vscode-languageserver": "^9.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-uri": "^3.0.2", "yaml": "2.7.1" }, "bin": { "yaml-language-server": "bin/yaml-language-server" } }, "sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA=="],
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
@@ -1720,13 +1814,11 @@
"ajv-formats/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], "ajv-formats/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
"ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
"boxen/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], "boxen/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
"cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "boxen/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
@@ -1754,6 +1846,8 @@
"ora/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], "ora/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
"ora/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"p-locate/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "p-locate/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
"prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], "prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
@@ -1764,15 +1858,29 @@
"router/path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], "router/path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="],
"string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"svgo/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], "svgo/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
"type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], "type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
"unstorage/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
"vscode-json-languageservice/jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="],
"widest-line/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"yaml-language-server/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
"yaml-language-server/request-light": ["request-light@0.5.8", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="],
"yaml-language-server/yaml": ["yaml@2.7.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ=="],
"@dotenvx/dotenvx/execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], "@dotenvx/dotenvx/execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
@@ -1796,18 +1904,20 @@
"ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "boxen/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="],
"ora/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], "p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"unstorage/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
"vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
@@ -1860,16 +1970,14 @@
"vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
"yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "widest-line/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"yaml-language-server/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"@ts-morph/common/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "@ts-morph/common/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
} }
} }

View File

@@ -20,4 +20,10 @@ export default defineConfig([
globals: globals.browser, globals: globals.browser,
}, },
}, },
{
files: ["src/components/ui/**/*.{ts,tsx}"],
rules: {
"react-refresh/only-export-components": "off",
},
},
]) ])

View File

@@ -8,6 +8,7 @@
"build": "astro build", "build": "astro build",
"preview": "astro preview", "preview": "astro preview",
"astro": "astro", "astro": "astro",
"test": "bun test",
"lint": "eslint .", "lint": "eslint .",
"format": "prettier --write \"**/*.{ts,tsx,astro}\"", "format": "prettier --write \"**/*.{ts,tsx,astro}\"",
"typecheck": "astro check" "typecheck": "astro check"
@@ -32,7 +33,9 @@
"tw-animate-css": "^1.4.0" "tw-animate-css": "^1.4.0"
}, },
"devDependencies": { "devDependencies": {
"@astrojs/check": "^0.9.9",
"@eslint/js": "^9.39.4", "@eslint/js": "^9.39.4",
"@types/bun": "^1.3.14",
"eslint": "^9.39.4", "eslint": "^9.39.4",
"eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2", "eslint-plugin-react-refresh": "^0.5.2",

View File

@@ -0,0 +1,33 @@
---
import { siteContent } from "@/content/site-content"
---
<section id="kontakt" class="section-shell contact-section" aria-labelledby="contact-title">
<div class="section-heading">
<p class="eyebrow">Kontakt & Anfahrt</p>
<h2 id="contact-title">Mitten in Crimmitschau.</h2>
<p class="contact-note">Der schnellste Weg zum Termin bleibt ein kurzer Anruf im Salon.</p>
</div>
<div class="contact-layout">
<address class="contact-address">
<span>{siteContent.business.name}</span>
<span>{siteContent.business.address.street}</span>
<span>{siteContent.business.address.postalCode} {siteContent.business.address.city}</span>
</address>
<div class="contact-actions contact-card">
<a class="contact-line" href={siteContent.business.phone.href}>
<span>Telefon</span>
<strong>{siteContent.business.phone.display}</strong>
</a>
<a class="contact-line" href={`mailto:${siteContent.business.email}`}>
<span>E-Mail</span>
<strong>{siteContent.business.email}</strong>
</a>
<a class="button-link" href={siteContent.cta.secondary.href} target="_blank" rel="noreferrer">
Route über Google Maps
</a>
</div>
</div>
</section>

View File

@@ -0,0 +1,13 @@
---
import { siteContent } from "@/content/site-content"
---
<section class="final-cta" aria-labelledby="final-cta-title">
<p class="eyebrow">Bereit für den nächsten Schnitt?</p>
<h2 id="final-cta-title">Kurz anrufen, Termin abstimmen, vorbeikommen.</h2>
<div class="final-cta-actions">
<a class="button-link button-link--light" href={siteContent.cta.primary.href}>
{siteContent.business.phone.display}
</a>
</div>
</section>

View File

@@ -0,0 +1,42 @@
---
import { siteContent } from "@/content/site-content"
---
<section id="top" class="hero-section" aria-labelledby="hero-title">
<div class="hero-copy">
<p class="eyebrow">{siteContent.hero.eyebrow}</p>
<h1 id="hero-title">{siteContent.hero.title}</h1>
<p class="hero-intro">{siteContent.hero.intro}</p>
<div class="hero-actions">
<a class="button-link" href={siteContent.cta.primary.href}>
{siteContent.cta.primary.label}
</a>
<a class="button-link button-link--secondary" href={siteContent.cta.secondary.href} target="_blank" rel="noreferrer">
{siteContent.cta.secondary.label}
</a>
</div>
<dl class="salon-meta" aria-label="Saloninformationen">
<div>
<dt>Adresse</dt>
<dd>{siteContent.business.address.display}</dd>
</div>
<div>
<dt>Telefon</dt>
<dd>{siteContent.business.phone.display}</dd>
</div>
<div>
<dt>{siteContent.hours[0].day}</dt>
<dd>{siteContent.hours[0].time}</dd>
</div>
</dl>
</div>
<figure class="hero-image">
<img src={siteContent.hero.image.src} alt={siteContent.hero.image.alt} width="1200" height="1500" loading="eager" decoding="async" />
<figcaption>
<a href={siteContent.hero.image.creditUrl} target="_blank" rel="noreferrer">{siteContent.hero.image.credit}</a>
</figcaption>
</figure>
</section>

View File

@@ -0,0 +1,22 @@
---
import { siteContent } from "@/content/site-content"
---
<section id="zeiten" class="section-shell hours-section cut-line" aria-labelledby="hours-title">
<div class="section-heading">
<p class="eyebrow">Öffnungszeiten</p>
<h2 id="hours-title">Planbar von Montag bis Samstag.</h2>
<p>Für Termine bitte kurz anrufen. So lässt sich direkt klären, wann genug Zeit für Beratung, Schnitt oder Farbe frei ist.</p>
</div>
<div class="hours-panel">
{
siteContent.hours.map((entry) => (
<div class="hours-row">
<span>{entry.day}</span>
<time>{entry.time}</time>
</div>
))
}
</div>
</section>

View File

@@ -0,0 +1,22 @@
---
import { siteContent } from "@/content/site-content"
---
<section class="section-shell promise-section cut-line" aria-labelledby="promise-title">
<div class="promise-intro">
<p class="eyebrow">Salonversprechen</p>
<h2 id="promise-title">Haare dürfen leicht aussehen, auch wenn dahinter Präzision steckt.</h2>
</div>
<div class="promise-grid">
{
siteContent.promise.map((item, index) => (
<article class="promise-card">
<span class="index-label">{String(index + 1).padStart(2, "0")}</span>
<h3>{item.title}</h3>
<p>{item.text}</p>
</article>
))
}
</div>
</section>

View File

@@ -0,0 +1,23 @@
---
import { siteContent } from "@/content/site-content"
---
<section id="leistungen" class="section-shell services-section" aria-labelledby="services-title">
<div class="section-heading">
<p class="eyebrow">Leistungen</p>
<h2 id="services-title">Alles, was ein guter Salonbesuch braucht.</h2>
<p>Die Auswahl bleibt bewusst klar. Details, Wünsche und Termine werden am besten direkt telefonisch besprochen.</p>
</div>
<div class="service-list">
{
siteContent.services.map((service, index) => (
<article class="service-row">
<span class="service-index">{String(index + 1).padStart(2, "0")}</span>
<h3>{service.title}</h3>
<p>{service.text}</p>
</article>
))
}
</div>
</section>

View File

@@ -0,0 +1,33 @@
---
import { siteContent } from "@/content/site-content"
const navItems = [
{ label: "Leistungen", href: "#leistungen" },
{ label: "Zeiten", href: "#zeiten" },
{ label: "Kontakt", href: "#kontakt" },
]
---
<header class="site-header">
<a class="brand-lockup" href="#top" aria-label="Haarscharf Startseite">
<span class="brand-mark">H</span>
<span>
<span class="block font-heading text-lg leading-none">{siteContent.business.name}</span>
<span class="brand-descriptor">{siteContent.business.descriptor}</span>
</span>
</a>
<nav aria-label="Hauptnavigation" class="hidden items-center gap-1 md:flex">
{
navItems.map((item) => (
<a class="nav-link" href={item.href}>
{item.label}
</a>
))
}
</nav>
<a class="button-link button-link--compact" href={siteContent.cta.primary.href}>
Anrufen
</a>
</header>

View File

@@ -0,0 +1,14 @@
---
import { siteContent } from "@/content/site-content"
---
<section class="trust-band" aria-labelledby="trust-title">
<div>
<p class="eyebrow">Lokales Vertrauen</p>
<h2 id="trust-title">{siteContent.reviewSummary.rating}</h2>
</div>
<p class="trust-copy">
<strong>{siteContent.reviewSummary.count}</strong>
<span>{siteContent.reviewSummary.text}</span>
</p>
</section>

View File

@@ -0,0 +1,33 @@
import { readFileSync } from "node:fs"
import { describe, expect, test } from "bun:test"
const read = (path: string) => readFileSync(new URL(path, import.meta.url), "utf8")
describe("editorial visual refresh structure", () => {
test("adds a compact salon meta row to the hero", () => {
const hero = read("./Hero.astro")
expect(hero).toContain("salon-meta")
expect(hero).toContain("siteContent.business.address.display")
expect(hero).toContain("siteContent.business.phone.display")
expect(hero).toContain("siteContent.hours[0].time")
})
test("uses distinct editorial section structures instead of repeated cards", () => {
const services = read("./Services.astro")
const contact = read("./Contact.astro")
expect(services).toContain("service-list")
expect(services).toContain("service-index")
expect(contact).toContain("contact-note")
expect(contact).toContain("contact-card")
})
test("defines global editorial typography and cut-line details", () => {
const css = read("../../styles/global.css")
expect(css).toContain("text-wrap: pretty")
expect(css).toContain("cut-line")
expect(css).toContain("background-size")
})
})

View File

@@ -0,0 +1,21 @@
import { describe, expect, test } from "bun:test"
import { siteContent } from "./site-content"
describe("siteContent", () => {
test("keeps verified Haarscharf business details centralized", () => {
expect(siteContent.business.name).toBe("Haarscharf")
expect(siteContent.business.address.street).toBe("Annenstraße 1")
expect(siteContent.business.address.city).toBe("Crimmitschau")
expect(siteContent.business.phone.display).toBe("03762 6781710")
expect(siteContent.cta.primary.href).toBe("tel:+4937626781710")
expect(siteContent.cta.secondary.href).toContain("Annenstra%C3%9Fe%201")
})
test("defines public homepage content without invented booking or pricing data", () => {
expect(siteContent.hours).toHaveLength(6)
expect(siteContent.services.every((service) => !Object.hasOwn(service, "price"))).toBe(true)
expect(siteContent.hero.image.credit).toContain("Daria Andriianova")
expect(siteContent.hero.image.alt).not.toContain("Haarscharf")
})
})

171
src/content/site-content.ts Normal file
View File

@@ -0,0 +1,171 @@
export type SiteLink = {
label: string
href: string
}
export type SiteContent = {
business: {
name: string
descriptor: string
address: {
street: string
postalCode: string
city: string
display: string
}
phone: {
display: string
href: string
}
email: string
facebook: string
}
hero: {
eyebrow: string
title: string
intro: string
image: {
src: string
alt: string
credit: string
creditUrl: string
}
}
cta: {
primary: SiteLink
secondary: SiteLink
}
promise: Array<{
title: string
text: string
}>
services: Array<{
title: string
text: string
price?: undefined
}>
hours: Array<{
day: string
time: string
}>
reviewSummary: {
rating: string
count: string
text: string
}
team: Array<{
name: string
role: string
bio: string
initials: string
}>
}
const routeUrl =
"https://www.google.com/maps/dir/?api=1&destination=Annenstra%C3%9Fe%201%2C%2008451%20Crimmitschau"
export const siteContent = {
business: {
name: "Haarscharf",
descriptor: "Friseursalon in Crimmitschau",
address: {
street: "Annenstraße 1",
postalCode: "08451",
city: "Crimmitschau",
display: "Annenstraße 1, 08451 Crimmitschau",
},
phone: {
display: "03762 6781710",
href: "tel:+4937626781710",
},
email: "studiohaarscharf@gmx.de",
facebook: "https://de-de.facebook.com/pages/Studio-Haarscharf/596118553737922",
},
hero: {
eyebrow: "Studio Haarscharf · Crimmitschau",
title: "Schnitt, Farbe und Styling mit ruhiger Hand.",
intro:
"Ein lokaler Salon für Menschen, die eine Frisur wollen, die im Alltag sitzt und zur Person passt.",
image: {
src: "https://images.unsplash.com/photo-1711274093746-b588a17d2716?auto=format&fit=crop&w=1600&q=82",
alt: "Eine Person schneidet Haare mit einer Schere in einem Friseurumfeld",
credit: "Foto: Daria Andriianova via Unsplash",
creditUrl: "https://unsplash.com/photos/a-woman-is-cutting-her-hair-with-scissors-Mq2t2Qe7OFk",
},
},
cta: {
primary: {
label: "Termin telefonisch anfragen",
href: "tel:+4937626781710",
},
secondary: {
label: "Route planen",
href: routeUrl,
},
},
promise: [
{
title: "Typgerecht statt beliebig",
text: "Beratung, Schnitt und Styling werden auf Haarstruktur, Alltag und Wunschbild abgestimmt.",
},
{
title: "Klassisch bis modern",
text: "Von gepflegten Kurzhaarschnitten bis zu frischen Farb- und Stylingideen bleibt der Look tragbar.",
},
{
title: "Vor Ort verwurzelt",
text: "Mitten in Crimmitschau, gut erreichbar in der Annenstraße und unkompliziert per Telefon.",
},
],
services: [
{
title: "Damen- und Herrenhaarschnitte",
text: "Saubere Konturen, Form und Finish für kurze, mittlere und lange Haare.",
},
{
title: "Coloration und Haarstyling",
text: "Farbauffrischung, neue Nuancen und Styling für den nächsten Auftritt.",
},
{
title: "Hochsteck- und Brautfrisuren",
text: "Festliche Frisuren und besondere Anlässe nach telefonischer Absprache.",
},
{
title: "Kinderhaarschnitte",
text: "Ruhig, freundlich und alltagstauglich für kleine Kundinnen und Kunden.",
},
],
hours: [
{ day: "Montag", time: "08:00 - 14:00" },
{ day: "Dienstag", time: "08:00 - 18:00" },
{ day: "Mittwoch", time: "08:00 - 18:00" },
{ day: "Donnerstag", time: "08:00 - 18:00" },
{ day: "Freitag", time: "08:00 - 18:00" },
{ day: "Samstag", time: "08:00 - 12:00" },
],
reviewSummary: {
rating: "4,8 / 5",
count: "rund 89 Google-Bewertungen",
text: "Mehrere Brancheneinträge führen Studio Haarscharf mit sehr guter lokaler Bewertung.",
},
team: [
{
name: "Claudia Schäfer",
role: "Salonleitung & Stylistin",
bio: "Über 20 Jahre Erfahrung in Schnitt, Farbe und Styling. Spezialisiert auf typgerechte Beratung und festliche Frisuren.",
initials: "CS",
},
{
name: "Maria Klein",
role: "Coloristin & Stylistin",
bio: "Expertin für Farbverläufe, Coloration und kreative Nuancen. Liebt es, mit natürlichen Tönen zu arbeiten.",
initials: "MK",
},
{
name: "Sophie Weber",
role: "Auszubildende",
bio: "Im 2. Ausbildungsjahr zur Friseurin. Bringt frische Ideen und moderne Styling-Trends mit ins Team.",
initials: "SW",
},
],
} satisfies SiteContent

View File

@@ -1,13 +1,23 @@
--- ---
import "@/styles/global.css" import "@/styles/global.css"
const {
title = "Haarscharf Crimmitschau | Friseur in der Annenstraße",
description = "Haarscharf ist ein lokaler Friseursalon in Crimmitschau für Schnitt, Farbe, Styling und Termine nach telefonischer Absprache.",
} = Astro.props
--- ---
<html lang="en"> <html lang="de">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Astro App</title> <meta name="description" content={description} />
<meta name="theme-color" content="#f6f1e8" />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:type" content="website" />
<title>{title}</title>
</head> </head>
<body> <body>
<slot /> <slot />

View File

@@ -1,17 +1,850 @@
--- ---
import Layout from "@/layouts/main.astro" import Layout from "@/layouts/main.astro"
import { Button } from "@/components/ui/button" import { siteContent } from "@/content/site-content"
const navItems = [
{ label: "Leistungen", href: "#leistungen" },
{ label: "Team", href: "#team" },
{ label: "Zeiten", href: "#zeiten" },
{ label: "Kontakt", href: "#kontakt" },
]
--- ---
<Layout> <Layout title="Haarscharf Crimmitschau | Friseur in der Annenstraße">
<div class="flex min-h-svh p-6"> <a class="skip-link" href="#top">Zum Inhalt springen</a>
<div class="flex max-w-md min-w-0 flex-col gap-4 text-sm leading-loose">
<div> <header class="site-header">
<h1 class="font-medium">Project ready!</h1> <a class="brand-lockup" href="#top" aria-label="Haarscharf Startseite">
<p>You may now add components and start building.</p> <span class="brand-mark">H</span>
<p>We've already added the button component for you.</p> <span>
<Button client:load className="mt-2">Button</Button> <span class="block font-heading text-lg leading-none">{siteContent.business.name}</span>
</div> <span class="brand-descriptor">{siteContent.business.descriptor}</span>
</span>
</a>
<nav aria-label="Hauptnavigation" class="hidden items-center gap-1 md:flex">
{navItems.map((item) => <a class="nav-link" href={item.href}>{item.label}</a>)}
</nav>
<div class="flex items-center gap-2">
<button
class="mobile-nav-toggle md:hidden"
aria-expanded="false"
aria-controls="mobile-nav"
aria-label="Menü öffnen"
type="button"
>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true">
<line x1="3" y1="5" x2="17" y2="5" />
<line x1="3" y1="10" x2="17" y2="10" />
<line x1="3" y1="15" x2="17" y2="15" />
</svg>
</button>
<a class="button-link button-link--compact" href={siteContent.cta.primary.href}>
Anrufen
</a>
</div>
</header>
<div id="mobile-nav" class="mobile-nav" aria-label="Mobile Navigation" role="dialog" aria-modal="true">
<div class="mobile-nav-backdrop"></div>
<div class="mobile-nav-panel">
<button class="mobile-nav-close" aria-label="Menü schließen" type="button">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true">
<line x1="4" y1="4" x2="16" y2="16" />
<line x1="16" y1="4" x2="4" y2="16" />
</svg>
</button>
<ul class="mobile-nav-list">
{navItems.map((item) => (
<li><a class="mobile-nav-link" href={item.href}>{item.label}</a></li>
))}
</ul>
<a class="mobile-nav-phone" href={siteContent.business.phone.href}>
<span class="contact-label">Telefon</span>
<strong>{siteContent.business.phone.display}</strong>
</a>
</div> </div>
</div> </div>
<main>
<!-- Hero: text-only, centered, warm typography -->
<section id="top" class="hero-section hero-section--text-only" aria-labelledby="hero-title">
<div class="hero-copy hero-copy--centered">
<p class="eyebrow">{siteContent.hero.eyebrow}</p>
<h1 id="hero-title">{siteContent.hero.title}</h1>
<p class="hero-intro">{siteContent.hero.intro}</p>
<div class="hero-actions hero-actions--centered">
<a class="button-link" href={siteContent.cta.primary.href}>
{siteContent.cta.primary.label}
</a>
<a class="button-link button-link--secondary" href={siteContent.cta.secondary.href} target="_blank" rel="noreferrer">
{siteContent.cta.secondary.label}
</a>
</div>
<dl class="salon-meta salon-meta--centered" aria-label="Saloninformationen">
<div>
<dt>Adresse</dt>
<dd>{siteContent.business.address.display}</dd>
</div>
<div>
<dt>Telefon</dt>
<dd>{siteContent.business.phone.display}</dd>
</div>
<div>
<dt>{siteContent.hours[0].day}</dt>
<dd>{siteContent.hours[0].time}</dd>
</div>
</dl>
</div>
</section>
<!-- Salon Promise -->
<section class="section-shell promise-section cut-line" aria-labelledby="promise-title">
<div class="promise-intro">
<p class="eyebrow">Salonversprechen</p>
<h2 id="promise-title">Haare dürfen leicht aussehen, auch wenn dahinter Präzision steckt.</h2>
</div>
<div class="promise-grid">
{
siteContent.promise.map((item, index) => (
<article class="promise-card">
<span class="index-label">{String(index + 1).padStart(2, "0")}</span>
<h3>{item.title}</h3>
<p>{item.text}</p>
</article>
))
}
</div>
</section>
<!-- Editorial image break: salon atmosphere -->
<figure class="editorial-image">
<img
src="https://images.unsplash.com/photo-1562322140-8baeececf3df?auto=format&fit=crop&w=1600&q=80"
alt="Warm beleuchteter Salon-Innenraum mit Friseurstühlen und Spiegeln"
width="1600"
height="900"
loading="lazy"
decoding="async"
/>
<figcaption>Atmosphäre im Salon</figcaption>
</figure>
<!-- Services: Grid instead of list -->
<section id="leistungen" class="section-shell services-section" aria-labelledby="services-title">
<div class="section-heading section-heading--centered">
<p class="eyebrow">Leistungen</p>
<h2 id="services-title">Alles, was ein guter Salonbesuch braucht.</h2>
<p>Die Auswahl bleibt bewusst klar. Details, Wünsche und Termine werden am besten direkt telefonisch besprochen.</p>
</div>
<div class="service-grid">
{
siteContent.services.map((service, index) => (
<article class="service-card">
<span class="service-index">{String(index + 1).padStart(2, "0")}</span>
<h3>{service.title}</h3>
<p>{service.text}</p>
</article>
))
}
</div>
</section>
<!-- Team: adapted from /2.astro -->
<section id="team" class="section-shell team-section cut-line" aria-labelledby="team-title">
<div class="section-heading section-heading--centered">
<p class="eyebrow">Unser Team</p>
<h2 id="team-title">Die Menschen hinter den Scheren.</h2>
</div>
<figure class="team-image">
<img
src="https://images.unsplash.com/photo-1711274093746-b588a17d2716?auto=format&fit=crop&w=1200&q=82"
alt="Eine Friseurin bei der Arbeit mit Schere"
width="1200"
height="600"
loading="lazy"
decoding="async"
/>
<figcaption>Handwerk mit Präzision</figcaption>
</figure>
<div class="team-grid">
{
siteContent.team.map((member) => (
<article class="team-card">
<div class="team-avatar">
<span>{member.initials}</span>
</div>
<h3>{member.name}</h3>
<p class="team-role">{member.role}</p>
<p>{member.bio}</p>
</article>
))
}
</div>
</section>
<!-- Hours -->
<section id="zeiten" class="section-shell hours-section cut-line" aria-labelledby="hours-title">
<div class="section-heading">
<p class="eyebrow">Öffnungszeiten</p>
<h2 id="hours-title">Planbar von Montag bis Samstag.</h2>
<p>Für Termine bitte kurz anrufen. So lässt sich direkt klären, wann genug Zeit für Beratung, Schnitt oder Farbe frei ist.</p>
</div>
<div class="hours-panel">
{
siteContent.hours.map((entry) => (
<div class="hours-row">
<span>{entry.day}</span>
<time>{entry.time}</time>
</div>
))
}
</div>
</section>
<!-- Trust -->
<section class="trust-band" aria-labelledby="trust-title">
<div>
<p class="eyebrow">Lokales Vertrauen</p>
<h2 id="trust-title">{siteContent.reviewSummary.rating}</h2>
</div>
<p class="trust-copy">
<strong>{siteContent.reviewSummary.count}</strong>
<span>{siteContent.reviewSummary.text}</span>
</p>
</section>
<!-- Contact: with labels adapted from /2.astro -->
<section id="kontakt" class="section-shell contact-section" aria-labelledby="contact-title">
<div class="section-heading">
<p class="eyebrow">Kontakt & Anfahrt</p>
<h2 id="contact-title">Mitten in Crimmitschau.</h2>
<p class="contact-note">Der schnellste Weg zum Termin bleibt ein kurzer Anruf im Salon.</p>
</div>
<div class="contact-layout">
<div class="contact-left">
<address class="contact-address">
<span>{siteContent.business.name}</span>
<span>{siteContent.business.address.street}</span>
<span>{siteContent.business.address.postalCode} {siteContent.business.address.city}</span>
</address>
<figure class="contact-image">
<img
src="https://images.unsplash.com/photo-1522337360788-8b13dee7a37e?auto=format&fit=crop&w=800&q=80"
alt="Friseur-Werkzeuge: Schere und Kamm auf einer Marmor-Arbeitsfläche"
width="800"
height="600"
loading="lazy"
decoding="async"
/>
<figcaption>Detail &amp; Sorgfalt</figcaption>
</figure>
</div>
<div class="contact-actions contact-card">
<a class="contact-line" href={siteContent.business.phone.href}>
<span class="contact-label">Telefon</span>
<strong>{siteContent.business.phone.display}</strong>
</a>
<a class="contact-line" href={`mailto:${siteContent.business.email}`}>
<span class="contact-label">E-Mail</span>
<strong>{siteContent.business.email}</strong>
</a>
<a class="button-link" href={siteContent.cta.secondary.href} target="_blank" rel="noreferrer">
Route über Google Maps
</a>
</div>
</div>
</section>
<!-- Final CTA -->
<section class="final-cta" aria-labelledby="final-cta-title">
<p class="eyebrow">Bereit für den nächsten Schnitt?</p>
<h2 id="final-cta-title">Kurz anrufen, Termin abstimmen, vorbeikommen.</h2>
<div class="final-cta-actions">
<a class="button-link button-link--light" href={siteContent.cta.primary.href}>
{siteContent.business.phone.display}
</a>
</div>
</section>
</main>
<script is:inline>
(function() {
const toggle = document.querySelector('.mobile-nav-toggle');
const nav = document.querySelector('#mobile-nav');
if (!toggle || !nav) return;
const closeBtn = nav.querySelector('.mobile-nav-close');
const backdrop = nav.querySelector('.mobile-nav-backdrop');
const links = nav.querySelectorAll('a');
function open() {
nav.classList.add('is-open');
toggle.setAttribute('aria-expanded', 'true');
document.body.style.overflow = 'hidden';
if (links.length) {
setTimeout(() => links[0].focus(), 0);
}
document.addEventListener('keydown', onKeyDown);
}
function close() {
nav.classList.remove('is-open');
toggle.setAttribute('aria-expanded', 'false');
document.body.style.overflow = '';
document.removeEventListener('keydown', onKeyDown);
toggle.focus();
}
function onKeyDown(e) {
if (e.key === 'Escape') close();
}
toggle.addEventListener('click', open);
if (closeBtn) closeBtn.addEventListener('click', close);
if (backdrop) backdrop.addEventListener('click', close);
links.forEach(link => link.addEventListener('click', close));
})();
</script>
</Layout> </Layout>
<style>
/* ─── Hero: text-only, centered ─── */
.hero-section--text-only {
position: relative;
display: grid;
place-items: center;
min-height: 92svh;
overflow: hidden;
padding: clamp(7rem, 14vw, 10rem) clamp(1rem, 5vw, 5rem) clamp(3.75rem, 7vw, 6rem);
background:
linear-gradient(180deg, color-mix(in oklch, var(--surface-warm) 55%, transparent) 0%, var(--background) 40%);
color: var(--foreground);
text-align: center;
}
.hero-section--text-only::after {
content: "";
position: absolute;
inset: 0;
background:
radial-gradient(ellipse 80% 50% at 50% 120%, color-mix(in oklch, var(--secondary) 25%, transparent) 0%, transparent 70%);
pointer-events: none;
}
.hero-copy--centered {
position: relative;
z-index: 2;
align-self: end;
max-width: 58rem;
margin: 0 auto;
}
.hero-copy--centered .eyebrow {
color: var(--accent);
}
.hero-copy--centered h1 {
max-width: 18ch;
margin: 1rem auto 1.4rem;
font-family: var(--font-heading);
font-size: clamp(3.4rem, 9vw, 7.5rem);
font-weight: 600;
line-height: 1.0;
color: var(--foreground);
}
.hero-copy--centered .hero-intro {
max-width: 42ch;
margin: 0 auto;
color: var(--muted-foreground);
font-size: clamp(1.15rem, 2vw, 1.45rem);
line-height: 1.6;
}
.hero-actions--centered {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.75rem;
padding-top: 1.35rem;
}
.hero-actions--centered .button-link--secondary {
border-color: var(--foreground);
color: var(--foreground);
}
.hero-actions--centered .button-link--secondary:hover,
.hero-actions--centered .button-link--secondary:focus-visible {
background: var(--foreground);
border-color: var(--foreground);
color: var(--background);
}
.salon-meta--centered {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0;
max-width: 50rem;
margin: clamp(2.5rem, 5vw, 4rem) auto 0;
border-top: 1px solid var(--hairline);
border-bottom: 1px solid var(--hairline);
color: var(--foreground);
}
.salon-meta--centered div {
display: grid;
gap: 0.25rem;
padding: 1rem clamp(0.8rem, 2vw, 1.2rem);
}
.salon-meta--centered div + div {
border-left: 1px solid var(--hairline);
}
.salon-meta--centered dt {
color: var(--muted-foreground);
font-size: 0.72rem;
font-weight: 800;
letter-spacing: 0;
text-transform: uppercase;
}
.salon-meta--centered dd {
margin: 0;
font-weight: 700;
line-height: 1.25;
}
/* ─── Services: grid layout ─── */
.service-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 0;
margin-top: clamp(2rem, 4vw, 4rem);
border-top: 1px solid oklch(0.62 0.042 49 / 45%);
border-left: 1px solid oklch(0.62 0.042 49 / 45%);
}
.service-card {
display: grid;
gap: 0.75rem;
border-bottom: 1px solid oklch(0.62 0.042 49 / 45%);
border-right: 1px solid oklch(0.62 0.042 49 / 45%);
padding: clamp(1.5rem, 3vw, 2.5rem);
transition: background-color 180ms ease;
}
.service-card:hover {
background: color-mix(in oklch, oklch(0.62 0.042 49 / 45%) 12%, transparent);
}
.service-card .service-index {
color: oklch(0.82 0.104 65);
font-family: var(--font-heading);
font-size: clamp(2rem, 4vw, 4rem);
line-height: 0.85;
}
.service-card h3 {
font-family: var(--font-heading);
font-size: clamp(1.3rem, 2vw, 1.65rem);
line-height: 1.15;
margin: 0;
}
.service-card p {
color: oklch(0.84 0.019 83);
line-height: 1.65;
margin: 0;
}
/* ─── Team section ─── */
.team-section {
background: var(--surface-warm);
}
.team-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 0;
margin-top: clamp(2rem, 4vw, 4rem);
border-top: 1px solid var(--hairline);
border-left: 1px solid var(--hairline);
}
.team-card {
display: grid;
justify-items: center;
gap: 0.625rem;
border-bottom: 1px solid var(--hairline);
border-right: 1px solid var(--hairline);
padding: clamp(2rem, 4vw, 3rem) clamp(1.5rem, 3vw, 2.5rem);
text-align: center;
transition: background-color 180ms ease;
}
.team-card:hover {
background: color-mix(in oklch, var(--background) 55%, transparent);
}
.team-avatar {
display: grid;
place-items: center;
width: 5rem;
height: 5rem;
margin-bottom: 0.75rem;
border-radius: 999px;
background: var(--muted);
font-family: var(--font-heading);
font-size: 1.25rem;
font-weight: 600;
color: var(--muted-foreground);
}
.team-card h3 {
font-family: var(--font-heading);
font-size: clamp(1.2rem, 1.8vw, 1.5rem);
line-height: 1.2;
margin: 0;
}
.team-role {
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.02em;
text-transform: uppercase;
color: var(--accent);
margin: 0;
}
.team-card > p:last-child {
color: var(--muted-foreground);
font-size: 0.95rem;
line-height: 1.65;
margin: 0;
}
/* ─── Contact labels ─── */
.contact-label {
display: block;
color: var(--muted-foreground);
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
}
/* ─── Editorial image break ─── */
.editorial-image {
margin: 0;
position: relative;
width: 100%;
height: clamp(18rem, 45vw, 32rem);
overflow: hidden;
border-radius: var(--radius);
}
.editorial-image img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
display: block;
}
.editorial-image figcaption {
position: absolute;
right: clamp(1rem, 4vw, 3rem);
bottom: 1rem;
z-index: 2;
padding: 0.25rem 0.6rem;
border-radius: var(--radius-sm);
background: oklch(0.1 0.02 28 / 55%);
color: oklch(0.95 0.01 84);
font-size: 0.78rem;
text-shadow: none;
}
/* ─── Team image ─── */
.team-image {
margin: clamp(1.5rem, 3vw, 2.5rem) auto 0;
max-width: var(--measure);
position: relative;
border-radius: var(--radius);
overflow: hidden;
}
.team-image img {
width: 100%;
height: auto;
aspect-ratio: 2 / 1;
object-fit: cover;
display: block;
}
.team-image figcaption {
position: absolute;
right: 1rem;
bottom: 0.75rem;
color: oklch(0.95 0.01 84);
font-size: 0.78rem;
text-shadow: 0 1px 3px oklch(0.1 0.02 28 / 50%);
}
/* ─── Contact image ─── */
.contact-left {
display: grid;
gap: clamp(1.5rem, 3vw, 2.5rem);
align-content: start;
}
.contact-image {
margin: 0;
border-radius: var(--radius);
overflow: hidden;
}
.contact-image img {
width: 100%;
height: auto;
aspect-ratio: 4 / 3;
object-fit: cover;
display: block;
}
.contact-image figcaption {
color: var(--muted-foreground);
font-size: 0.82rem;
margin-top: 0.375rem;
text-align: center;
}
/* ─── Centered section headings ─── */
.section-heading--centered {
text-align: center;
margin: 0 auto;
}
.section-heading--centered h2 {
margin: 0 auto;
}
.section-heading--centered p:not(.eyebrow) {
margin: 0 auto;
}
/* ─── Mobile overrides ─── */
@media (max-width: 820px) {
.hero-section--text-only {
min-height: 94svh;
}
.hero-copy--centered h1 {
font-size: clamp(2.6rem, 10vw, 4rem);
}
.salon-meta--centered {
grid-template-columns: 1fr;
}
.salon-meta--centered div + div {
border-top: 1px solid var(--hairline);
border-left: 0;
}
.service-grid {
grid-template-columns: 1fr;
}
.team-grid {
grid-template-columns: 1fr;
}
}
/* ─── Header override for light hero ─── */
.site-header {
color: var(--foreground);
}
.site-header .nav-link {
color: inherit;
}
.site-header .nav-link:hover,
.site-header .nav-link:focus-visible {
background: color-mix(in oklch, var(--foreground) 10%, transparent);
color: var(--foreground);
}
.site-header .button-link--compact {
background: color-mix(in oklch, var(--foreground) 10%, transparent);
border-color: color-mix(in oklch, var(--foreground) 35%, transparent);
color: var(--foreground);
}
.site-header .button-link--compact:hover,
.site-header .button-link--compact:focus-visible {
background: var(--foreground);
border-color: var(--foreground);
color: var(--background);
}
/* ─── Mobile navigation ─── */
.mobile-nav-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2.5rem;
height: 2.5rem;
border: 1px solid color-mix(in oklch, var(--foreground) 25%, transparent);
border-radius: var(--radius);
background: color-mix(in oklch, var(--foreground) 8%, transparent);
color: var(--foreground);
cursor: pointer;
transition: background-color 180ms ease, border-color 180ms ease;
}
.mobile-nav-toggle:hover,
.mobile-nav-toggle:focus-visible {
background: color-mix(in oklch, var(--foreground) 16%, transparent);
border-color: color-mix(in oklch, var(--foreground) 45%, transparent);
}
@media (min-width: 821px) {
.mobile-nav-toggle {
display: none;
}
}
.mobile-nav {
position: fixed;
inset: 0;
z-index: 60;
pointer-events: none;
visibility: hidden;
}
.mobile-nav.is-open {
pointer-events: auto;
visibility: visible;
}
.mobile-nav-backdrop {
position: absolute;
inset: 0;
background: oklch(0.1 0.02 28 / 55%);
opacity: 0;
transition: opacity 200ms ease;
}
.mobile-nav.is-open .mobile-nav-backdrop {
opacity: 1;
}
.mobile-nav-panel {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: min(20rem, 85vw);
background: var(--background);
color: var(--foreground);
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 1.5rem;
transform: translateX(100%);
transition: transform 220ms ease;
box-shadow: -4px 0 24px oklch(0.1 0.02 28 / 12%);
}
.mobile-nav.is-open .mobile-nav-panel {
transform: translateX(0);
}
.mobile-nav-close {
align-self: flex-end;
display: inline-flex;
align-items: center;
justify-content: center;
width: 2.5rem;
height: 2.5rem;
border: 1px solid var(--hairline);
border-radius: var(--radius);
background: transparent;
color: var(--foreground);
cursor: pointer;
transition: background-color 180ms ease;
}
.mobile-nav-close:hover,
.mobile-nav-close:focus-visible {
background: var(--muted);
}
.mobile-nav-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.mobile-nav-link {
display: block;
padding: 0.85rem 0.5rem;
border-radius: var(--radius);
color: var(--foreground);
font-size: 1.25rem;
font-weight: 600;
text-decoration: none;
transition: background-color 180ms ease;
min-height: 44px;
line-height: 1.2;
}
.mobile-nav-link:hover,
.mobile-nav-link:focus-visible {
background: var(--muted);
}
.mobile-nav-phone {
margin-top: auto;
display: grid;
gap: 0.3rem;
padding: 1rem;
border-radius: var(--radius);
border: 1px solid var(--hairline);
background: var(--card);
color: var(--foreground);
text-decoration: none;
transition: background-color 180ms ease, border-color 180ms ease;
}
.mobile-nav-phone:hover,
.mobile-nav-phone:focus-visible {
background: var(--muted);
border-color: var(--primary);
}
.mobile-nav-phone strong {
font-size: 1.35rem;
font-weight: 700;
}
</style>

View File

@@ -7,30 +7,35 @@
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
:root { :root {
--background: oklch(1 0 0); --background: oklch(0.965 0.018 82);
--foreground: oklch(0.147 0.004 49.25); --foreground: oklch(0.17 0.028 31);
--card: oklch(1 0 0); --card: oklch(0.99 0.011 84);
--card-foreground: oklch(0.147 0.004 49.25); --card-foreground: oklch(0.18 0.026 31);
--popover: oklch(1 0 0); --popover: oklch(0.986 0.012 84);
--popover-foreground: oklch(0.147 0.004 49.25); --popover-foreground: oklch(0.18 0.026 31);
--primary: oklch(0.514 0.222 16.935); --primary: oklch(0.34 0.105 18);
--primary-foreground: oklch(0.969 0.015 12.422); --primary-foreground: oklch(0.986 0.012 84);
--secondary: oklch(0.967 0.001 286.375); --secondary: oklch(0.87 0.045 149);
--secondary-foreground: oklch(0.21 0.006 285.885); --secondary-foreground: oklch(0.2 0.036 34);
--muted: oklch(0.97 0.001 106.424); --muted: oklch(0.92 0.022 78);
--muted-foreground: oklch(0.553 0.013 58.071); --muted-foreground: oklch(0.43 0.031 42);
--accent: oklch(0.97 0.001 106.424); --accent: oklch(0.74 0.095 64);
--accent-foreground: oklch(0.216 0.006 56.043); --accent-foreground: oklch(0.2 0.036 34);
--destructive: oklch(0.577 0.245 27.325); --destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.923 0.003 48.717); --border: oklch(0.78 0.026 70);
--input: oklch(0.923 0.003 48.717); --input: oklch(0.82 0.027 72);
--ring: oklch(0.709 0.01 56.259); --ring: oklch(0.58 0.112 19);
--chart-1: oklch(0.828 0.111 230.318); --chart-1: oklch(0.828 0.111 230.318);
--chart-2: oklch(0.685 0.169 237.323); --chart-2: oklch(0.685 0.169 237.323);
--chart-3: oklch(0.588 0.158 241.966); --chart-3: oklch(0.588 0.158 241.966);
--chart-4: oklch(0.5 0.134 242.749); --chart-4: oklch(0.5 0.134 242.749);
--chart-5: oklch(0.443 0.11 240.79); --chart-5: oklch(0.443 0.11 240.79);
--radius: 0.625rem; --radius: 0.5rem;
--surface-warm: oklch(0.934 0.025 78);
--surface-deep: oklch(0.195 0.037 31);
--hairline: color-mix(in oklch, var(--foreground) 18%, transparent);
--hero-ink: oklch(0.985 0.011 84);
--measure: 68rem;
--sidebar: oklch(0.985 0.001 106.423); --sidebar: oklch(0.985 0.001 106.423);
--sidebar-foreground: oklch(0.147 0.004 49.25); --sidebar-foreground: oklch(0.147 0.004 49.25);
--sidebar-primary: oklch(0.586 0.253 17.585); --sidebar-primary: oklch(0.586 0.253 17.585);
@@ -123,12 +128,635 @@
@apply border-border outline-ring/50; @apply border-border outline-ring/50;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground antialiased;
background-image: linear-gradient(180deg, color-mix(in oklch, var(--surface-warm) 68%, transparent), transparent 28rem);
background-repeat: no-repeat;
background-size: 100% 28rem;
} }
button:not(:disabled), [role="button"]:not(:disabled) { button:not(:disabled), [role="button"]:not(:disabled) {
cursor: pointer; cursor: pointer;
} }
html { html {
@apply font-sans; @apply font-sans;
scroll-behavior: smooth;
} }
h1,
h2,
h3,
p {
text-wrap: pretty;
}
}
@layer components {
.skip-link {
position: fixed;
left: 1rem;
top: 1rem;
z-index: 80;
transform: translateY(-150%);
border-radius: var(--radius);
background: var(--primary);
color: var(--primary-foreground);
padding: 0.65rem 0.9rem;
transition: transform 180ms ease;
}
.skip-link:focus {
transform: translateY(0);
}
.site-header {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 50;
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 1rem;
padding: clamp(0.8rem, 2vw, 1.25rem) clamp(1rem, 4vw, 3rem);
color: var(--hero-ink);
}
.brand-lockup {
display: inline-flex;
align-items: center;
gap: 0.75rem;
width: fit-content;
color: inherit;
text-decoration: none;
}
.brand-mark {
display: grid;
place-items: center;
width: 2.25rem;
height: 2.25rem;
border: 1px solid color-mix(in oklch, currentColor 58%, transparent);
border-radius: 999px;
font-family: var(--font-heading);
font-size: 1.05rem;
line-height: 1;
}
.brand-descriptor {
display: block;
color: color-mix(in oklch, var(--hero-ink) 74%, transparent);
font-size: 0.78rem;
line-height: 1.1;
}
.site-header nav {
justify-self: end;
}
.nav-link {
border-radius: 999px;
color: inherit;
font-size: 0.95rem;
padding: 0.55rem 0.8rem;
text-decoration: none;
transition: background-color 180ms ease, color 180ms ease;
}
.nav-link:hover,
.nav-link:focus-visible {
background: color-mix(in oklch, currentColor 13%, transparent);
color: oklch(0.99 0.008 84);
}
.button-link {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 2.8rem;
width: fit-content;
border: 1px solid var(--primary);
border-radius: var(--radius);
background: var(--primary);
color: var(--primary-foreground);
font-weight: 700;
line-height: 1;
padding: 0.82rem 1.15rem;
text-decoration: none;
transition: transform 180ms ease, background-color 180ms ease, border-color 180ms ease, box-shadow 180ms ease;
}
.button-link:hover,
.button-link:focus-visible {
background: oklch(0.28 0.094 18);
border-color: oklch(0.28 0.094 18);
box-shadow: 0 0.75rem 2rem oklch(0.14 0.035 24 / 18%);
transform: translateY(-1px);
}
.button-link--compact {
min-height: 2.45rem;
padding: 0.55rem 0.95rem;
background: color-mix(in oklch, var(--hero-ink) 14%, transparent);
border-color: color-mix(in oklch, var(--hero-ink) 45%, transparent);
color: var(--hero-ink);
}
.button-link--secondary {
background: transparent;
color: var(--foreground);
}
.button-link--secondary:hover,
.button-link--secondary:focus-visible {
background: var(--foreground);
border-color: var(--foreground);
color: var(--background);
}
.button-link--light {
background: oklch(0.98 0.012 84);
border-color: oklch(0.98 0.012 84);
color: oklch(0.22 0.039 22);
}
.eyebrow {
color: var(--primary);
font-size: 0.83rem;
font-weight: 800;
letter-spacing: 0;
margin: 0;
text-transform: uppercase;
}
.cut-line {
position: relative;
}
.cut-line::before {
content: "";
position: absolute;
top: 0;
left: clamp(1rem, 5vw, 5rem);
right: clamp(1rem, 5vw, 5rem);
height: 1px;
background: linear-gradient(90deg, transparent, var(--hairline) 12%, var(--hairline) 88%, transparent);
}
.hero-section {
position: relative;
display: grid;
min-height: 92svh;
overflow: hidden;
padding: clamp(7rem, 14vw, 10rem) clamp(1rem, 5vw, 5rem) clamp(3.75rem, 7vw, 6rem);
}
.hero-section::after {
content: "";
position: absolute;
inset: 0;
background:
linear-gradient(90deg, oklch(0.115 0.03 28 / 94%) 0%, oklch(0.16 0.033 30 / 78%) 42%, oklch(0.18 0.035 30 / 30%) 100%),
linear-gradient(0deg, oklch(0.1 0.025 28 / 66%) 0%, transparent 46%);
z-index: 1;
}
.hero-copy {
position: relative;
z-index: 2;
align-self: end;
max-width: 58rem;
color: var(--hero-ink);
}
.hero-copy .eyebrow {
color: oklch(0.84 0.093 68);
}
.hero-copy .button-link--secondary {
border-color: color-mix(in oklch, oklch(0.98 0.012 84) 58%, transparent);
color: oklch(0.98 0.012 84);
}
.hero-copy .button-link--secondary:hover,
.hero-copy .button-link--secondary:focus-visible {
background: oklch(0.98 0.012 84);
border-color: oklch(0.98 0.012 84);
color: oklch(0.22 0.039 22);
}
.hero-copy h1 {
max-width: 12ch;
font-family: var(--font-heading);
font-size: clamp(4.2rem, 10.5vw, 9.25rem);
font-weight: 600;
line-height: 0.88;
margin: 1rem 0 1.4rem;
}
.hero-intro {
max-width: 39rem;
color: oklch(0.93 0.015 84);
font-size: clamp(1.15rem, 2vw, 1.45rem);
line-height: 1.55;
margin: 0;
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
padding-top: 1.35rem;
}
.salon-meta {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0;
max-width: 50rem;
margin: clamp(2rem, 4vw, 3.2rem) 0 0;
border-top: 1px solid color-mix(in oklch, var(--hero-ink) 34%, transparent);
border-bottom: 1px solid color-mix(in oklch, var(--hero-ink) 22%, transparent);
}
.salon-meta div {
display: grid;
gap: 0.32rem;
padding: 1rem clamp(0.8rem, 2vw, 1.2rem);
}
.salon-meta div + div {
border-left: 1px solid color-mix(in oklch, var(--hero-ink) 18%, transparent);
}
.salon-meta dt {
color: color-mix(in oklch, var(--hero-ink) 58%, transparent);
font-size: 0.72rem;
font-weight: 800;
letter-spacing: 0;
text-transform: uppercase;
}
.salon-meta dd {
margin: 0;
font-weight: 700;
line-height: 1.25;
}
.hero-image {
position: absolute;
inset: 0;
margin: 0;
}
.hero-image img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
.hero-image figcaption {
position: absolute;
right: clamp(1rem, 4vw, 3rem);
bottom: 1rem;
z-index: 2;
color: oklch(0.9 0.012 84);
font-size: 0.78rem;
}
.hero-image a {
color: inherit;
}
.section-shell {
padding: clamp(4.5rem, 8vw, 8rem) clamp(1rem, 5vw, 5rem);
}
.section-heading {
display: grid;
gap: 1rem;
max-width: 42rem;
}
.section-heading h2,
.promise-section h2,
.final-cta h2 {
font-family: var(--font-heading);
font-size: clamp(2.45rem, 5.4vw, 5.35rem);
font-weight: 600;
line-height: 1.02;
margin: 0;
}
.section-heading p:not(.eyebrow) {
color: var(--muted-foreground);
font-size: clamp(1.05rem, 1.5vw, 1.22rem);
line-height: 1.65;
margin: 0;
}
.promise-section {
display: grid;
gap: clamp(2rem, 5vw, 5rem);
grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
background:
linear-gradient(90deg, transparent 0 calc(50% - 0.5px), var(--hairline) calc(50% - 0.5px) calc(50% + 0.5px), transparent calc(50% + 0.5px)),
var(--background);
}
.promise-intro {
position: sticky;
top: 6rem;
align-self: start;
}
.promise-grid {
display: grid;
gap: 0;
border-top: 1px solid var(--hairline);
}
.promise-card {
display: grid;
grid-template-columns: minmax(3.2rem, 0.22fr) minmax(0, 0.75fr);
column-gap: clamp(1rem, 3vw, 2.5rem);
border-bottom: 1px solid var(--hairline);
padding: clamp(1.25rem, 2.3vw, 2.1rem) 0;
}
.index-label {
color: var(--primary);
display: block;
font-family: var(--font-heading);
font-size: clamp(2rem, 4vw, 4rem);
line-height: 0.85;
opacity: 0.92;
}
.promise-grid h3,
.service-row h3 {
font-family: var(--font-heading);
font-size: clamp(1.55rem, 2vw, 2rem);
line-height: 1.08;
margin: 0 0 0.75rem;
}
.promise-card h3,
.promise-card p {
grid-column: 2;
}
.promise-grid p,
.service-row p {
color: var(--muted-foreground);
line-height: 1.65;
margin: 0;
}
.services-section {
background: var(--surface-deep);
color: oklch(0.97 0.012 84);
}
.services-section .eyebrow {
color: oklch(0.82 0.104 65);
}
.services-section .section-heading p {
color: oklch(0.84 0.019 83);
}
.service-list {
display: grid;
gap: 0;
margin-top: clamp(2rem, 4vw, 4rem);
border-top: 1px solid oklch(0.62 0.042 49 / 45%);
}
.service-row {
display: grid;
grid-template-columns: minmax(3.4rem, 0.18fr) minmax(14rem, 0.62fr) minmax(0, 1fr);
gap: clamp(1rem, 3vw, 2.5rem);
align-items: baseline;
border-bottom: 1px solid oklch(0.62 0.042 49 / 45%);
padding: clamp(1.2rem, 2.4vw, 2rem) 0;
}
.service-index {
color: oklch(0.82 0.104 65);
font-family: var(--font-heading);
font-size: clamp(2rem, 4vw, 4.4rem);
line-height: 0.85;
}
.service-row p {
color: oklch(0.84 0.019 83);
}
.hours-section {
display: grid;
gap: clamp(2rem, 5vw, 5rem);
grid-template-columns: minmax(0, 0.95fr) minmax(280px, 0.8fr);
background: var(--surface-warm);
}
.hours-panel {
border-top: 1px solid var(--foreground);
background: color-mix(in oklch, var(--background) 45%, transparent);
padding: 0 clamp(0.2rem, 1vw, 0.8rem);
}
.hours-row {
display: flex;
justify-content: space-between;
gap: 1.5rem;
border-bottom: 1px solid color-mix(in oklch, var(--foreground) 16%, transparent);
padding: 1.05rem 0;
}
.hours-row span {
font-weight: 800;
}
.hours-row time {
color: var(--muted-foreground);
font-variant-numeric: tabular-nums;
}
.trust-band {
display: grid;
align-items: center;
gap: 2rem;
grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
background: color-mix(in oklch, var(--secondary) 82%, var(--background));
padding: clamp(3rem, 6vw, 5rem) clamp(1rem, 5vw, 5rem);
}
.trust-band h2 {
font-family: var(--font-heading);
font-size: clamp(4rem, 9vw, 7rem);
line-height: 0.92;
margin: 0.8rem 0 0;
}
.trust-copy {
display: grid;
gap: 0.75rem;
font-size: clamp(1.1rem, 1.8vw, 1.45rem);
line-height: 1.55;
max-width: 42ch;
margin: 0;
}
.contact-layout {
display: grid;
gap: clamp(2rem, 5vw, 5rem);
grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
margin-top: clamp(2rem, 5vw, 4rem);
}
.contact-note {
max-width: 36rem;
}
.contact-address {
display: grid;
gap: 0.35rem;
font-family: var(--font-heading);
font-size: clamp(1.8rem, 3.5vw, 3.2rem);
font-style: normal;
line-height: 1.1;
}
.contact-actions {
display: grid;
gap: 0;
align-content: start;
}
.contact-card {
border-top: 1px solid var(--foreground);
border-bottom: 1px solid var(--hairline);
}
.contact-line {
display: grid;
gap: 0.5rem;
border: 0;
border-bottom: 1px solid var(--hairline);
color: inherit;
padding: 1.15rem 0;
text-decoration: none;
transition: border-color 180ms ease, background-color 180ms ease;
}
.contact-line:hover,
.contact-line:focus-visible {
background: color-mix(in oklch, var(--card) 48%, transparent);
border-color: var(--primary);
}
.contact-line span {
color: var(--muted-foreground);
font-size: 0.9rem;
}
.contact-line strong {
font-size: clamp(1.2rem, 2vw, 1.65rem);
}
.contact-actions > .button-link {
margin-top: 1.15rem;
}
.final-cta {
display: grid;
gap: 1.5rem;
justify-items: start;
background:
linear-gradient(90deg, color-mix(in oklch, var(--primary) 92%, black) 0%, var(--primary) 100%);
color: var(--primary-foreground);
padding: clamp(4rem, 8vw, 7rem) clamp(1rem, 5vw, 5rem);
}
.final-cta .eyebrow {
color: oklch(0.85 0.087 68);
}
.final-cta h2 {
max-width: 12ch;
}
.final-cta-actions {
border-top: 1px solid color-mix(in oklch, var(--primary-foreground) 34%, transparent);
padding-top: 1.25rem;
}
}
@media (max-width: 820px) {
.site-header {
grid-template-columns: 1fr auto;
color: var(--hero-ink);
}
.hero-section {
min-height: 94svh;
}
.hero-copy h1 {
font-size: clamp(3.4rem, 18vw, 5.6rem);
}
.salon-meta {
grid-template-columns: 1fr;
}
.salon-meta div + div {
border-top: 1px solid color-mix(in oklch, var(--hero-ink) 18%, transparent);
border-left: 0;
}
.promise-section,
.hours-section,
.trust-band,
.contact-layout {
grid-template-columns: 1fr;
}
.promise-section {
background: var(--background);
}
.promise-intro {
position: static;
}
.promise-card,
.service-row {
grid-template-columns: 1fr;
}
.promise-card h3,
.promise-card p {
grid-column: auto;
}
.service-row {
gap: 0.75rem;
}
.hours-row {
align-items: baseline;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
}
} }