Compare commits

...

5 Commits

18 changed files with 1236 additions and 338 deletions

View File

@@ -1,21 +1,20 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="de">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- TODO: Set the document title to the name of your application --> <title>WEBklar</title>
<title>Lovable App</title> <meta name="description" content="WEBklar Ihre Webagentur" />
<meta name="description" content="Lovable Generated Project" /> <meta name="author" content="WEBklar" />
<meta name="author" content="Lovable" />
<!-- TODO: Update og:title to match your application name --> <meta property="og:title" content="WEBklar" />
<meta property="og:title" content="Lovable App" /> <meta property="og:description" content="WEBklar Ihre Webagentur" />
<meta property="og:description" content="Lovable Generated Project" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:image" content="https://lovable.dev/opengraph-image-p98pqg.png" /> <meta property="og:image" content="https://lovable.dev/opengraph-image-p98pqg.png" />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@Lovable" /> <meta name="twitter:site" content="@WEBklar" />
<meta name="twitter:image" content="https://lovable.dev/opengraph-image-p98pqg.png" /> <meta name="twitter:image" content="https://lovable.dev/opengraph-image-p98pqg.png" />
</head> </head>

711
package-lock.json generated
View File

@@ -70,7 +70,7 @@
"@types/node": "^22.16.5", "@types/node": "^22.16.5",
"@types/react": "^18.3.23", "@types/react": "^18.3.23",
"@types/react-dom": "^18.3.7", "@types/react-dom": "^18.3.7",
"@vitejs/plugin-react-swc": "^3.11.0", "@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"eslint": "^9.32.0", "eslint": "^9.32.0",
"eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-hooks": "^5.2.0",
@@ -120,6 +120,173 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/compat-data": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
"integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-compilation-targets": "^7.28.6",
"@babel/helper-module-transforms": "^7.28.6",
"@babel/helpers": "^7.28.6",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/traverse": "^7.29.0",
"@babel/types": "^7.29.0",
"@jridgewell/remapping": "^2.3.5",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
"json5": "^2.2.3",
"semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/babel"
}
},
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/generator": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz",
"integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.0",
"@babel/types": "^7.29.0",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
"integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.28.6",
"@babel/helper-validator-option": "^7.27.1",
"browserslist": "^4.24.0",
"lru-cache": "^5.1.1",
"semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^3.0.2"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/helper-globals": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-imports": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.28.6",
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/traverse": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-plugin-utils": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
"integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": { "node_modules/@babel/helper-validator-identifier": {
"version": "7.28.5", "version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
@@ -130,6 +297,78 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/helper-validator-option": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
"integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
"integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.29.0"
},
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/plugin-transform-react-jsx-self": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
"integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/plugin-transform-react-jsx-source": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
"integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.28.2", "version": "7.28.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz",
@@ -139,6 +378,54 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/template": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.28.6",
"@babel/parser": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/types": "^7.29.0",
"debug": "^4.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/types": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@@ -849,17 +1136,24 @@
} }
}, },
"node_modules/@jridgewell/gen-mapping": { "node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5", "version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.24" "@jridgewell/trace-mapping": "^0.3.24"
}
}, },
"engines": { "node_modules/@jridgewell/remapping": {
"node": ">=6.0.0" "version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
} }
}, },
"node_modules/@jridgewell/resolve-uri": { "node_modules/@jridgewell/resolve-uri": {
@@ -871,15 +1165,6 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5", "version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
@@ -887,9 +1172,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@jridgewell/trace-mapping": { "node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25", "version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/resolve-uri": "^3.1.0",
@@ -2593,232 +2878,6 @@
"win32" "win32"
] ]
}, },
"node_modules/@swc/core": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.2.tgz",
"integrity": "sha512-YWqn+0IKXDhqVLKoac4v2tV6hJqB/wOh8/Br8zjqeqBkKa77Qb0Kw2i7LOFzjFNZbZaPH6AlMGlBwNrxaauaAg==",
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@swc/counter": "^0.1.3",
"@swc/types": "^0.1.23"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/swc"
},
"optionalDependencies": {
"@swc/core-darwin-arm64": "1.13.2",
"@swc/core-darwin-x64": "1.13.2",
"@swc/core-linux-arm-gnueabihf": "1.13.2",
"@swc/core-linux-arm64-gnu": "1.13.2",
"@swc/core-linux-arm64-musl": "1.13.2",
"@swc/core-linux-x64-gnu": "1.13.2",
"@swc/core-linux-x64-musl": "1.13.2",
"@swc/core-win32-arm64-msvc": "1.13.2",
"@swc/core-win32-ia32-msvc": "1.13.2",
"@swc/core-win32-x64-msvc": "1.13.2"
},
"peerDependencies": {
"@swc/helpers": ">=0.5.17"
},
"peerDependenciesMeta": {
"@swc/helpers": {
"optional": true
}
}
},
"node_modules/@swc/core-darwin-arm64": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.13.2.tgz",
"integrity": "sha512-44p7ivuLSGFJ15Vly4ivLJjg3ARo4879LtEBAabcHhSZygpmkP8eyjyWxrH3OxkY1eRZSIJe8yRZPFw4kPXFPw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-darwin-x64": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.13.2.tgz",
"integrity": "sha512-Lb9EZi7X2XDAVmuUlBm2UvVAgSCbD3qKqDCxSI4jEOddzVOpNCnyZ/xEampdngUIyDDhhJLYU9duC+Mcsv5Y+A==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm-gnueabihf": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.13.2.tgz",
"integrity": "sha512-9TDe/92ee1x57x+0OqL1huG4BeljVx0nWW4QOOxp8CCK67Rpc/HHl2wciJ0Kl9Dxf2NvpNtkPvqj9+BUmM9WVA==",
"cpu": [
"arm"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm64-gnu": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.13.2.tgz",
"integrity": "sha512-KJUSl56DBk7AWMAIEcU83zl5mg3vlQYhLELhjwRFkGFMvghQvdqQ3zFOYa4TexKA7noBZa3C8fb24rI5sw9Exg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm64-musl": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.13.2.tgz",
"integrity": "sha512-teU27iG1oyWpNh9CzcGQ48ClDRt/RCem7mYO7ehd2FY102UeTws2+OzLESS1TS1tEZipq/5xwx3FzbVgiolCiQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-x64-gnu": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.13.2.tgz",
"integrity": "sha512-dRPsyPyqpLD0HMRCRpYALIh4kdOir8pPg4AhNQZLehKowigRd30RcLXGNVZcc31Ua8CiPI4QSgjOIxK+EQe4LQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-x64-musl": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.13.2.tgz",
"integrity": "sha512-CCxETW+KkYEQDqz1SYC15YIWYheqFC+PJVOW76Maa/8yu8Biw+HTAcblKf2isrlUtK8RvrQN94v3UXkC2NzCEw==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-arm64-msvc": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.13.2.tgz",
"integrity": "sha512-Wv/QTA6PjyRLlmKcN6AmSI4jwSMRl0VTLGs57PHTqYRwwfwd7y4s2fIPJVBNbAlXd795dOEP6d/bGSQSyhOX3A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-ia32-msvc": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.13.2.tgz",
"integrity": "sha512-PuCdtNynEkUNbUXX/wsyUC+t4mamIU5y00lT5vJcAvco3/r16Iaxl5UCzhXYaWZSNVZMzPp9qN8NlSL8M5pPxw==",
"cpu": [
"ia32"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-x64-msvc": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.13.2.tgz",
"integrity": "sha512-qlmMkFZJus8cYuBURx1a3YAG2G7IW44i+FEYV5/32ylKkzGNAr9tDJSA53XNnNXkAB5EXSPsOz7bn5C3JlEtdQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/counter": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/@swc/types": {
"version": "0.1.23",
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.23.tgz",
"integrity": "sha512-u1iIVZV9Q0jxY+yM2vw/hZGDNudsN85bBpTqzAQ9rzkxW9D+e3aEM4Han+ow518gSewkXgjmEK0BD79ZcNVgPw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@swc/counter": "^0.1.3"
}
},
"node_modules/@tabler/icons": { "node_modules/@tabler/icons": {
"version": "3.36.1", "version": "3.36.1",
"resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.36.1.tgz", "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.36.1.tgz",
@@ -2991,7 +3050,53 @@
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT",
"peer": true
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
"integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7",
"@types/babel__generator": "*",
"@types/babel__template": "*",
"@types/babel__traverse": "*"
}
},
"node_modules/@types/babel__generator": {
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
"integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.0.0"
}
},
"node_modules/@types/babel__template": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
"integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"node_modules/@types/babel__traverse": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
"integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.28.2"
}
}, },
"node_modules/@types/chai": { "node_modules/@types/chai": {
"version": "5.2.3", "version": "5.2.3",
@@ -3094,7 +3199,6 @@
"integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==", "integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~6.21.0" "undici-types": "~6.21.0"
} }
@@ -3110,7 +3214,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz",
"integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/prop-types": "*", "@types/prop-types": "*",
"csstype": "^3.0.2" "csstype": "^3.0.2"
@@ -3122,7 +3225,6 @@
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"peerDependencies": { "peerDependencies": {
"@types/react": "^18.0.0" "@types/react": "^18.0.0"
} }
@@ -3188,7 +3290,6 @@
"integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/scope-manager": "8.38.0",
"@typescript-eslint/types": "8.38.0", "@typescript-eslint/types": "8.38.0",
@@ -3401,18 +3502,25 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
} }
}, },
"node_modules/@vitejs/plugin-react-swc": { "node_modules/@vitejs/plugin-react": {
"version": "3.11.0", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.11.0.tgz", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
"integrity": "sha512-YTJCGFdNMHCMfjODYtxRNVAYmTWQ1Lb8PulP/2/f/oEEtglw8oKxKIZmmRkyXrVrHfsKOaVkAc3NT9/dMutO5w==", "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "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", "@rolldown/pluginutils": "1.0.0-beta.27",
"@swc/core": "^1.12.11" "@types/babel__core": "^7.20.5",
"react-refresh": "^0.17.0"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"vite": "^4 || ^5 || ^6 || ^7" "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
} }
}, },
"node_modules/@vitest/expect": { "node_modules/@vitest/expect": {
@@ -3544,7 +3652,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -3833,7 +3940,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001726", "caniuse-lite": "^1.0.30001726",
"electron-to-chromium": "^1.5.173", "electron-to-chromium": "^1.5.173",
@@ -4098,6 +4204,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true,
"license": "MIT"
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -4304,7 +4417,6 @@
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
"license": "MIT", "license": "MIT",
"peer": true,
"funding": { "funding": {
"type": "github", "type": "github",
"url": "https://github.com/sponsors/kossnocorp" "url": "https://github.com/sponsors/kossnocorp"
@@ -4401,7 +4513,8 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT",
"peer": true
}, },
"node_modules/dom-helpers": { "node_modules/dom-helpers": {
"version": "5.2.1", "version": "5.2.1",
@@ -4459,8 +4572,7 @@
"version": "8.6.0", "version": "8.6.0",
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/embla-carousel-react": { "node_modules/embla-carousel-react": {
"version": "8.6.0", "version": "8.6.0",
@@ -4649,7 +4761,6 @@
"integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
@@ -5089,6 +5200,16 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/get-intrinsic": { "node_modules/get-intrinsic": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -5567,7 +5688,6 @@
"integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"abab": "^2.0.6", "abab": "^2.0.6",
"acorn": "^8.8.1", "acorn": "^8.8.1",
@@ -5608,6 +5728,19 @@
} }
} }
}, },
"node_modules/jsesc": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"dev": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
},
"engines": {
"node": ">=6"
}
},
"node_modules/json-buffer": { "node_modules/json-buffer": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@@ -5629,6 +5762,19 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.4", "version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -6197,6 +6343,7 @@
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"lz-string": "bin/bin.js" "lz-string": "bin/bin.js"
} }
@@ -6638,7 +6785,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.11", "nanoid": "^3.3.11",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
@@ -6779,6 +6925,7 @@
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"ansi-regex": "^5.0.1", "ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0", "ansi-styles": "^5.0.0",
@@ -6794,6 +6941,7 @@
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@@ -6804,6 +6952,7 @@
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },
@@ -6816,7 +6965,8 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT",
"peer": true
}, },
"node_modules/prop-types": { "node_modules/prop-types": {
"version": "15.8.1", "version": "15.8.1",
@@ -6890,7 +7040,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
}, },
@@ -6917,7 +7066,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0", "loose-envify": "^1.1.0",
"scheduler": "^0.23.2" "scheduler": "^0.23.2"
@@ -6931,7 +7079,6 @@
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.61.1.tgz", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.61.1.tgz",
"integrity": "sha512-2vbXUFDYgqEgM2RcXcAT2PwDW/80QARi+PKmHy5q2KhuKvOlG8iIYgf7eIlIANR5trW9fJbP4r5aub3a4egsew==", "integrity": "sha512-2vbXUFDYgqEgM2RcXcAT2PwDW/80QARi+PKmHy5q2KhuKvOlG8iIYgf7eIlIANR5trW9fJbP4r5aub3a4egsew==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
}, },
@@ -6974,6 +7121,16 @@
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
} }
}, },
"node_modules/react-refresh": {
"version": "0.17.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
"integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-remove-scroll": { "node_modules/react-remove-scroll": {
"version": "2.7.1", "version": "2.7.1",
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
@@ -7647,7 +7804,6 @@
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
"integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@alloc/quick-lru": "^5.2.0", "@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2", "arg": "^5.0.2",
@@ -7714,8 +7870,7 @@
"version": "0.182.0", "version": "0.182.0",
"resolved": "https://registry.npmjs.org/three/-/three-0.182.0.tgz", "resolved": "https://registry.npmjs.org/three/-/three-0.182.0.tgz",
"integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==", "integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==",
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/tiny-invariant": { "node_modules/tiny-invariant": {
"version": "1.3.3", "version": "1.3.3",
@@ -7778,7 +7933,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -7901,7 +8055,6 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -8102,7 +8255,6 @@
"integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.21.3", "esbuild": "^0.21.3",
"postcss": "^8.4.43", "postcss": "^8.4.43",
@@ -8496,6 +8648,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true,
"license": "ISC"
},
"node_modules/yaml": { "node_modules/yaml": {
"version": "2.6.0", "version": "2.6.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz",

View File

@@ -75,7 +75,7 @@
"@types/node": "^22.16.5", "@types/node": "^22.16.5",
"@types/react": "^18.3.23", "@types/react": "^18.3.23",
"@types/react-dom": "^18.3.7", "@types/react-dom": "^18.3.7",
"@vitejs/plugin-react-swc": "^3.11.0", "@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"eslint": "^9.32.0", "eslint": "^9.32.0",
"eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-hooks": "^5.2.0",

BIN
public/backgroud_effect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

8
public/favicon.svg Normal file
View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
<rect x="48" y="48" width="416" height="416" rx="92" fill="#FFFFFF"/>
<ellipse cx="256" cy="256" rx="210" ry="150" fill="#111111" transform="rotate(-28 256 256)"/>
<circle cx="356" cy="172" r="18" fill="#FFFFFF"/>
<g transform="translate(256 256) rotate(-28)">
<path d="M 0,-170 C 22,-105 60,-72 120,-56 C 60,-40 22,-8 0,64 C -22,-8 -60,-40 -120,-56 C -60,-72 -22,-105 0,-170 Z" fill="#FFFFFF"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 510 B

128
src/components/CountUp.tsx Normal file
View File

@@ -0,0 +1,128 @@
import { useInView, useMotionValue, useSpring } from "motion/react";
import { useCallback, useEffect, useRef } from "react";
interface CountUpProps {
to: number;
from?: number;
direction?: "up" | "down";
delay?: number;
duration?: number;
className?: string;
startWhen?: boolean;
separator?: string;
suffix?: string;
prefix?: string;
padMinLength?: number;
onStart?: () => void;
onEnd?: () => void;
}
export default function CountUp({
to,
from = 0,
direction = "up",
delay = 0,
duration = 2,
className = "",
startWhen = true,
separator = "",
suffix = "",
prefix = "",
padMinLength,
onStart,
onEnd,
}: CountUpProps) {
const ref = useRef<HTMLSpanElement>(null);
const containerRef = useRef<HTMLSpanElement>(null);
const motionValue = useMotionValue(direction === "down" ? to : from);
const damping = 20 + 40 * (1 / duration);
const stiffness = 100 * (1 / duration);
const springValue = useSpring(motionValue, {
damping,
stiffness,
});
const isInView = useInView(containerRef, { once: true, margin: "0px" });
const getDecimalPlaces = (num: number) => {
const str = num.toString();
if (str.includes(".")) {
const decimals = str.split(".")[1];
if (decimals && parseInt(decimals, 10) !== 0) {
return decimals.length;
}
}
return 0;
};
const maxDecimals = Math.max(getDecimalPlaces(from), getDecimalPlaces(to));
const formatValue = useCallback(
(latest: number) => {
if (padMinLength != null) {
const n = Math.round(latest);
return n.toString().padStart(padMinLength, "0");
}
const hasDecimals = maxDecimals > 0;
const options: Intl.NumberFormatOptions = {
useGrouping: !!separator,
minimumFractionDigits: hasDecimals ? maxDecimals : 0,
maximumFractionDigits: hasDecimals ? maxDecimals : 0,
};
let formattedNumber = Intl.NumberFormat("de-DE", options).format(latest);
if (separator) {
formattedNumber = formattedNumber.replace(/\s/g, separator);
}
return formattedNumber;
},
[maxDecimals, separator, padMinLength]
);
useEffect(() => {
if (ref.current) {
ref.current.textContent = formatValue(direction === "down" ? to : from);
}
}, [from, to, direction, formatValue]);
useEffect(() => {
if (isInView && startWhen) {
if (typeof onStart === "function") onStart();
const timeoutId = setTimeout(() => {
motionValue.set(direction === "down" ? from : to);
}, delay * 1000);
const durationTimeoutId = setTimeout(
() => {
if (typeof onEnd === "function") onEnd();
},
delay * 1000 + duration * 1000
);
return () => {
clearTimeout(timeoutId);
clearTimeout(durationTimeoutId);
};
}
}, [isInView, startWhen, motionValue, direction, from, to, delay, onStart, onEnd, duration]);
useEffect(() => {
const unsubscribe = springValue.on("change", (latest) => {
if (ref.current) {
ref.current.textContent = formatValue(latest);
}
});
return () => unsubscribe();
}, [springValue, formatValue]);
return (
<span ref={containerRef} className={className}>
{prefix && <span>{prefix}</span>}
<span ref={ref} />
{suffix && <span>{suffix}</span>}
</span>
);
}

View File

@@ -1,6 +1,7 @@
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { ArrowRight } from "lucide-react"; import { ArrowRight } from "lucide-react";
import CountUp from "@/components/CountUp";
const DifferentiationSection = () => { const DifferentiationSection = () => {
return ( return (
@@ -15,7 +16,9 @@ const DifferentiationSection = () => {
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="p-6 border border-border rounded-lg bg-background"> <div className="p-6 border border-border rounded-lg bg-background">
<div className="text-4xl font-display font-medium text-foreground mb-2">01</div> <div className="text-4xl font-display font-medium text-foreground mb-2">
<CountUp from={0} to={1} duration={1} padMinLength={2} startWhen={true} />
</div>
<h3 className="text-lg font-display font-medium text-foreground uppercase tracking-tight mb-2"> <h3 className="text-lg font-display font-medium text-foreground uppercase tracking-tight mb-2">
Alles aus einer Hand Alles aus einer Hand
</h3> </h3>
@@ -25,7 +28,9 @@ const DifferentiationSection = () => {
</div> </div>
<div className="p-6 border border-border rounded-lg bg-background"> <div className="p-6 border border-border rounded-lg bg-background">
<div className="text-4xl font-display font-medium text-foreground mb-2">02</div> <div className="text-4xl font-display font-medium text-foreground mb-2">
<CountUp from={0} to={2} duration={1} padMinLength={2} startWhen={true} />
</div>
<h3 className="text-lg font-display font-medium text-foreground uppercase tracking-tight mb-2"> <h3 className="text-lg font-display font-medium text-foreground uppercase tracking-tight mb-2">
Systeme statt Inseln Systeme statt Inseln
</h3> </h3>
@@ -35,7 +40,9 @@ const DifferentiationSection = () => {
</div> </div>
<div className="p-6 border border-border rounded-lg bg-background"> <div className="p-6 border border-border rounded-lg bg-background">
<div className="text-4xl font-display font-medium text-foreground mb-2">03</div> <div className="text-4xl font-display font-medium text-foreground mb-2">
<CountUp from={0} to={3} duration={1} padMinLength={2} startWhen={true} />
</div>
<h3 className="text-lg font-display font-medium text-foreground uppercase tracking-tight mb-2"> <h3 className="text-lg font-display font-medium text-foreground uppercase tracking-tight mb-2">
Langfristige Partnerschaft Langfristige Partnerschaft
</h3> </h3>

View File

@@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import Logo from '@/components/Logo';
const DevStudio: React.FC = () => { const DevStudio: React.FC = () => {
return ( return (
@@ -15,7 +16,7 @@ const Footer: React.FC = () => {
<div> <div>
<div className="mr-0 mb-4 md:mr-4 md:flex"> <div className="mr-0 mb-4 md:mr-4 md:flex">
<a className="relative z-20 mr-4 flex items-center space-x-2 px-2 py-1 text-sm font-normal text-white" href="/"> <a className="relative z-20 mr-4 flex items-center space-x-2 px-2 py-1 text-sm font-normal text-white" href="/">
<img alt="logo" width="30" height="30" src="https://assets.aceternity.com/logo-dark.png" /> <Logo width={30} height={30} />
<span className="font-medium text-white">WEBklar</span> <span className="font-medium text-white">WEBklar</span>
</a> </a>
</div> </div>

View File

@@ -13,6 +13,7 @@ import {
MobileNavToggle, MobileNavToggle,
MobileNavMenu, MobileNavMenu,
} from "@/components/ui/resizable-navbar"; } from "@/components/ui/resizable-navbar";
import Logo from "@/components/Logo";
const Header = () => { const Header = () => {
const navItems = [ const navItems = [
@@ -30,6 +31,7 @@ const Header = () => {
{/* Desktop Navigation */} {/* Desktop Navigation */}
<NavBody> <NavBody>
<NavbarLogo href="#"> <NavbarLogo href="#">
<Logo width={30} height={30} />
<span className="font-display text-lg font-medium tracking-tight"> <span className="font-display text-lg font-medium tracking-tight">
Webklar Webklar
</span> </span>
@@ -39,8 +41,7 @@ const Header = () => {
<Link to="/kontakt"> <Link to="/kontakt">
<NavbarButton <NavbarButton
as="span" as="span"
variant="primary" variant="dark"
className="!text-black"
> >
Kontakt Kontakt
</NavbarButton> </NavbarButton>
@@ -52,6 +53,7 @@ const Header = () => {
<MobileNav> <MobileNav>
<MobileNavHeader> <MobileNavHeader>
<NavbarLogo href="#"> <NavbarLogo href="#">
<Logo width={30} height={30} />
<span className="font-display text-lg font-medium tracking-tight"> <span className="font-display text-lg font-medium tracking-tight">
Webklar Webklar
</span> </span>
@@ -82,8 +84,8 @@ const Header = () => {
<Link to="/kontakt" onClick={() => setIsMobileMenuOpen(false)}> <Link to="/kontakt" onClick={() => setIsMobileMenuOpen(false)}>
<NavbarButton <NavbarButton
as="span" as="span"
variant="primary" variant="dark"
className="block w-full text-center !text-black" className="block w-full text-center"
> >
Kontakt Kontakt
</NavbarButton> </NavbarButton>

View File

@@ -1,12 +1,35 @@
import { Link } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { ArrowRight } from "lucide-react"; import { ArrowRight } from "lucide-react";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import Silk from "@/components/Silk"; import Silk from "@/components/Silk";
import CountUp from "@/components/CountUp";
const SPARKLE_SVG = (
<svg className="btn-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M9.813 15.904 9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09ZM18.259 8.715 18 9.75l-.259-1.035a3.375 3.375 0 0 0-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 0 0 2.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 0 0 2.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 0 0-2.456 2.456ZM16.894 20.567 16.5 21.75l-.394-1.183a2.25 2.25 0 0 0-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 0 0 1.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 0 0 1.423 1.423l1.183.394-1.183.394a2.25 2.25 0 0 0-1.423 1.423Z"
/>
</svg>
);
function DemoButtonLetters({ text }: { text: string }) {
return (
<>
{text.split("").map((char, i) => (
<span key={i} className="btn-letter">
{char}
</span>
))}
</>
);
}
const FOUNDING_DATE = new Date("2026-01-25"); // Samstag, 25. Januar 2026 const FOUNDING_DATE = new Date("2026-01-25"); // Samstag, 25. Januar 2026
const Hero = () => { const Hero = () => {
const navigate = useNavigate();
const [companyAge, setCompanyAge] = useState(""); const [companyAge, setCompanyAge] = useState("");
useEffect(() => { useEffect(() => {
@@ -66,23 +89,49 @@ const Hero = () => {
</p> </p>
{/* CTA Buttons */} {/* CTA Buttons */}
<div className="flex flex-col sm:flex-row gap-4 mb-6 animate-fade-in" style={{ animationDelay: '0.5s' }}> <div className="flex flex-col sm:flex-row flex-nowrap items-stretch sm:items-center gap-3 sm:gap-4 mb-6 animate-fade-in" style={{ animationDelay: '0.5s' }}>
<Link to="/kontakt"> <div className="btn-wrapper shrink-0 w-full sm:w-auto">
<Button <button
size="lg" type="button"
className="btn-minimal rounded-full px-8 py-6 text-base font-medium group" className="btn btn-primary w-full sm:w-auto justify-center"
onClick={() => navigate("/kontakt")}
aria-label="Kostenlose Potenzialanalyse sichern"
> >
Kostenlose Potenzialanalyse sichern <ArrowRight className="btn-icon" size={24} strokeWidth={2} aria-hidden />
<ArrowRight className="w-4 h-4 ml-2 group-hover:translate-x-1 transition-transform" /> <div className="txt-wrapper">
</Button> <span className="txt-width-helper" aria-hidden="true">
</Link> <DemoButtonLetters text="Kostenlose Potenzialanalyse sichern" />
<Button </span>
size="lg" <div className="txt-1">
variant="outline" <DemoButtonLetters text="Kostenlose Potenzialanalyse sichern" />
className="btn-outline rounded-full px-8 py-6 text-base font-medium" </div>
<div className="txt-2">
<DemoButtonLetters text="Wird weitergeleitet..." />
</div>
</div>
</button>
</div>
<div className="btn-wrapper w-full sm:w-auto">
<button
type="button"
className="btn w-full sm:w-auto justify-center"
onClick={() => navigate("/kontakt")}
aria-label="System-Demo anfordern"
> >
System-Demo anfordern {SPARKLE_SVG}
</Button> <div className="txt-wrapper">
<span className="txt-width-helper" aria-hidden="true">
<DemoButtonLetters text="System-Demo anfordern" />
</span>
<div className="txt-1">
<DemoButtonLetters text="System-Demo anfordern" />
</div>
<div className="txt-2">
<DemoButtonLetters text="Wird angefordert..." />
</div>
</div>
</button>
</div>
</div> </div>
{/* Trust Line */} {/* Trust Line */}
@@ -97,7 +146,17 @@ const Hero = () => {
<div className="divider mb-12" /> <div className="divider mb-12" />
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-12"> <div className="grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-12">
<div className="animate-fade-in" style={{ animationDelay: '0.6s' }}> <div className="animate-fade-in" style={{ animationDelay: '0.6s' }}>
<div className="stat-number text-4xl md:text-5xl text-foreground mb-2">10+</div> <div className="stat-number text-4xl md:text-5xl text-foreground mb-2">
<CountUp
from={0}
to={10}
direction="up"
duration={1.2}
className="count-up-text"
startWhen={true}
suffix="+"
/>
</div>
<div className="label-tag">Projekte</div> <div className="label-tag">Projekte</div>
</div> </div>
<div className="animate-fade-in" style={{ animationDelay: '0.7s' }}> <div className="animate-fade-in" style={{ animationDelay: '0.7s' }}>
@@ -105,7 +164,17 @@ const Hero = () => {
<div className="label-tag">Am Markt</div> <div className="label-tag">Am Markt</div>
</div> </div>
<div className="animate-fade-in" style={{ animationDelay: '0.8s' }}> <div className="animate-fade-in" style={{ animationDelay: '0.8s' }}>
<div className="stat-number text-4xl md:text-5xl text-foreground mb-2">99,9%</div> <div className="stat-number text-4xl md:text-5xl text-foreground mb-2">
<CountUp
from={0}
to={99.9}
direction="up"
duration={1.5}
className="count-up-text"
startWhen={true}
suffix="%"
/>
</div>
<div className="label-tag">Systemverfügbarkeit</div> <div className="label-tag">Systemverfügbarkeit</div>
</div> </div>
<div className="animate-fade-in" style={{ animationDelay: '0.9s' }}> <div className="animate-fade-in" style={{ animationDelay: '0.9s' }}>

39
src/components/Logo.tsx Normal file
View File

@@ -0,0 +1,39 @@
interface LogoProps {
className?: string;
width?: number;
height?: number;
}
const Logo = ({ className, width = 30, height = 30 }: LogoProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={width}
height={height}
viewBox="0 0 512 512"
className={className}
aria-hidden
>
{/* rounded square background */}
<rect x="48" y="48" width="416" height="416" rx="92" fill="#FFFFFF" />
{/* tilted oval */}
<ellipse cx="256" cy="256" rx="210" ry="150" fill="#111111" transform="rotate(-28 256 256)" />
{/* small dot */}
<circle cx="356" cy="172" r="18" fill="#FFFFFF" />
{/* enlarged sparkle star */}
<g transform="translate(256 256) rotate(-28)">
<path
d="
M 0,-170
C 22,-105 60,-72 120,-56
C 60,-40 22,-8 0,64
C -22,-8 -60,-40 -120,-56
C -60,-72 -22,-105 0,-170
Z
"
fill="#FFFFFF"
/>
</g>
</svg>
);
export default Logo;

View File

@@ -1,22 +1,24 @@
import CountUp from "@/components/CountUp";
const Process = () => { const Process = () => {
const steps = [ const steps = [
{ {
number: "01", number: 1,
title: "Erstgespräch", title: "Erstgespräch",
description: "Wir lernen Ihr Unternehmen und Ihre Ziele kennen. In einem unverbindlichen Gespräch besprechen wir Ihre Wünsche.", description: "Wir lernen Ihr Unternehmen und Ihre Ziele kennen. In einem unverbindlichen Gespräch besprechen wir Ihre Wünsche.",
}, },
{ {
number: "02", number: 2,
title: "Konzept & Design", title: "Konzept & Design",
description: "Basierend auf unserer Analyse erstellen wir ein individuelles Konzept und Design für Ihre Website.", description: "Basierend auf unserer Analyse erstellen wir ein individuelles Konzept und Design für Ihre Website.",
}, },
{ {
number: "03", number: 3,
title: "Entwicklung", title: "Entwicklung",
description: "Unsere Entwickler setzen Ihre Website mit modernsten Technologien um. Sie bleiben informiert.", description: "Unsere Entwickler setzen Ihre Website mit modernsten Technologien um. Sie bleiben informiert.",
}, },
{ {
number: "04", number: 4,
title: "Launch & Support", title: "Launch & Support",
description: "Nach gründlichen Tests geht Ihre Website live. Wir stehen Ihnen auch danach mit Support zur Seite.", description: "Nach gründlichen Tests geht Ihre Website live. Wir stehen Ihnen auch danach mit Support zur Seite.",
}, },
@@ -45,13 +47,22 @@ const Process = () => {
{/* Number */} {/* Number */}
<div className="hidden md:block"> <div className="hidden md:block">
<span className="stat-number text-6xl text-border group-hover:text-muted-foreground/30 transition-colors"> <span className="stat-number text-6xl text-border group-hover:text-muted-foreground/30 transition-colors">
{step.number} <CountUp
from={0}
to={step.number}
direction="up"
duration={1}
padMinLength={2}
startWhen={true}
/>
</span> </span>
</div> </div>
{/* Content */} {/* Content */}
<div className="flex-1"> <div className="flex-1">
<span className="md:hidden label-tag mb-2 block">{step.number}</span> <span className="md:hidden label-tag mb-2 block">
<CountUp from={0} to={step.number} duration={1} padMinLength={2} startWhen={true} />
</span>
<h3 className="text-2xl md:text-3xl font-display font-medium text-foreground mb-4 uppercase tracking-tight"> <h3 className="text-2xl md:text-3xl font-display font-medium text-foreground mb-4 uppercase tracking-tight">
{step.title} {step.title}
</h3> </h3>

View File

@@ -35,8 +35,17 @@ const Values = () => {
]; ];
return ( return (
<section id="features" className="py-24 md:py-32 bg-background relative"> <section id="features" className="py-24 md:py-32 bg-background relative overflow-hidden">
<div className="container mx-auto px-6"> {/* Hintergrundbild: kleiner, leicht transparent */}
<div
className="absolute inset-0 bg-right bg-no-repeat opacity-[0.3]"
style={{
backgroundImage: "url(/backgroud_effect.png)",
backgroundSize: "45%",
}}
aria-hidden
/>
<div className="container mx-auto px-6 relative z-10">
{/* Section Header */} {/* Section Header */}
<div className="mb-16 md:mb-24 max-w-3xl"> <div className="mb-16 md:mb-24 max-w-3xl">
<div className="label-tag mb-4">Was Sie bekommen</div> <div className="label-tag mb-4">Was Sie bekommen</div>

View File

@@ -5,7 +5,7 @@ import { cn } from "@/lib/utils";
const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", { const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", {
variants: { variants: {
variant: { variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90", default: "btn-primary-style rounded-full bg-[hsl(198,93%,42%)] text-white hover:bg-[hsl(198,93%,48%)] border border-white/20",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",

View File

@@ -290,13 +290,13 @@ export const NavbarButton = ({
...props ...props
}: NavbarButtonProps) => { }: NavbarButtonProps) => {
const baseStyles = const baseStyles =
"px-4 py-2 rounded-md bg-white text-black text-sm font-bold relative cursor-pointer hover:-translate-y-0.5 transition duration-200 inline-block text-center"; "px-4 py-2 rounded-full text-sm font-bold relative cursor-pointer transition duration-200 inline-block text-center";
const variantStyles = { const variantStyles = {
primary: primary:
"shadow-[0_0_24px_rgba(34,_42,_53,_0.06),_0_1px_1px_rgba(0,_0,_0,_0.05),_0_0_0_1px_rgba(34,_42,_53,_0.04),_0_0_4px_rgba(34,_42,_53,_0.08),_0_16px_68px_rgba(47,_48,_55,_0.05),_0_1px_0_rgba(255,_255,_255,_0.1)_inset]", "bg-[hsl(198,93%,42%)] text-white border border-white/20 shadow-[inset_0_1px_1px_rgba(255,255,255,0.25),inset_0_2px_2px_rgba(255,255,255,0.2),0_2px_4px_rgba(0,0,0,0.2),0_4px_8px_rgba(0,0,0,0.15)] hover:border-white/40 hover:shadow-[inset_0_1px_1px_rgba(255,255,255,0.3),inset_0_2px_2px_rgba(255,255,255,0.25),0_2px_4px_rgba(0,0,0,0.2),0_4px_8px_rgba(0,0,0,0.15)]",
secondary: "bg-transparent shadow-none dark:text-white", secondary: "bg-transparent shadow-none dark:text-white",
dark: "bg-black text-white shadow-[0_0_24px_rgba(34,_42,_53,_0.06),_0_1px_1px_rgba(0,_0,_0,_0.05),_0_0_0_1px_rgba(34,_42,_53,_0.04),_0_0_4px_rgba(34,_42,_53,_0.08),_0_16px_68px_rgba(47,_48,_55,_0.05),_0_1px_0_rgba(255,_255,_255,_0.1)_inset]", dark: "btn !text-white",
gradient: gradient:
"bg-gradient-to-b from-blue-500 to-blue-700 text-white shadow-[0px_2px_0px_0px_rgba(255,255,255,0.3)_inset]", "bg-gradient-to-b from-blue-500 to-blue-700 text-white shadow-[0px_2px_0px_0px_rgba(255,255,255,0.3)_inset]",
}; };

View File

@@ -1,19 +1,17 @@
/* Fonts first @import must be at the very top */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
@import url("https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Crimson+Pro:wght@400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Lora:wght@400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap");
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
/* webklar Design System - Muradov Inspired Minimal Dark Theme */ /* webklar Design System - Muradov Inspired Minimal Dark Theme */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
@import url("https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Crimson+Pro:wght@400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Lora:wght@400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap");
@layer base { @layer base {
:root { :root {
/* Ultra Minimal Deep Black Theme - Muradov Inspired */ /* Ultra Minimal Deep Black Theme - Muradov Inspired */
@@ -241,6 +239,457 @@
background: hsl(0 0% 10%); background: hsl(0 0% 10%);
} }
/* Custom CTA button (System-Demo) */
.btn-wrapper {
position: relative;
display: inline-block;
width: fit-content;
flex-shrink: 0;
}
.btn {
--border-radius: 24px;
--padding: 4px;
--transition: 0.35s cubic-bezier(0.4, 0, 0.2, 1);
--button-color: #101010;
--highlight-color-hue: 210deg;
outline: none;
user-select: none;
display: flex;
flex-wrap: nowrap;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.5em 1.1em;
font-family: "Poppins", "Inter", "Segoe UI", sans-serif;
font-size: 1em;
font-weight: 400;
background-color: var(--button-color);
overflow: hidden;
box-shadow:
inset 0px 1px 1px rgba(255, 255, 255, 0.2),
inset 0px 2px 2px rgba(255, 255, 255, 0.15),
inset 0px 4px 4px rgba(255, 255, 255, 0.1),
inset 0px 8px 8px rgba(255, 255, 255, 0.05),
inset 0px 16px 16px rgba(255, 255, 255, 0.05),
0px -1px 1px rgba(0, 0, 0, 0.02),
0px -2px 2px rgba(0, 0, 0, 0.03),
0px -4px 4px rgba(0, 0, 0, 0.05),
0px -8px 8px rgba(0, 0, 0, 0.06),
0px -16px 16px rgba(0, 0, 0, 0.08);
border: solid 1px rgba(255, 255, 255, 0.13);
border-radius: var(--border-radius);
cursor: pointer;
transition: box-shadow var(--transition), border var(--transition), background-color var(--transition);
position: relative;
}
.btn::before {
content: "";
position: absolute;
top: calc(0px - var(--padding));
left: calc(0px - var(--padding));
width: calc(100% + var(--padding) * 2);
height: calc(100% + var(--padding) * 2);
border-radius: calc(var(--border-radius) + var(--padding));
pointer-events: none;
background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.27), rgba(0, 0, 0, 0.4));
z-index: -1;
transition: box-shadow var(--transition), filter var(--transition);
box-shadow:
0 -8px 8px -6px transparent inset,
0 -16px 16px -8px transparent inset,
1px 1px 1px rgba(255, 255, 255, 0.13),
2px 2px 2px rgba(255, 255, 255, 0.07),
-1px -1px 1px rgba(0, 0, 0, 0.13),
-2px -2px 2px rgba(0, 0, 0, 0.07);
}
.btn::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: inherit;
pointer-events: none;
background-image: linear-gradient(
0deg,
#fff,
hsl(var(--highlight-color-hue), 100%, 70%),
hsla(var(--highlight-color-hue), 100%, 70%, 0.5),
8%,
transparent
);
background-position: 0 0;
opacity: 0;
transition: opacity var(--transition), filter var(--transition);
}
.btn-letter {
position: relative;
display: inline-block;
color: rgba(255, 255, 255, 0.33);
animation: letter-anim 2.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
transition: color var(--transition), text-shadow var(--transition), opacity var(--transition), transform var(--transition);
}
@keyframes letter-anim {
50% {
text-shadow: 0 0 3px rgba(255, 255, 255, 0.53);
color: #fff;
}
}
.btn-svg {
flex-shrink: 0;
height: 24px;
width: 24px;
fill: #e8e8e8;
animation: flicker 2.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
animation-delay: 0.5s;
filter: drop-shadow(0 0 2px rgba(255, 255, 255, 0.6));
transition: fill var(--transition), filter var(--transition), opacity var(--transition);
}
@keyframes flicker {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.4;
}
}
.txt-wrapper {
position: relative;
display: flex;
align-items: center;
flex-shrink: 0;
overflow: hidden;
min-width: 0;
padding-right: 2px;
}
.txt-width-helper {
visibility: hidden;
white-space: nowrap;
font: inherit;
word-spacing: -1em;
pointer-events: none;
}
.txt-width-helper .btn-letter {
animation: none;
}
.txt-1,
.txt-2 {
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
word-spacing: -1em;
white-space: nowrap;
max-width: 100%;
overflow: hidden;
}
.txt-1 {
animation: appear-anim 1s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
.txt-2 {
opacity: 0;
}
@keyframes appear-anim {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.btn:focus .txt-1 {
animation: opacity-anim 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
animation-delay: 0.8s;
}
.btn:focus .txt-2 {
animation: opacity-anim 0.4s cubic-bezier(0.4, 0, 0.2, 1) reverse forwards;
animation-delay: 0.8s;
}
@keyframes opacity-anim {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.btn:focus .btn-letter {
animation: focused-letter-anim 1.2s cubic-bezier(0.4, 0, 0.2, 1) forwards, letter-anim 1.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
animation-delay: 0s, 1s;
}
@keyframes focused-letter-anim {
0%,
100% {
transform: scale(1);
filter: blur(0px);
}
50% {
transform: scale(1.08);
filter: blur(2px) brightness(150%)
drop-shadow(0 0 8px hsl(var(--highlight-color-hue), 100%, 70%));
}
}
.btn:focus .btn-svg {
animation-duration: 1.2s;
animation-delay: 0.2s;
}
.btn:focus::before {
box-shadow:
0 -8px 12px -6px rgba(255, 255, 255, 0.2) inset,
0 -16px 16px -8px hsla(var(--highlight-color-hue), 100%, 70%, 0.2) inset,
1px 1px 1px rgba(255, 255, 255, 0.2),
2px 2px 2px rgba(255, 255, 255, 0.07),
-1px -1px 1px rgba(0, 0, 0, 0.13),
-2px -2px 2px rgba(0, 0, 0, 0.07);
}
.btn:focus::after {
opacity: 0.6;
mask-image: linear-gradient(0deg, #fff, transparent);
filter: brightness(100%);
}
.btn-letter:nth-child(1),
.btn:focus .btn-letter:nth-child(1) { animation-delay: 0s; }
.btn-letter:nth-child(2),
.btn:focus .btn-letter:nth-child(2) { animation-delay: 0.08s; }
.btn-letter:nth-child(3),
.btn:focus .btn-letter:nth-child(3) { animation-delay: 0.16s; }
.btn-letter:nth-child(4),
.btn:focus .btn-letter:nth-child(4) { animation-delay: 0.24s; }
.btn-letter:nth-child(5),
.btn:focus .btn-letter:nth-child(5) { animation-delay: 0.32s; }
.btn-letter:nth-child(6),
.btn:focus .btn-letter:nth-child(6) { animation-delay: 0.4s; }
.btn-letter:nth-child(7),
.btn:focus .btn-letter:nth-child(7) { animation-delay: 0.48s; }
.btn-letter:nth-child(8),
.btn:focus .btn-letter:nth-child(8) { animation-delay: 0.56s; }
.btn-letter:nth-child(9),
.btn:focus .btn-letter:nth-child(9) { animation-delay: 0.64s; }
.btn-letter:nth-child(10),
.btn:focus .btn-letter:nth-child(10) { animation-delay: 0.72s; }
.btn-letter:nth-child(11),
.btn:focus .btn-letter:nth-child(11) { animation-delay: 0.8s; }
.btn-letter:nth-child(12),
.btn:focus .btn-letter:nth-child(12) { animation-delay: 0.88s; }
.btn-letter:nth-child(13),
.btn:focus .btn-letter:nth-child(13) { animation-delay: 0.96s; }
.btn-letter:nth-child(14),
.btn:focus .btn-letter:nth-child(14) { animation-delay: 1.04s; }
.btn-letter:nth-child(15),
.btn:focus .btn-letter:nth-child(15) { animation-delay: 1.12s; }
.btn-letter:nth-child(16),
.btn:focus .btn-letter:nth-child(16) { animation-delay: 1.2s; }
.btn-letter:nth-child(17),
.btn:focus .btn-letter:nth-child(17) { animation-delay: 1.28s; }
.btn-letter:nth-child(18),
.btn:focus .btn-letter:nth-child(18) { animation-delay: 1.36s; }
.btn-letter:nth-child(19),
.btn:focus .btn-letter:nth-child(19) { animation-delay: 1.44s; }
.btn-letter:nth-child(20),
.btn:focus .btn-letter:nth-child(20) { animation-delay: 1.52s; }
.btn-letter:nth-child(21),
.btn:focus .btn-letter:nth-child(21) { animation-delay: 1.6s; }
.btn-letter:nth-child(22),
.btn:focus .btn-letter:nth-child(22) { animation-delay: 1.68s; }
.btn-letter:nth-child(23),
.btn:focus .btn-letter:nth-child(23) { animation-delay: 1.76s; }
.btn-letter:nth-child(24),
.btn:focus .btn-letter:nth-child(24) { animation-delay: 1.84s; }
.btn-letter:nth-child(25),
.btn:focus .btn-letter:nth-child(25) { animation-delay: 1.92s; }
.btn-letter:nth-child(26),
.btn:focus .btn-letter:nth-child(26) { animation-delay: 2s; }
.btn-letter:nth-child(27),
.btn:focus .btn-letter:nth-child(27) { animation-delay: 2.08s; }
.btn-letter:nth-child(28),
.btn:focus .btn-letter:nth-child(28) { animation-delay: 2.16s; }
.btn-letter:nth-child(29),
.btn:focus .btn-letter:nth-child(29) { animation-delay: 2.24s; }
.btn-letter:nth-child(30),
.btn:focus .btn-letter:nth-child(30) { animation-delay: 2.32s; }
.btn-letter:nth-child(31),
.btn:focus .btn-letter:nth-child(31) { animation-delay: 2.4s; }
.btn-letter:nth-child(32),
.btn:focus .btn-letter:nth-child(32) { animation-delay: 2.48s; }
.btn-letter:nth-child(33),
.btn:focus .btn-letter:nth-child(33) { animation-delay: 2.56s; }
.btn-letter:nth-child(34),
.btn:focus .btn-letter:nth-child(34) { animation-delay: 2.64s; }
.btn-letter:nth-child(35),
.btn:focus .btn-letter:nth-child(35) { animation-delay: 2.72s; }
.btn:active {
border: solid 1px hsla(var(--highlight-color-hue), 100%, 80%, 0.7);
background-color: hsla(var(--highlight-color-hue), 50%, 20%, 0.5);
}
.btn:active::before {
box-shadow:
0 -8px 12px -6px rgba(255, 255, 255, 0.67) inset,
0 -16px 16px -8px hsla(var(--highlight-color-hue), 100%, 70%, 0.8) inset,
1px 1px 1px rgba(255, 255, 255, 0.27),
2px 2px 2px rgba(255, 255, 255, 0.13),
-1px -1px 1px rgba(0, 0, 0, 0.13),
-2px -2px 2px rgba(0, 0, 0, 0.07);
}
.btn:active::after {
opacity: 1;
mask-image: linear-gradient(0deg, #fff, transparent);
filter: brightness(200%);
}
.btn:active .btn-letter {
text-shadow: 0 0 1px hsla(var(--highlight-color-hue), 100%, 90%, 0.9);
animation: none;
}
.btn:hover {
border: solid 1px hsla(var(--highlight-color-hue), 100%, 80%, 0.4);
}
.btn:hover::before {
box-shadow:
0 -8px 8px -6px rgba(255, 255, 255, 0.67) inset,
0 -16px 16px -8px hsla(var(--highlight-color-hue), 100%, 70%, 0.3) inset,
1px 1px 1px rgba(255, 255, 255, 0.13),
2px 2px 2px rgba(255, 255, 255, 0.07),
-1px -1px 1px rgba(0, 0, 0, 0.13),
-2px -2px 2px rgba(0, 0, 0, 0.07);
}
.btn:hover::after {
opacity: 1;
mask-image: linear-gradient(0deg, #fff, transparent);
}
.btn:hover .btn-svg {
fill: #fff;
filter: drop-shadow(0 0 3px hsl(var(--highlight-color-hue), 100%, 70%))
drop-shadow(0 -4px 6px rgba(0, 0, 0, 0.6));
animation: none;
}
@media (max-width: 639px) {
.btn {
font-size: 0.9rem;
padding: 0.5em 0.9em;
gap: 0.4rem;
}
.btn-svg,
.btn-icon {
width: 20px;
height: 20px;
}
}
/* Shared primary button look for all blue/primary buttons */
.btn-primary-style {
padding: 0.5em 1.1em;
border-radius: 24px;
box-shadow:
inset 0px 1px 1px rgba(255, 255, 255, 0.25),
inset 0px 2px 2px rgba(255, 255, 255, 0.2),
0px 2px 4px rgba(0, 0, 0, 0.2),
0px 4px 8px rgba(0, 0, 0, 0.15);
transition: box-shadow 0.35s cubic-bezier(0.4, 0, 0.2, 1),
border 0.35s cubic-bezier(0.4, 0, 0.2, 1),
background-color 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}
.btn-primary-style:hover {
border-color: rgba(255, 255, 255, 0.4);
box-shadow:
inset 0px 1px 1px rgba(255, 255, 255, 0.3),
inset 0px 2px 2px rgba(255, 255, 255, 0.25),
0px 2px 4px rgba(0, 0, 0, 0.2),
0px 4px 8px rgba(0, 0, 0, 0.15);
}
/* Primary (blue) variant same structure, blue color */
.btn-primary {
--button-color: hsl(198, 93%, 42%);
--highlight-color-hue: 198deg;
box-shadow:
inset 0px 1px 1px rgba(255, 255, 255, 0.25),
inset 0px 2px 2px rgba(255, 255, 255, 0.2),
0px 2px 4px rgba(0, 0, 0, 0.2),
0px 4px 8px rgba(0, 0, 0, 0.15);
border: solid 1px rgba(255, 255, 255, 0.2);
}
.btn-primary::before {
background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.25));
}
.btn-primary .btn-letter {
color: rgba(255, 255, 255, 0.75);
}
@keyframes letter-anim-primary {
0%, 100% {
text-shadow: none;
color: rgba(255, 255, 255, 0.75);
}
50% {
text-shadow: 0 0 6px rgba(255, 255, 255, 0.95), 0 0 12px rgba(255, 255, 255, 0.4);
color: #fff;
}
}
.btn-primary .btn-letter {
animation: letter-anim-primary 2.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
/* Arrow icon (stroke-based) same size and animation as .btn-svg */
.btn-icon {
flex-shrink: 0;
width: 24px;
height: 24px;
color: #e8e8e8;
animation: flicker 2.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
animation-delay: 0.5s;
filter: drop-shadow(0 0 2px rgba(255, 255, 255, 0.6));
transition: color var(--transition), filter var(--transition), opacity var(--transition);
}
.btn:hover .btn-icon {
color: #fff;
filter: drop-shadow(0 0 3px hsl(var(--highlight-color-hue), 100%, 70%))
drop-shadow(0 -4px 6px rgba(0, 0, 0, 0.6));
animation: none;
}
.btn:focus .btn-icon {
animation-duration: 1.2s;
animation-delay: 0.2s;
}
/* Stats number */ /* Stats number */
.stat-number { .stat-number {
font-family: 'Space Grotesk', system-ui, sans-serif; font-family: 'Space Grotesk', system-ui, sans-serif;
@@ -249,6 +698,23 @@
line-height: 1; line-height: 1;
} }
/* Count-up with gradient */
.count-up-text {
background: linear-gradient(135deg, hsl(0 0% 92%) 0%, hsl(0 0% 70%) 50%, hsl(0 0% 92%) 100%);
background-size: 200% auto;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.dark .count-up-text {
background: linear-gradient(135deg, hsl(0 0% 98%) 0%, hsl(0 0% 75%) 50%, hsl(0 0% 98%) 100%);
background-size: 200% auto;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Grid line decoration */ /* Grid line decoration */
.grid-lines { .grid-lines {
background-image: background-image:

View File

@@ -1,5 +1,5 @@
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc"; import react from "@vitejs/plugin-react";
import path from "path"; import path from "path";
import { componentTagger } from "lovable-tagger"; import { componentTagger } from "lovable-tagger";