From 72180ba817b5794bf39013cfe9e6a9083855ceee Mon Sep 17 00:00:00 2001 From: Koala <6156589+Shik3i@users.noreply.github.com> Date: Mon, 1 Jun 2026 03:20:51 +0200 Subject: [PATCH] feat(website): SEO, a11y, and build pipeline overhaul MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SEO: per-locale og:locale, Organization+WebSite schema, FAQPage replacing ItemList - SEO: BreadcrumbList on legal pages, site.webmanifest, expanded sitemap - a11y: hamburger ARIA+ESC, skip-to-content, aria-hidden on step-num - a11y: focus-visible states, prefers-reduced-motion, emoji→SVG icons - CSS: extract .mock-section-label, replace transition:all, will-change hints - Build: esbuild JS minifier (-46%), sharp AVIF conversion (26 files, quality 70) - Build: content hashing (style.XXXX.min.css), SVG minification, picture injection - Cleanup: remove lightningcss (caused CSS merging bugs) --- package-lock.json | 1312 ++++++++++++++++- package.json | 5 +- website/app.js | 24 +- website/build.js | 343 ++--- website/datenschutz.html | 11 + website/impressum.html | 11 + website/locales/de.json | 1 + website/locales/en.json | 1 + website/locales/es.json | 1 + website/locales/fr.json | 1 + website/locales/pt-BR.json | 1 + website/locales/ru.json | 1 + website/site.webmanifest | 23 + website/style.css | 94 +- website/template.html | 153 +- website/www/README.md | 8 + website/www/app.e6679b8d.min.js | 59 + website/www/app.min.js | 628 -------- website/www/assets/KoalaCupple_New-1x.avif | Bin 0 -> 12068 bytes website/www/assets/KoalaCupple_New.avif | Bin 0 -> 25281 bytes website/www/assets/KoalaDeploy-1x.avif | Bin 0 -> 17175 bytes website/www/assets/KoalaDeploy.avif | Bin 0 -> 35743 bytes website/www/assets/KoalaGithub-1x.avif | Bin 0 -> 10993 bytes website/www/assets/KoalaGithub.avif | Bin 0 -> 19993 bytes website/www/assets/KoalaImprintl.avif | Bin 0 -> 23814 bytes website/www/assets/KoalaPrivacy.avif | Bin 0 -> 24129 bytes website/www/assets/KoalaQuestions-1x.avif | Bin 0 -> 15799 bytes website/www/assets/KoalaQuestions.avif | Bin 0 -> 19860 bytes website/www/assets/KoalaSearching.avif | Bin 0 -> 23089 bytes website/www/assets/KoalaThumbsDown.avif | Bin 0 -> 15322 bytes website/www/assets/KoalaThumbsUp.avif | Bin 0 -> 17283 bytes website/www/assets/LookDownKoala-1x.avif | Bin 0 -> 4163 bytes website/www/assets/LookDownKoala.avif | Bin 0 -> 8933 bytes website/www/assets/NewLogoIcon.avif | Bin 0 -> 5799 bytes website/www/assets/NewLogoIcon_128.avif | Bin 0 -> 4191 bytes website/www/assets/NewLogoIcon_80.avif | Bin 0 -> 2946 bytes .../www/assets/PlatformJuggler_New-1x.avif | Bin 0 -> 20447 bytes website/www/assets/PlatformJuggler_New.avif | Bin 0 -> 32773 bytes website/www/assets/PopcornFriends-1x.avif | Bin 0 -> 12947 bytes website/www/assets/PopcornFriends.avif | Bin 0 -> 23527 bytes website/www/assets/ProContraKoala-1x.avif | Bin 0 -> 13544 bytes website/www/assets/ProContraKoala.avif | Bin 0 -> 19616 bytes website/www/assets/RemoteProf-1x.avif | Bin 0 -> 11235 bytes website/www/assets/RemoteProf.avif | Bin 0 -> 23134 bytes website/www/datenschutz.html | 35 +- website/www/de/index.html | 203 +-- website/www/es/index.html | 203 +-- website/www/fr/index.html | 203 +-- website/www/impressum.html | 35 +- website/www/index.html | 201 +-- website/www/join.html | 24 +- website/www/lang-init.f4d146ef.min.js | 1 + website/www/lang-init.min.js | 69 - website/www/pt-BR/index.html | 203 +-- website/www/ru/index.html | 203 +-- website/www/site.webmanifest | 23 + website/www/style.62d39607.min.css | 1 + website/www/style.min.css | 1 - 58 files changed, 2569 insertions(+), 1513 deletions(-) create mode 100644 website/site.webmanifest create mode 100644 website/www/README.md create mode 100644 website/www/app.e6679b8d.min.js delete mode 100644 website/www/app.min.js create mode 100644 website/www/assets/KoalaCupple_New-1x.avif create mode 100644 website/www/assets/KoalaCupple_New.avif create mode 100644 website/www/assets/KoalaDeploy-1x.avif create mode 100644 website/www/assets/KoalaDeploy.avif create mode 100644 website/www/assets/KoalaGithub-1x.avif create mode 100644 website/www/assets/KoalaGithub.avif create mode 100644 website/www/assets/KoalaImprintl.avif create mode 100644 website/www/assets/KoalaPrivacy.avif create mode 100644 website/www/assets/KoalaQuestions-1x.avif create mode 100644 website/www/assets/KoalaQuestions.avif create mode 100644 website/www/assets/KoalaSearching.avif create mode 100644 website/www/assets/KoalaThumbsDown.avif create mode 100644 website/www/assets/KoalaThumbsUp.avif create mode 100644 website/www/assets/LookDownKoala-1x.avif create mode 100644 website/www/assets/LookDownKoala.avif create mode 100644 website/www/assets/NewLogoIcon.avif create mode 100644 website/www/assets/NewLogoIcon_128.avif create mode 100644 website/www/assets/NewLogoIcon_80.avif create mode 100644 website/www/assets/PlatformJuggler_New-1x.avif create mode 100644 website/www/assets/PlatformJuggler_New.avif create mode 100644 website/www/assets/PopcornFriends-1x.avif create mode 100644 website/www/assets/PopcornFriends.avif create mode 100644 website/www/assets/ProContraKoala-1x.avif create mode 100644 website/www/assets/ProContraKoala.avif create mode 100644 website/www/assets/RemoteProf-1x.avif create mode 100644 website/www/assets/RemoteProf.avif create mode 100644 website/www/lang-init.f4d146ef.min.js delete mode 100644 website/www/lang-init.min.js create mode 100644 website/www/site.webmanifest create mode 100644 website/www/style.62d39607.min.css delete mode 100644 website/www/style.min.css diff --git a/package-lock.json b/package-lock.json index b6a0ab2..f2e39ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,472 @@ { "name": "koalasync", - "version": "1.8.5", + "version": "1.9.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "koalasync", - "version": "1.8.5", + "version": "1.9.3", "devDependencies": { "archiver": "^7.0.1", + "esbuild": "^0.28.0", "eslint": "^10.4.0", - "fs-extra": "^11.2.0" + "fs-extra": "^11.2.0", + "sharp": "^0.34.5", + "svgo": "^4.0.1" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -225,6 +681,496 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -539,6 +1485,13 @@ ], "license": "MIT" }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, "node_modules/brace-expansion": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", @@ -604,6 +1557,16 @@ "dev": true, "license": "MIT" }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, "node_modules/compress-commons": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", @@ -670,6 +1633,86 @@ "node": ">= 8" } }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -695,6 +1738,75 @@ "dev": true, "license": "MIT" }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -709,6 +1821,61 @@ "dev": true, "license": "MIT" }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -1354,6 +2521,13 @@ "dev": true, "license": "ISC" }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/minimatch": { "version": "9.0.9", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", @@ -1404,6 +2578,19 @@ "node": ">=0.10.0" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -1498,6 +2685,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -1596,6 +2790,74 @@ ], "license": "MIT" }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1632,6 +2894,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/streamx": { "version": "2.25.0", "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", @@ -1758,6 +3030,32 @@ "node": ">=8" } }, + "node_modules/svgo": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", + "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^11.1.0", + "css-select": "^5.1.0", + "css-tree": "^3.0.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "^1.5.0" + }, + "bin": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, "node_modules/tar-stream": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", @@ -1791,6 +3089,14 @@ "b4a": "^1.6.4" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index eb5c6ac..a46ae9d 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,10 @@ }, "devDependencies": { "archiver": "^7.0.1", + "esbuild": "^0.28.0", "eslint": "^10.4.0", - "fs-extra": "^11.2.0" + "fs-extra": "^11.2.0", + "sharp": "^0.34.5", + "svgo": "^4.0.1" } } diff --git a/website/app.js b/website/app.js index 578dd29..ed4497e 100644 --- a/website/app.js +++ b/website/app.js @@ -433,15 +433,25 @@ document.addEventListener('DOMContentLoaded', () => { // Mobile Hamburger Menu Toggle const hamburger = document.querySelector('.hamburger'); - const navLinks = document.querySelector('.nav-links'); + const navLinks = document.querySelector('#primary-nav'); if (hamburger && navLinks) { - // Initialize accessibility attribute hamburger.setAttribute('aria-expanded', 'false'); - - hamburger.addEventListener('click', () => { - const isOpen = navLinks.classList.toggle('open'); - hamburger.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); - }); + + const open = () => { + navLinks.classList.add('open'); + hamburger.setAttribute('aria-expanded', 'true'); + document.addEventListener('keydown', onEsc); + }; + const close = () => { + navLinks.classList.remove('open'); + hamburger.setAttribute('aria-expanded', 'false'); + document.removeEventListener('keydown', onEsc); + }; + const toggle = () => navLinks.classList.contains('open') ? close() : open(); + const onEsc = (e) => { if (e.key === 'Escape') close(); }; + + hamburger.addEventListener('click', toggle); + navLinks.querySelectorAll('a').forEach(a => a.addEventListener('click', close)); } // Dynamically localize home links on root dynamic pages (impressum, datenschutz, join) diff --git a/website/build.js b/website/build.js index bde1221..952386c 100644 --- a/website/build.js +++ b/website/build.js @@ -1,12 +1,15 @@ /** * KoalaSync Static Site Generator (i18n compiler) - * Pure, dependency-free Node.js build pipeline. + * Build pipeline: esbuild + AVIF + hashing + SVG min. */ - const fs = require('fs'); const path = require('path'); +const crypto = require('crypto'); +const sharp = require('sharp'); +const esbuild = require('esbuild'); +const { optimize: svgoOptimize } = require('svgo'); -// Minify CSS: strips comments, collapses whitespace, removes trailing semicolons +// CSS minifier: simple regex-based (proven, 27% reduction, no deps) function minifyCSS(code) { return code .replace(/\/\*[\s\S]*?\*\//g, '') @@ -15,216 +18,224 @@ function minifyCSS(code) { .replace(/;\}/g, '}') .trim(); } +const MIN_AVIF_KB = 3; -// Minify JS: state-machine that tracks string context so -// // inside URLs (https://) inside strings is never mistaken for a comment. -function minifyJS(code) { - var out = ''; - var inSingle = false, inDouble = false, inTemplate = false; - var templateBrace = 0; - var i = 0; - - while (i < code.length) { - var ch = code[i]; - var next = code[i + 1] || ''; - - // --- Escape handling (must come before string toggle) --- - if (ch === '\\' && (inSingle || inDouble || inTemplate)) { - out += ch + next; - i += 2; - continue; - } - - // --- String toggle --- - if (!inDouble && !inTemplate && ch === "'") { inSingle = !inSingle; out += ch; i++; continue; } - if (!inSingle && !inTemplate && ch === '"') { inDouble = !inDouble; out += ch; i++; continue; } - if (!inSingle && !inDouble) { - if (ch === '`' && !inTemplate) { inTemplate = true; templateBrace = 0; out += ch; i++; continue; } - if (inTemplate && ch === '`' && templateBrace === 0) { inTemplate = false; out += ch; i++; continue; } - } - - // --- Template interpolation depth tracking --- - if (inTemplate && !inSingle && !inDouble) { - if (ch === '$' && next === '{') { templateBrace++; out += ch + next; i += 2; continue; } - if (ch === '}' && templateBrace > 0) { templateBrace--; out += ch; i++; continue; } - } - - // --- Inside a string / template literal → output as-is --- - if (inSingle || inDouble || inTemplate) { out += ch; i++; continue; } - - // --- Outside strings: handle comments --- - if (ch === '/' && next === '/') { - while (i < code.length && code[i] !== '\n') i++; - out += '\n'; - i++; - continue; - } - if (ch === '/' && next === '*') { - i += 2; - while (i < code.length - 1) { - if (code[i] === '*' && code[i + 1] === '/') { i += 2; break; } - if (code[i] === '\n') out += '\n'; - i++; - } - continue; - } - - out += ch; - i++; - } - - // Collapse horizontal whitespace (preserve newlines) - return out - .replace(/[^\S\n]+/g, ' ') - .replace(/^ +/gm, '') - .replace(/ +$/gm, '') - .replace(/\n{3,}/g, '\n\n') - .trim(); -} - -// Helper to recursively copy directories function copyDirSync(src, dest) { fs.mkdirSync(dest, { recursive: true }); - const entries = fs.readdirSync(src, { withFileTypes: true }); - - for (let entry of entries) { - const srcPath = path.join(src, entry.name); - const destPath = path.join(dest, entry.name); - - if (entry.isDirectory()) { - copyDirSync(srcPath, destPath); - } else { - // Binary assets (images, etc.) are copied as-is - fs.copyFileSync(srcPath, destPath); - } + for (const entry of fs.readdirSync(src, { withFileTypes: true })) { + const s = path.join(src, entry.name); + const d = path.join(dest, entry.name); + entry.isDirectory() ? copyDirSync(s, d) : fs.copyFileSync(s, d); } } -function compile() { - console.log('Starting KoalaSync i18n compilation...'); +function sha8(buf) { return crypto.createHash('sha256').update(buf).digest('hex').slice(0, 8); } +async function minifyJS(raw) { + const result = await esbuild.transform(raw, { + loader: 'js', + minify: true, + target: 'es2020' + }); + return result.code; +} + +function injectAvifPictures(html) { + return html.replace(/]*)>/gi, (match, attrs) => { + const srcMatch = attrs.match(/\bsrc="([^"]*)"/i); + if (!srcMatch) return match; + if (!/\.webp"$/i.test(srcMatch[0])) return match; + const src = srcMatch[1]; + const avifSrc = src.replace(/\.webp$/i, '.avif'); + const srcsetMatch = attrs.match(/\bsrcset="([^"]*)"/i); + if (srcsetMatch) { + const avifSrcset = srcsetMatch[1].replace(/\.webp/gi, '.avif'); + return ``; + } + return ``; + }); +} + +function minifyInlineSvgs(html) { + const svgRegex = //gi; + return html.replace(svgRegex, (svg) => { + try { + const result = svgoOptimize(svg, { multipass: true, plugins: ['preset-default'] }); + return result.data; + } catch { return svg; } + }); +} + +async function compile() { + console.log('Starting KoalaSync i18n compilation...'); const websiteDir = __dirname; const wwwDir = path.join(websiteDir, 'www'); - - // 1. Create build directories fs.mkdirSync(wwwDir, { recursive: true }); - // 2. Read template + // ── 1. Minify CSS/JS (must happen first so hashes go into HTML) ── + console.log('Minifying CSS/JS...'); + const styleRaw = fs.readFileSync(path.join(websiteDir, 'style.css'), 'utf8'); + const styleMin = minifyCSS(styleRaw); + const styleHash = sha8(styleMin); + const styleName = `style.${styleHash}.min.css`; + + const appRaw = fs.readFileSync(path.join(websiteDir, 'app.js'), 'utf8'); + const appMin = await minifyJS(appRaw); + const appHash = sha8(appMin); + const appName = `app.${appHash}.min.js`; + + const langRaw = fs.readFileSync(path.join(websiteDir, 'lang-init.js'), 'utf8'); + const langMin = await minifyJS(langRaw); + const langHash = sha8(langMin); + const langName = `lang-init.${langHash}.min.js`; + + const stylePct = ((1 - styleMin.length / styleRaw.length) * 100).toFixed(0); + const appPct = ((1 - appMin.length / appRaw.length) * 100).toFixed(0); + const langPct = ((1 - langMin.length / langRaw.length) * 100).toFixed(0); + console.log(` CSS: ${styleName} (${(styleMin.length/1024).toFixed(1)} KB, -${stylePct}%)`); + console.log(` App: ${appName} (${(appMin.length/1024).toFixed(1)} KB, -${appPct}%)`); + console.log(` Lang: ${langName} (${(langMin.length/1024).toFixed(1)} KB, -${langPct}%)`); + + // ── 2. Clean stale minified output ── + for (const f of fs.readdirSync(wwwDir)) { + if (/\.min\.(css|js)$/.test(f) || /\.(css|js)$/.test(f)) { + const p = path.join(wwwDir, f); + if (fs.statSync(p).isFile()) fs.unlinkSync(p); + } + } + + // Write minified files + fs.writeFileSync(path.join(wwwDir, styleName), styleMin); + fs.writeFileSync(path.join(wwwDir, appName), appMin); + fs.writeFileSync(path.join(wwwDir, langName), langMin); + + // ── 3. Compile HTML templates ── const templatePath = path.join(websiteDir, 'template.html'); if (!fs.existsSync(templatePath)) { - console.error('Error: template.html not found! Run from website/ directory or repo root.'); + console.error('Error: template.html not found!'); process.exit(1); } const templateContent = fs.readFileSync(templatePath, 'utf8'); - const localesDir = path.join(websiteDir, 'locales'); const languages = ['en', 'de', 'fr', 'es', 'pt-BR', 'ru']; - // 3. Compile helper function + const englishHtml = {}; // track for join-page cross-ref + function compilePage(locale, assetPath, lang) { let compiled = templateContent; - - // Inject asset path prefix first compiled = compiled.replace(/\{\{ASSET_PATH\}\}/g, assetPath); - - // Inject selected state for the dropdown languages.forEach(l => { - const placeholder = `{{SELECTED_${l.toUpperCase()}}}`; - compiled = compiled.replace(new RegExp(placeholder, 'g'), l === lang ? 'selected' : ''); + compiled = compiled.replace(new RegExp(`\\{\\{SELECTED_${l.toUpperCase()}\\}\\}`, 'g'), l === lang ? 'selected' : ''); }); - - // Inject all translations - for (let [key, value] of Object.entries(locale)) { - const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g'); - compiled = compiled.replace(regex, value); + for (const [key, value] of Object.entries(locale)) { + compiled = compiled.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value); } - return compiled; } - // 4. Generate HTML files - for (let lang of languages) { + for (const lang of languages) { const localePath = path.join(localesDir, `${lang}.json`); - if (!fs.existsSync(localePath)) { - console.warn(`Warning: Locale file for ${lang} not found.`); - continue; - } + if (!fs.existsSync(localePath)) { console.warn(`Warning: Locale ${lang} not found.`); continue; } const locale = JSON.parse(fs.readFileSync(localePath, 'utf8')); if (lang === 'en') { - console.log('Compiling English version (index.html)...'); - const enHtml = compilePage(locale, '', lang); - fs.writeFileSync(path.join(wwwDir, 'index.html'), enHtml, 'utf8'); + console.log('Compiling English (index.html)...'); + const html = compilePage(locale, '', lang); + fs.writeFileSync(path.join(wwwDir, 'index.html'), html); + englishHtml[''] = html; } else { - console.log(`Compiling ${lang.toUpperCase()} version (${lang}/index.html)...`); + console.log(`Compiling ${lang.toUpperCase()} (${lang}/index.html)...`); const langDir = path.join(wwwDir, lang); fs.mkdirSync(langDir, { recursive: true }); - const langHtml = compilePage(locale, '../', lang); - fs.writeFileSync(path.join(langDir, 'index.html'), langHtml, 'utf8'); + const html = compilePage(locale, '../', lang); + fs.writeFileSync(path.join(langDir, 'index.html'), html); + englishHtml[lang] = html; } } - // 5. Clean stale minified output from previous builds - const staleGlobs = ['style.css', 'style.min.css', 'app.js', 'app.min.js', 'lang-init.js', 'lang-init.min.js']; - for (let f of staleGlobs) { - const p = path.join(wwwDir, f); - if (fs.existsSync(p)) fs.unlinkSync(p); + // ── 4. Copy static HTML files (join, impressum, datenschutz) ── + console.log('Copying static pages...'); + const staticHtml = ['join.html', 'impressum.html', 'datenschutz.html']; + for (const file of staticHtml) { + const src = path.join(websiteDir, file); + const dest = path.join(wwwDir, file); + if (fs.existsSync(src)) { fs.copyFileSync(src, dest); console.log(` Copied: ${file}`); } } - // 6. Copy static assets - console.log('Copying assets and static website files...'); - const staticFiles = [ - 'style.css', - 'app.js', - 'lang-init.js', - 'robots.txt', - 'sitemap.xml', - 'version.json', - 'join.html', - 'impressum.html', - 'datenschutz.html' - ]; - - for (let file of staticFiles) { - const srcPath = path.join(websiteDir, file); - // Rename .css → .min.css and .js → .min.js in output - const destName = file.endsWith('.css') ? file.replace(/\.css$/, '.min.css') - : file.endsWith('.js') ? file.replace(/\.js$/, '.min.js') - : file; - const destPath = path.join(wwwDir, destName); - if (fs.existsSync(srcPath)) { - if (file.endsWith('.css')) { - const raw = fs.readFileSync(srcPath, 'utf8'); - const minified = minifyCSS(raw); - fs.writeFileSync(destPath, minified, 'utf8'); - const saved = ((raw.length - minified.length) / raw.length * 100).toFixed(0); - console.log(`Minified: ${file} → ${destName} (-${saved}%)`); - } else if (file.endsWith('.js')) { - const raw = fs.readFileSync(srcPath, 'utf8'); - const minified = minifyJS(raw); - fs.writeFileSync(destPath, minified, 'utf8'); - const saved = ((raw.length - minified.length) / raw.length * 100).toFixed(0); - console.log(`Minified: ${file} → ${destName} (-${saved}%)`); - } else { - fs.copyFileSync(srcPath, destPath); - console.log(`Copied: ${file}`); - } - } else { - console.warn(`Warning: Static file ${file} not found.`); - } + // ── 5. Copy generic static files ── + const genericFiles = ['robots.txt', 'sitemap.xml', 'site.webmanifest', 'version.json']; + for (const file of genericFiles) { + const src = path.join(websiteDir, file); + const dest = path.join(wwwDir, file); + if (fs.existsSync(src)) { fs.copyFileSync(src, dest); } } - // Copy assets folder recursively + // ── 6. Copy assets ── + console.log('Copying assets...'); const srcAssets = path.join(websiteDir, 'assets'); const destAssets = path.join(wwwDir, 'assets'); if (fs.existsSync(srcAssets)) { copyDirSync(srcAssets, destAssets); - console.log('Copied assets directory recursively.'); - } else { - console.error('Error: assets/ directory not found in website/.'); + console.log(' Assets copied.'); } - console.log('KoalaSync compilation finished successfully! Output is in website/www/'); + // ── 7. Convert all WebP to AVIF (quality 70) ── + console.log('Converting WebP → AVIF...'); + let avifCount = 0; + const webpFiles = fs.readdirSync(destAssets).filter(f => f.endsWith('.webp')); + for (const f of webpFiles) { + const src = path.join(destAssets, f); + const stat = fs.statSync(src); + if (stat.size < MIN_AVIF_KB * 1024) continue; + const dest = path.join(destAssets, f.replace(/\.webp$/, '.avif')); + if (fs.existsSync(dest) && fs.statSync(dest).mtimeMs >= stat.mtimeMs) continue; + await sharp(src).avif({ quality: 70, speed: 6 }).toFile(dest); + avifCount++; + } + console.log(` ${avifCount} AVIF files generated.`); + + // ── 8. Post-process ALL HTML files ── + console.log('Post-processing HTML...'); + function walkHtml(dir, fn) { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const p = path.join(dir, entry.name); + if (entry.isDirectory()) { walkHtml(p, fn); } + else if (entry.name.endsWith('.html')) { fn(p); } + } + } + + walkHtml(wwwDir, (filePath) => { + let html = fs.readFileSync(filePath, 'utf8'); + + // 8a. Replace hashed asset refs + html = html.replace(/href="(?:\.\.\/)?style\.min\.css"/g, (m) => { + const prefix = m.includes('../') ? '../' : ''; + return `href="${prefix}${styleName}"`; + }); + html = html.replace(/src="(?:\.\.\/)?app\.min\.js"/g, (m) => { + const prefix = m.includes('../') ? '../' : ''; + return `src="${prefix}${appName}"`; + }); + html = html.replace(/src="(?:\.\.\/)?lang-init\.min\.js"/g, (m) => { + const prefix = m.includes('../') ? '../' : ''; + return `src="${prefix}${langName}"`; + }); + // Also update preload directives + html = html.replace(/href="(?:\.\.\/)?style\.min\.css"/g, (m) => { + const prefix = m.includes('../') ? '../' : ''; + return `href="${prefix}${styleName}"`; + }); + + // 8b. Inject AVIF wrappers + html = injectAvifPictures(html); + + // 8c. Minify inline SVGs + html = minifyInlineSvgs(html); + + fs.writeFileSync(filePath, html); + }); + + console.log('KoalaSync build finished successfully! Output: website/www/'); } -compile(); +compile().catch(err => { console.error('Build failed:', err); process.exit(1); }); diff --git a/website/datenschutz.html b/website/datenschutz.html index fcd0c72..7aa56b2 100644 --- a/website/datenschutz.html +++ b/website/datenschutz.html @@ -9,6 +9,17 @@ + + diff --git a/website/impressum.html b/website/impressum.html index dde294b..a0d89f2 100644 --- a/website/impressum.html +++ b/website/impressum.html @@ -9,6 +9,17 @@ + + diff --git a/website/locales/de.json b/website/locales/de.json index c1e6512..c135719 100644 --- a/website/locales/de.json +++ b/website/locales/de.json @@ -4,6 +4,7 @@ "CANONICAL_PATH": "de/", "LANG_TOGGLE_URL": "../", "LANG_TOGGLE_TEXT": "EN", + "OG_LOCALE": "de_DE", "META_TITLE": "KoalaSync | Netflix, YouTube & jedes Video mit Freunden synchronisieren", "META_DESCRIPTION": "Schaue Netflix, YouTube, Twitch und jedes HTML5-Video synchron mit Freunden. Kostenlose, quelloffene Browser-Erweiterung. Keine Anmeldung erforderlich.", diff --git a/website/locales/en.json b/website/locales/en.json index 6f47e0d..b5d7565 100644 --- a/website/locales/en.json +++ b/website/locales/en.json @@ -4,6 +4,7 @@ "CANONICAL_PATH": "", "LANG_TOGGLE_URL": "de/", "LANG_TOGGLE_TEXT": "DE", + "OG_LOCALE": "en_US", "META_TITLE": "KoalaSync | Sync Netflix, YouTube & Any Video with Friends", "META_DESCRIPTION": "Watch Netflix, YouTube, Twitch & any HTML5 video in perfect sync with friends. Free, open-source browser extension for Chrome and Firefox. No sign-up needed.", diff --git a/website/locales/es.json b/website/locales/es.json index 570dce3..37a358a 100644 --- a/website/locales/es.json +++ b/website/locales/es.json @@ -4,6 +4,7 @@ "CANONICAL_PATH": "es/", "LANG_TOGGLE_URL": "../", "LANG_TOGGLE_TEXT": "EN", + "OG_LOCALE": "es_ES", "META_TITLE": "KoalaSync | Sincroniza Netflix, YouTube y cualquier video con amigos", "META_DESCRIPTION": "Mira Netflix, YouTube, Twitch y cualquier video HTML5 en perfecta sincronización con amigos. Extensión de navegador gratuita y de código abierto. Sin registro.", diff --git a/website/locales/fr.json b/website/locales/fr.json index 08623ea..aaa3bcb 100644 --- a/website/locales/fr.json +++ b/website/locales/fr.json @@ -4,6 +4,7 @@ "CANONICAL_PATH": "fr/", "LANG_TOGGLE_URL": "../", "LANG_TOGGLE_TEXT": "EN", + "OG_LOCALE": "fr_FR", "META_TITLE": "KoalaSync | Synchronisez Netflix, YouTube et n'importe quelle vidéo avec vos amis", "META_DESCRIPTION": "Regardez Netflix, YouTube, Twitch et des vidéos HTML5 en synchro avec vos amis. Extension de navigateur gratuite et open-source. Aucune inscription requise.", diff --git a/website/locales/pt-BR.json b/website/locales/pt-BR.json index 7019a01..769c754 100644 --- a/website/locales/pt-BR.json +++ b/website/locales/pt-BR.json @@ -4,6 +4,7 @@ "CANONICAL_PATH": "pt-BR/", "LANG_TOGGLE_URL": "../", "LANG_TOGGLE_TEXT": "EN", + "OG_LOCALE": "pt_BR", "META_TITLE": "KoalaSync | Sincronize Netflix, YouTube e qualquer vídeo com amigos", "META_DESCRIPTION": "Assista Netflix, YouTube, Twitch e qualquer vídeo HTML5 em perfeita sincronia com amigos. Extensão de navegador gratuita e de código aberto. Sem registro.", diff --git a/website/locales/ru.json b/website/locales/ru.json index bf2206a..bab5bec 100644 --- a/website/locales/ru.json +++ b/website/locales/ru.json @@ -4,6 +4,7 @@ "CANONICAL_PATH": "ru/", "LANG_TOGGLE_URL": "../", "LANG_TOGGLE_TEXT": "EN", + "OG_LOCALE": "ru_RU", "META_TITLE": "KoalaSync | Синхронизация Netflix, YouTube и любого видео с друзьями", "META_DESCRIPTION": "Смотрите Netflix, YouTube, Twitch и любые HTML5-видео в синхронизации с друзьями. Бесплатное расширение браузера с открытым кодом. Регистрация не требуется.", diff --git a/website/site.webmanifest b/website/site.webmanifest new file mode 100644 index 0000000..d9af219 --- /dev/null +++ b/website/site.webmanifest @@ -0,0 +1,23 @@ +{ + "name": "KoalaSync", + "short_name": "KoalaSync", + "description": "Real-time video synchronization for friends. Privacy-first, open source.", + "start_url": "/", + "display": "standalone", + "background_color": "#0f172a", + "theme_color": "#0f172a", + "icons": [ + { + "src": "/assets/NewLogoIcon_64.webp", + "sizes": "64x64", + "type": "image/webp", + "purpose": "any" + }, + { + "src": "/assets/NewLogoIcon_128.webp", + "sizes": "128x128", + "type": "image/webp", + "purpose": "any maskable" + } + ] +} diff --git a/website/style.css b/website/style.css index 532fa76..a1d86b2 100644 --- a/website/style.css +++ b/website/style.css @@ -255,13 +255,12 @@ nav { border-radius: 12px; font-weight: 600; text-decoration: none; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1), color 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.3s cubic-bezier(0.4, 0, 0.2, 1); display: inline-flex; align-items: center; gap: 0.5rem; font-size: 0.95rem; } - .btn-primary { background: var(--accent); color: white; @@ -400,7 +399,7 @@ nav { padding: 8px 4px; cursor: pointer; border-radius: 8px; - transition: all 0.2s; + transition: color 0.2s, background-color 0.2s; text-align: center; } @@ -455,6 +454,15 @@ nav { margin-bottom: 0.4rem; } +.mock-section-label { + display: block; + font-size: 11px; + text-transform: uppercase; + color: var(--text-muted); + margin-bottom: 4px; + font-weight: 700; +} + .mock-input { background: #1e293b; border: 1px solid #334155; @@ -729,7 +737,7 @@ input:checked + .mock-slider:before { border-radius: 24px; border: 1px solid rgba(255, 255, 255, 0.08); box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.3s cubic-bezier(0.4, 0, 0.2, 1); position: relative; overflow: hidden; } @@ -769,7 +777,7 @@ input:checked + .mock-slider:before { color: var(--accent); border-radius: 12px; margin-right: 14px; - transition: all 0.3s ease; + transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease; } .feature-card:hover .feature-icon-svg { @@ -977,7 +985,7 @@ input:checked + .mock-slider:before { align-items: center; justify-content: center; box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.05); - transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1); + transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s cubic-bezier(0.16, 1, 0.3, 1); } .step-illustration-1:hover, .step-illustration-2:hover, .step-illustration-3:hover { @@ -1056,7 +1064,7 @@ input:checked + .mock-slider:before { display: flex; align-items: center; justify-content: center; - transition: all 0.3s; + transition: opacity 0.3s, box-shadow 0.3s; } .illus-extension-btn.active { @@ -1142,7 +1150,7 @@ input:checked + .mock-slider:before { background: rgba(255, 255, 255, 0.03); box-shadow: 0 2px 5px rgba(0,0,0,0.2); cursor: default; - transition: all 0.2s; + transition: opacity 0.2s, transform 0.2s; } .illus-store-btn img { @@ -1692,7 +1700,7 @@ input:checked + .mock-slider:before { padding: 0.35rem 0.75rem; border-radius: 6px; cursor: pointer; - transition: all 0.2s; + transition: color 0.2s, background-color 0.2s; } .terminal-tab-btn:hover { @@ -1751,7 +1759,7 @@ input:checked + .mock-slider:before { font-weight: 600; border-radius: 6px; cursor: pointer; - transition: all 0.2s; + transition: background-color 0.2s, color 0.2s, opacity 0.2s; display: flex; align-items: center; gap: 0.3rem; @@ -1779,7 +1787,7 @@ footer { [data-reveal] { opacity: 0; transform: translateY(30px); - transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1); + transition: opacity 0.8s cubic-bezier(0.4, 0, 0.2, 1), transform 0.8s cubic-bezier(0.4, 0, 0.2, 1); } [data-reveal].revealed { @@ -1902,7 +1910,7 @@ html:not(.lang-de) [lang="de"] { border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 9999px; padding: 6px 14px 6px 12px; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + transition: background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), color 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1); color: var(--text-muted); } @@ -2570,3 +2578,65 @@ html:not(.lang-de) [lang="de"] { box-shadow: 0 20px 25px -5px rgba(34, 197, 94, 0.4); } +/* --- Focus states for interactive cards --- */ +.feature-card:focus-visible, +.use-case-card:focus-visible, +.compat-logo:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 4px; + transform: translateY(-5px); +} +.feature-card, +.use-case-card, +.compat-logo { + scroll-margin-top: 100px; +} + +/* --- Skip-to-content accessibility link --- */ +.skip-link { + position: absolute; + left: -9999px; + top: 0; + background: var(--accent); + color: white; + padding: 0.75rem 1.25rem; + border-radius: 0 0 8px 0; + font-weight: 700; + z-index: 9999; + text-decoration: none; +} +.skip-link:focus { + left: 0; +} + +/* --- Reduced motion support --- */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } + .blob { animation: none; } + .join-status-pulse { animation: none; } + .status-ring.active-pulse { animation: none; } +} + +/* --- will-change hints for animated elements --- */ +.blob, +.join-status-pulse, +.status-ring.active-pulse, +.hero-mockup-wrapper, +.cta-group .btn { + will-change: transform, opacity; +} +@media (prefers-reduced-motion: reduce) { + .blob, + .join-status-pulse, + .status-ring.active-pulse, + .hero-mockup-wrapper, + .cta-group .btn { + will-change: auto; + } +} + diff --git a/website/template.html b/website/template.html index db1eb72..e58f722 100644 --- a/website/template.html +++ b/website/template.html @@ -26,8 +26,13 @@ - + + + + + + @@ -39,10 +44,33 @@ + + + - + - +
@@ -26,21 +37,21 @@
- + diff --git a/website/www/de/index.html b/website/www/de/index.html index 08f7166..dbd43cc 100644 --- a/website/www/de/index.html +++ b/website/www/de/index.html @@ -6,9 +6,9 @@ KoalaSync | Netflix, YouTube & jedes Video mit Freunden synchronisieren - + - + @@ -26,8 +26,13 @@ - + + + + + + @@ -39,10 +44,33 @@ + - + + + - + diff --git a/website/www/es/index.html b/website/www/es/index.html index 42e026f..dc8aea4 100644 --- a/website/www/es/index.html +++ b/website/www/es/index.html @@ -6,9 +6,9 @@ KoalaSync | Sincroniza Netflix, YouTube y cualquier video con amigos - + - + @@ -26,8 +26,13 @@ - + + + + + + @@ -39,10 +44,33 @@ + - + + + - + diff --git a/website/www/fr/index.html b/website/www/fr/index.html index 650d687..fbbf4c8 100644 --- a/website/www/fr/index.html +++ b/website/www/fr/index.html @@ -6,9 +6,9 @@ KoalaSync | Synchronisez Netflix, YouTube et n'importe quelle vidéo avec vos amis - + - + @@ -26,8 +26,13 @@ - + + + + + + @@ -39,10 +44,33 @@ + - + + + - + diff --git a/website/www/impressum.html b/website/www/impressum.html index dde294b..086afb5 100644 --- a/website/www/impressum.html +++ b/website/www/impressum.html @@ -4,17 +4,28 @@ Impressum / Legal Notice | KoalaSync - - + + + + - +
@@ -26,21 +37,21 @@
- + diff --git a/website/www/index.html b/website/www/index.html index 8c838a6..86c57be 100644 --- a/website/www/index.html +++ b/website/www/index.html @@ -6,9 +6,9 @@ KoalaSync | Sync Netflix, YouTube & Any Video with Friends - + - + @@ -27,7 +27,12 @@ + + + + + @@ -39,10 +44,33 @@ + - + + + - + diff --git a/website/www/join.html b/website/www/join.html index c6d0efb..cb8d206 100644 --- a/website/www/join.html +++ b/website/www/join.html @@ -4,8 +4,8 @@ Join Room | KoalaSync - - + + @@ -27,7 +27,7 @@ - +
@@ -39,21 +39,21 @@
- + diff --git a/website/www/lang-init.f4d146ef.min.js b/website/www/lang-init.f4d146ef.min.js new file mode 100644 index 0000000..237240d --- /dev/null +++ b/website/www/lang-init.f4d146ef.min.js @@ -0,0 +1 @@ +(function(){var l=document.documentElement,e=window.location.pathname,s={de:"de",fr:"fr",es:"es",pt:"pt-BR",ru:"ru"},v=e==="/"||e==="/index.html"||e==="";if(v){var o=localStorage.getItem("koala_lang"),i=navigator.language.split("-")[0],d=o||s[i]||"en";if(d!=="en"){window.location.replace(d+"/");return}}for(var r=l.className.split(" "),a=null,c=!1,t=0;tKoalaSync | Sincronize Netflix, YouTube e qualquer vídeo com amigos - + - + @@ -26,8 +26,13 @@ - + + + + + + @@ -39,10 +44,33 @@ + - + + + - + diff --git a/website/www/ru/index.html b/website/www/ru/index.html index a6f3af1..6497579 100644 --- a/website/www/ru/index.html +++ b/website/www/ru/index.html @@ -6,9 +6,9 @@ KoalaSync | Синхронизация Netflix, YouTube и любого видео с друзьями - + - + @@ -26,8 +26,13 @@ - + + + + + + @@ -39,10 +44,33 @@ + - + + + - + diff --git a/website/www/site.webmanifest b/website/www/site.webmanifest new file mode 100644 index 0000000..d9af219 --- /dev/null +++ b/website/www/site.webmanifest @@ -0,0 +1,23 @@ +{ + "name": "KoalaSync", + "short_name": "KoalaSync", + "description": "Real-time video synchronization for friends. Privacy-first, open source.", + "start_url": "/", + "display": "standalone", + "background_color": "#0f172a", + "theme_color": "#0f172a", + "icons": [ + { + "src": "/assets/NewLogoIcon_64.webp", + "sizes": "64x64", + "type": "image/webp", + "purpose": "any" + }, + { + "src": "/assets/NewLogoIcon_128.webp", + "sizes": "128x128", + "type": "image/webp", + "purpose": "any maskable" + } + ] +} diff --git a/website/www/style.62d39607.min.css b/website/www/style.62d39607.min.css new file mode 100644 index 0000000..7278ab6 --- /dev/null +++ b/website/www/style.62d39607.min.css @@ -0,0 +1 @@ +:root{--bg:#0f172a;--card:#1e293b;--accent:#6366f1;--accent-glow:rgba(99,102,241,0.3);--text:#f8fafc;--text-muted:#cbd5e1;--success:#22c55e;--glass:rgba(30,41,59,0.4);--glass-border:rgba(255,255,255,0.05)}.invite-banner{background:var(--accent);color:white;padding:0.75rem 0;text-align:center;font-weight:600;font-size:0.9rem;position:relative;z-index:2000;box-shadow:0 4px 12px rgba(0,0,0,0.3)}.btn-banner{background:white;color:var(--accent);padding:4px 12px;border-radius:6px;text-decoration:none;font-size:0.8rem;font-weight:700;margin-left:12px;cursor:pointer;border:none;transition:transform 0.2s}.btn-banner:hover{transform:scale(1.05)}*{margin:0;padding:0;box-sizing:border-box}:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:6px}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";background-color:var(--bg);color:var(--text);line-height:1.6;overflow-x:hidden;position:relative}.bg-blobs{position:fixed;top:0;left:0;width:100%;height:100%;z-index:-1;overflow:hidden;background:radial-gradient(circle at 50% 50%,#1e1b4b 0%,#0f172a 100%)}.blob{position:absolute;width:600px;height:600px;background:radial-gradient(circle,var(--accent-glow) 0%,transparent 70%);filter:blur(80px);border-radius:50%;opacity:0.5;animation:move 25s infinite alternate ease-in-out}.blob-1{top:-100px;left:-100px;animation-delay:0s}.blob-2{bottom:-100px;right:-100px;animation-delay:-5s;background:radial-gradient(circle,rgba(139,92,246,0.2) 0%,transparent 70%)}.blob-3{top:40%;left:30%;animation-duration:35s;animation-delay:-10s}@keyframes move{0%{transform:translate(0,0) scale(1)}33%{transform:translate(100px,100px) scale(1.2)}66%{transform:translate(-50px,200px) scale(0.8)}100%{transform:translate(0,0) scale(1)}}.container{max-width:1100px;margin:0 auto;padding:0 2rem}section{padding:6rem 0}.use-cases-section,#features,#self-hosting,.comparison-section{content-visibility:auto;contain-intrinsic-size:auto 1400px}nav{position:fixed;top:0;width:100%;z-index:1000;background:var(--glass);backdrop-filter:blur(12px);border-bottom:1px solid var(--glass-border);padding:1rem 0}.nav-content{display:flex;justify-content:space-between;align-items:center}.logo-area{display:flex;align-items:center;gap:0.75rem;font-weight:800;font-size:1.5rem;letter-spacing:-0.5px}.logo-area img{height:40px;width:40px}.nav-ext-status{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:rgba(16,185,129,0.15);border:1px solid rgba(16,185,129,0.3);color:#10b981;border-radius:12px;font-size:0.55rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;box-shadow:0 0 10px rgba(16,185,129,0.1);animation:fade-in 0.4s ease-out;margin-left:0.2rem}@keyframes fade-in{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.nav-links{display:flex;gap:2rem}.nav-links a{color:var(--text-muted);text-decoration:none;font-weight:500;transition:color 0.3s}.nav-links a:hover{color:var(--accent)}.hero{min-height:100vh;display:flex;align-items:center;padding-top:8rem;padding-bottom:4rem}.hero-grid{display:grid;grid-template-columns:1.2fr 1fr;align-items:center;gap:4rem;text-align:left;width:100%}.hero-text h1{font-size:4.5rem;font-weight:800;line-height:1.1;margin-bottom:1.5rem;background:linear-gradient(to bottom,#fff 40%,#6366f1);-webkit-background-clip:text;-webkit-text-fill-color:transparent}.hero-text p,.hero-subtitle{font-size:1.25rem;color:var(--text-muted);margin-bottom:2.5rem;max-width:600px;font-weight:400;line-height:1.6}.hero-mascot-container{display:block;margin-bottom:-0.5rem;margin-left:2.2rem}.hero-lookdown-mascot{display:block;width:90px;height:auto}@media (max-width:768px){.hero-mascot-container{margin-left:0;display:flex;justify-content:center}}.cta-group{display:flex;gap:1rem;flex-wrap:wrap}.btn{padding:0.85rem 1.75rem;border-radius:12px;font-weight:600;text-decoration:none;transition:transform 0.3s cubic-bezier(0.4,0,0.2,1),background-color 0.3s cubic-bezier(0.4,0,0.2,1),box-shadow 0.3s cubic-bezier(0.4,0,0.2,1),color 0.3s cubic-bezier(0.4,0,0.2,1),opacity 0.3s cubic-bezier(0.4,0,0.2,1),border-color 0.3s cubic-bezier(0.4,0,0.2,1);display:inline-flex;align-items:center;gap:0.5rem;font-size:0.95rem}.btn-primary{background:var(--accent);color:white;box-shadow:0 10px 15px -3px var(--accent-glow)}.btn-primary:hover{transform:translateY(-2px);box-shadow:0 20px 25px -5px var(--accent-glow)}.btn-firefox{background:#e66000;color:white;box-shadow:0 10px 15px -3px rgba(230,96,0,0.3)}.btn-firefox:hover{background:#ff7300;transform:translateY(-2px);box-shadow:0 20px 25px -5px rgba(230,96,0,0.4)}.btn-secondary{background:var(--card);color:var(--text);border:1px solid var(--glass-border)}.btn-secondary:hover{background:#2d3748;transform:translateY(-2px)}.version-badge{display:inline-block;background:rgba(99,102,241,0.1);color:var(--accent);padding:0.4rem 1rem;border-radius:99px;font-size:0.8rem;font-weight:700;margin-bottom:1.5rem;border:1px solid rgba(99,102,241,0.3);letter-spacing:0.05em;text-transform:uppercase}.hero-mockup-wrapper{display:flex;justify-content:center;align-items:center;width:100%}.extension-mockup{width:320px;height:520px;background:#0f172a;border-radius:20px;border:1px solid rgba(255,255,255,0.08);box-shadow:0 20px 40px rgba(0,0,0,0.4),0 0 20px rgba(99,102,241,0.15);display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;overflow:hidden;position:relative;user-select:none;padding:16px;padding-bottom:0;box-sizing:border-box}.mock-header-row{display:flex;align-items:center;margin-bottom:16px;flex-shrink:0}.mock-header-title{font-size:18px;margin:0;color:var(--accent);letter-spacing:1px;text-transform:uppercase;display:inline-flex;align-items:center;gap:8px;font-weight:800}.mock-header-title img{width:24px;height:24px;object-fit:contain;border-radius:4px}.mock-version-link{margin-left:auto;display:flex;align-items:center;gap:4px;font-size:10px;color:var(--text-muted);text-decoration:none;opacity:0.5;transition:opacity 0.2s,color 0.2s;cursor:pointer}.mock-version-link:hover{opacity:1;color:var(--accent)}.mock-tabs{display:flex;gap:4px;background:#1e293b;padding:4px;border-radius:12px;margin-bottom:20px;flex-shrink:0}.mock-tab{flex:1;background:none;border:none;color:var(--text-muted);font-size:0.75rem;font-weight:600;padding:8px 4px;cursor:pointer;border-radius:8px;transition:color 0.2s,background-color 0.2s;text-align:center}.mock-tab:hover{color:var(--text)}.mock-tab.active{background:var(--accent);color:white}.mock-body{flex:1;overflow-y:auto;padding:0;padding-bottom:16px;display:flex;flex-direction:column;font-size:0.8rem;scrollbar-width:none}.mock-body::-webkit-scrollbar{display:none}.mock-screen{display:none;flex-direction:column;gap:12px}.mock-screen.active{display:flex}.mock-card{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:12px}.mock-label{font-size:0.65rem;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:0.4rem}.mock-section-label{display:block;font-size:11px;text-transform:uppercase;color:var(--text-muted);margin-bottom:4px;font-weight:700}.mock-input{background:#1e293b;border:1px solid #334155;border-radius:8px;color:white;padding:8px 10px;font-size:0.75rem;width:100%;outline:none}.mock-btn{background:var(--accent);color:white;border:none;border-radius:6px;padding:0.5rem;font-weight:600;font-size:0.75rem;cursor:pointer;transition:background 0.2s;text-align:center}.mock-btn:hover{background:#4f46e5}.mock-joined-room{display:flex;justify-content:space-between;align-items:center;background:rgba(99,102,241,0.1);border:1px solid rgba(99,102,241,0.2);border-radius:8px;padding:0.6rem 0.75rem}.mock-room-name{font-weight:700;color:var(--accent);font-size:0.85rem}.mock-server-badge{background:rgba(99,102,241,0.2);color:var(--accent);font-size:0.6rem;font-weight:700;padding:2px 6px;border-radius:4px}.mock-invite-box{display:flex;gap:0.4rem}.mock-invite-box input{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mock-peer-list{display:flex;flex-direction:column;gap:0.5rem}.mock-peer-item{display:flex;flex-direction:column;background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.03);border-radius:8px;padding:0.5rem 0.6rem}.mock-peer-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:0.25rem}.mock-peer-name{font-weight:700;color:var(--text)}.mock-peer-meta{font-size:0.65rem;color:var(--text-muted)}.mock-peer-tab{font-size:0.7rem;color:var(--accent);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mock-peer-status{font-size:0.65rem;color:var(--text-muted);display:flex;align-items:center;gap:0.25rem}.mock-target-box{display:flex;align-items:center;gap:0.4rem;background:rgba(234,179,8,0.1);border:1px solid rgba(234,179,8,0.2);color:#facc15;padding:0.5rem 0.6rem;border-radius:8px;font-weight:600;font-size:0.7rem}.mock-ctrl-buttons{display:grid;grid-template-columns:1fr 1fr;gap:0.5rem}.mock-btn-play{background:#22c55e}.mock-btn-play:hover{background:#16a34a}.mock-btn-pause{background:#ef4444}.mock-btn-pause:hover{background:#dc2626}.mock-btn-force{background:var(--accent);grid-column:span 2}.mock-status-display{display:flex;align-items:center;justify-content:space-between}.mock-status-pill{display:inline-flex;align-items:center;gap:0.3rem;background:rgba(34,197,94,0.1);border:1px solid rgba(34,197,94,0.2);color:#22c55e;padding:2px 8px;border-radius:99px;font-size:0.65rem;font-weight:700}.mock-log-item{font-size:0.7rem;color:var(--text-muted);border-left:2px solid var(--accent);padding-left:0.4rem;margin-top:0.4rem}.mock-settings-row{display:flex;align-items:flex-start;gap:0.5rem;margin-bottom:0.6rem}.mock-settings-row input[type="checkbox"]{margin-top:0.2rem;cursor:pointer}.mock-settings-row label{cursor:pointer;font-weight:600}.mock-settings-row p{font-size:0.65rem;color:var(--text-muted);margin-top:0.1rem}.mock-toggle-switch{position:relative;display:inline-block;width:36px;height:20px;flex-shrink:0}.mock-toggle-switch input{opacity:0;width:0;height:0}.mock-slider{position:absolute;cursor:default;top:0;left:0;right:0;bottom:0;background-color:#334155;transition:.3s;border-radius:20px}.mock-slider:before{position:absolute;content:"";height:14px;width:14px;left:3px;bottom:3px;background-color:#94a3b8;transition:.3s;border-radius:50%}input:checked + .mock-slider{background-color:var(--accent)}input:checked + .mock-slider:before{transform:translateX(16px);background-color:white}.mock-diagnostic-grid{display:grid;grid-template-columns:1fr 1fr;gap:0.4rem}.mock-diag-box{background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.04);border-radius:6px;padding:0.4rem}.mock-diag-box .diag-val{font-family:monospace;font-weight:700;color:var(--accent);font-size:0.75rem}.features-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem;margin-top:4rem}.feature-card{background:rgba(30,41,59,0.45);backdrop-filter:blur(16px) saturate(120%);-webkit-backdrop-filter:blur(16px) saturate(120%);padding:2.5rem;border-radius:24px;border:1px solid rgba(255,255,255,0.08);box-shadow:0 8px 32px 0 rgba(0,0,0,0.3);transition:transform 0.3s cubic-bezier(0.4,0,0.2,1),box-shadow 0.3s cubic-bezier(0.4,0,0.2,1),border-color 0.3s cubic-bezier(0.4,0,0.2,1);position:relative;overflow:hidden}.feature-card::before{content:'';position:absolute;top:0;left:0;right:0;bottom:0;border-radius:24px;padding:1px;background:linear-gradient(to bottom right,rgba(255,255,255,0.12),transparent);-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none}.feature-card:hover{transform:translateY(-5px);box-shadow:0 15px 30px rgba(99,102,241,0.2);border-color:rgba(99,102,241,0.3)}.feature-card:hover::before{background:linear-gradient(to bottom right,rgba(99,102,241,0.3),transparent)}.feature-icon-svg{display:flex;flex-shrink:0;align-items:center;justify-content:center;width:44px;height:44px;background:rgba(99,102,241,0.12);color:var(--accent);border-radius:12px;margin-right:14px;transition:background 0.3s ease,color 0.3s ease,box-shadow 0.3s ease,transform 0.3s ease}.feature-card:hover .feature-icon-svg{background:var(--accent);color:white;box-shadow:0 0 15px var(--accent-glow);transform:scale(1.05)}.bento-icon{width:22px;height:22px;display:block;flex-shrink:0}.feature-card h3{margin-bottom:1rem;font-size:1.25rem;font-weight:700;display:flex;align-items:center}.feature-card p{color:var(--text-muted);font-size:0.95rem;line-height:1.6}.feature-card.bento-large{grid-column:span 2;background:linear-gradient(135deg,rgba(30,41,59,0.45) 0%,rgba(99,102,241,0.08) 100%);padding:3rem 3.5rem;display:grid;grid-template-columns:1fr 2fr;gap:3rem;align-items:center}.feature-card.bento-large h3{flex-direction:column;align-items:center;text-align:center;gap:1rem;margin-bottom:0;font-size:1.25rem}.feature-card.bento-large .feature-icon,.feature-card.bento-large .feature-icon-svg{width:52px;height:52px;border-radius:14px;margin-right:0;flex-shrink:0}.feature-card.bento-large .bento-icon{width:24px;height:24px}.feature-card.bento-large p{font-size:1rem;line-height:1.7;margin:0}.feature-card.bento-large::after{content:'';position:absolute;top:0;left:2.5rem;right:2.5rem;height:2px;background:linear-gradient(90deg,transparent,rgba(99,102,241,0.4),transparent);opacity:0;transition:opacity 0.3s ease}.feature-card.bento-large:hover::after{opacity:1}@media (max-width:900px){.features-grid{grid-template-columns:repeat(2,1fr);gap:1.25rem}.feature-card.bento-large{grid-column:span 2;padding:2.5rem;gap:2rem}.feature-card.bento-large h3{font-size:1.15rem}}@media (max-width:600px){.features-grid{grid-template-columns:1fr;gap:1rem}.feature-card.bento-large{grid-column:span 1;display:flex;flex-direction:column;padding:1.75rem;gap:1rem}.feature-card.bento-large h3{flex-direction:row;align-items:center;text-align:left;gap:0.75rem;margin-bottom:0;font-size:1.15rem}.feature-card.bento-large .feature-icon,.feature-card.bento-large .feature-icon-svg{width:40px;height:40px;border-radius:10px;margin-right:0}.feature-card.bento-large .bento-icon{width:18px;height:18px}.feature-card.bento-large p{font-size:0.9rem;line-height:1.6}.feature-card.bento-large::after{display:none}.feature-card{padding:1.75rem}.feature-card h3{font-size:1.1rem}.feature-icon-svg{width:40px;height:40px;border-radius:10px;margin-right:12px}.bento-icon{width:18px;height:18px}}.steps{display:flex;flex-direction:column;gap:6rem}.step{display:grid;grid-template-columns:1fr 1.1fr;gap:6rem;align-items:center}.step:nth-child(even) .step-text{order:2}.step-num{font-size:4rem;font-weight:800;color:rgba(99,102,241,0.15);line-height:1;margin-bottom:0.5rem}.step-text h3{font-size:1.85rem;margin-bottom:1rem;font-weight:800}.step-text p{color:var(--text-muted);font-size:1.05rem;line-height:1.6}.step-illustration-1,.step-illustration-2,.step-illustration-3{background:radial-gradient(circle at top left,#1e293b,#0f172a);height:280px;border-radius:24px;border:1px solid var(--glass-border);position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;box-shadow:0 20px 40px rgba(0,0,0,0.4),inset 0 1px 0 rgba(255,255,255,0.05);transition:transform 0.4s cubic-bezier(0.16,1,0.3,1),border-color 0.4s cubic-bezier(0.16,1,0.3,1),box-shadow 0.4s cubic-bezier(0.16,1,0.3,1)}.step-illustration-1:hover,.step-illustration-2:hover,.step-illustration-3:hover{transform:translateY(-6px) scale(1.02);border-color:rgba(99,102,241,0.25);box-shadow:0 25px 50px rgba(99,102,241,0.15),inset 0 1px 0 rgba(255,255,255,0.1)}.illus-browser-container{width:90%;height:80%;background:#090d16;border:1px solid rgba(255,255,255,0.05);border-radius:12px;overflow:hidden;box-shadow:0 15px 30px rgba(0,0,0,0.5);display:flex;flex-direction:column}.illus-browser-header{background:#131924;padding:0.6rem 0.8rem;display:flex;align-items:center;border-bottom:1px solid rgba(255,255,255,0.05)}.illus-browser-dots{display:flex;gap:6px;margin-right:1.5rem}.illus-browser-dot{width:8px;height:8px;border-radius:50%;opacity:0.6}.illus-browser-dot:nth-child(1){background:#ef4444}.illus-browser-dot:nth-child(2){background:#fbbf24}.illus-browser-dot:nth-child(3){background:#22c55e}.illus-browser-address-bar{background:#090d16;border:1px solid rgba(255,255,255,0.08);border-radius:6px;color:var(--text-muted);font-size:0.68rem;padding:3px 12px;flex-grow:1;max-width:60%;text-align:center;font-family:monospace;letter-spacing:0.2px}.illus-browser-address-bar .url-protocol{color:#22c55e;font-weight:600}.illus-browser-toolbar{display:flex;margin-left:auto}.illus-extension-btn{width:22px;height:22px;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:opacity 0.3s,box-shadow 0.3s}.illus-extension-btn.active{background:rgba(99,102,241,0.2);border:1px solid var(--accent);box-shadow:0 0 10px rgba(99,102,241,0.4);animation:active-pulse 2s infinite alternate}@keyframes active-pulse{0%{transform:scale(1);box-shadow:0 0 5px rgba(99,102,241,0.4)}100%{transform:scale(1.08);box-shadow:0 0 12px rgba(99,102,241,0.7)}}.illus-browser-content{flex-grow:1;padding:1rem;position:relative;display:flex;align-items:flex-start}.illus-store-card{background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.04);border-radius:12px;padding:0.8rem;width:65%;display:flex;flex-direction:column;gap:10px}.illus-store-card-header{display:flex;align-items:center;gap:8px}.illus-large-logo{width:30px;height:30px;object-fit:contain;border-radius:6px;box-shadow:0 0 10px rgba(99,102,241,0.2)}.illus-store-info{display:flex;flex-direction:column}.illus-store-title{font-size:0.88rem;font-weight:800;color:var(--text);line-height:1.1}.illus-store-desc{font-size:0.58rem;color:var(--text-muted);line-height:1.2;margin-top:2px}.illus-store-buttons{display:flex;flex-direction:column;gap:6px}.illus-store-btn{display:inline-flex;align-items:center;gap:6px;padding:5px 8px;border-radius:8px;font-size:0.58rem;font-weight:700;color:white;border:1px solid rgba(255,255,255,0.05);background:rgba(255,255,255,0.03);box-shadow:0 2px 5px rgba(0,0,0,0.2);cursor:default;transition:opacity 0.2s,transform 0.2s}.illus-store-btn img{width:11px;height:11px;display:block}.illus-store-btn.chrome{border-color:rgba(99,102,241,0.25);background:rgba(99,102,241,0.08);box-shadow:0 0 10px rgba(99,102,241,0.05)}.illus-store-btn.firefox{border-color:rgba(249,115,22,0.25);background:rgba(249,115,22,0.08);box-shadow:0 0 10px rgba(249,115,22,0.05)}.install-breathe{animation:install-breathe 2.5s ease-in-out infinite;z-index:2;position:relative}@keyframes install-breathe{0%,100%{transform:scale(1);box-shadow:0 0 15px rgba(99,102,241,0.2)}50%{transform:scale(1.05);box-shadow:0 0 25px rgba(99,102,241,0.5)}}.install-breathe.firefox,.btn-firefox.install-breathe{animation-name:install-breathe-ff}@keyframes install-breathe-ff{0%,100%{transform:scale(1);box-shadow:0 0 15px rgba(249,115,22,0.2)}50%{transform:scale(1.05);box-shadow:0 0 25px rgba(249,115,22,0.5)}}.illus-extension-popup{position:absolute;top:0.6rem;right:0.6rem;width:145px;background:rgba(30,41,59,0.75);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,0.12);border-radius:12px;padding:0.6rem 0.8rem;box-shadow:0 10px 25px rgba(0,0,0,0.5),inset 0 1px 0 rgba(255,255,255,0.1);animation:popup-float 4s ease-in-out infinite;z-index:5}@keyframes popup-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}.illus-extension-popup .popup-title{display:flex;align-items:center;gap:5px;font-size:0.72rem;font-weight:700;color:var(--text);margin-bottom:6px;border-bottom:1px solid rgba(255,255,255,0.08);padding-bottom:4px}.illus-extension-popup .popup-title img{width:12px;height:12px}.illus-extension-popup .popup-status{margin-bottom:4px}.status-badge-success{background:rgba(34,197,94,0.12);color:#22c55e;font-size:0.6rem;font-weight:700;padding:2px 6px;border-radius:4px;border:1px solid rgba(34,197,94,0.2);display:inline-flex;align-items:center;gap:3px;animation:status-glow 2s infinite alternate}@keyframes status-glow{0%{box-shadow:0 0 0 rgba(34,197,94,0)}100%{box-shadow:0 0 6px rgba(34,197,94,0.3)}}.illus-extension-popup .popup-quick-start{font-size:0.55rem;color:var(--text-muted);font-weight:500;line-height:1.2}.illus-popup-card{width:220px;background:rgba(30,41,59,0.75);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.08);border-radius:16px;padding:0.95rem;box-shadow:0 15px 35px rgba(0,0,0,0.5),inset 0 1px 0 rgba(255,255,255,0.1);display:flex;flex-direction:column;gap:0.75rem;animation:popup-float 4s ease-in-out infinite;animation-delay:-1s}.illus-popup-header{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid rgba(255,255,255,0.06);padding-bottom:8px}.illus-popup-brand{display:flex;align-items:center;gap:6px;font-size:0.82rem;font-weight:800;letter-spacing:-0.2px}.illus-popup-version{font-size:0.58rem;color:var(--text-muted)}.illus-popup-tabs{display:flex;gap:4px;background:rgba(9,13,22,0.4);padding:3px;border-radius:8px;border:1px solid rgba(255,255,255,0.03)}.illus-popup-tab{flex:1;text-align:center;font-size:0.62rem;padding:4px 0;border-radius:6px;color:var(--text-muted);font-weight:600}.illus-popup-tab.active{background:var(--card);color:var(--accent);box-shadow:0 2px 5px rgba(0,0,0,0.2)}.illus-popup-body{display:flex;flex-direction:column;gap:0.75rem;position:relative}.illus-popup-btn{background:linear-gradient(135deg,var(--accent),#8b5cf6);border-radius:8px;padding:9px;color:white;font-weight:700;font-size:0.7rem;text-align:center;box-shadow:0 4px 12px rgba(99,102,241,0.3);position:relative;overflow:hidden;cursor:default;animation:create-btn-pulse 2s infinite alternate}@keyframes create-btn-pulse{0%{transform:scale(1);box-shadow:0 4px 12px rgba(99,102,241,0.3)}100%{transform:scale(1.03);box-shadow:0 6px 16px rgba(99,102,241,0.5)}}.illus-btn-shine{position:absolute;top:0;left:-100%;width:50%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.25),transparent);transform:skewX(-20deg);animation:shimmer-sweep 3s infinite ease-in-out}@keyframes shimmer-sweep{0%{left:-100%}50%,100%{left:150%}}.illus-collapsed-details{background:rgba(9,13,22,0.4);border:1px solid rgba(255,255,255,0.05);border-radius:8px;padding:7px 12px;font-size:0.56rem;color:var(--text-muted);font-weight:700;text-transform:uppercase;display:flex;align-items:center;gap:6px;letter-spacing:0.2px}.details-arrow{font-size:0.48rem;color:var(--text-muted);opacity:0.7}.illus-floating-success{position:absolute;bottom:-1.2rem;left:50%;transform:translateX(-50%);background:rgba(9,13,22,0.9);border:1px solid rgba(34,197,94,0.3);border-radius:20px;padding:3px 10px;display:flex;align-items:center;gap:4px;box-shadow:0 4px 10px rgba(0,0,0,0.4);animation:floating-success-fade 5s infinite;white-space:nowrap;z-index:10}@keyframes floating-success-fade{0%,100%,75%{opacity:0;transform:translate(-50%,5px) scale(0.9)}15%,60%{opacity:1;transform:translate(-50%,0) scale(1)}}.illus-floating-success .success-icon{font-size:0.65rem}.illus-floating-success span[lang]{font-size:0.58rem;color:#22c55e;font-weight:700}.illus-sync-theater{width:95%;display:flex;align-items:center;justify-content:center;position:relative;gap:0.6rem}.illus-player-card{width:145px;background:rgba(15,23,42,0.7);border:1px solid rgba(255,255,255,0.05);border-radius:12px;padding:6px;box-shadow:0 10px 25px rgba(0,0,0,0.4);display:flex;flex-direction:column;gap:4px;position:relative;z-index:2}.illus-player-card.player-a{animation:popup-float 4s ease-in-out infinite;animation-delay:-2s}.illus-player-card.player-b{animation:popup-float 4s ease-in-out infinite;animation-delay:-3s}.player-header{display:flex;justify-content:space-between;align-items:center;font-size:0.55rem}.player-user{font-weight:700;color:var(--text)}.player-badge{font-size:0.42rem;font-weight:800;padding:1px 3px;border-radius:3px}.player-badge.active{background:rgba(34,197,94,0.15);color:#22c55e;border:1px solid rgba(34,197,94,0.25)}.player-video-canvas{height:70px;border-radius:8px;background:linear-gradient(135deg,#1e1b4b,#311042);position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255,255,255,0.02)}.player-video-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:radial-gradient(circle at center,rgba(139,92,246,0.1) 0%,transparent 80%)}.player-play-pulse{width:24px;height:24px;border-radius:50%;background:rgba(99,102,241,0.85);color:white;font-size:0.65rem;display:flex;align-items:center;justify-content:center;box-shadow:0 0 10px rgba(99,102,241,0.5);z-index:3;animation:play-pulse 2s infinite alternate}@keyframes play-pulse{0%{transform:scale(1);box-shadow:0 0 6px rgba(99,102,241,0.4)}100%{transform:scale(1.15);box-shadow:0 0 15px rgba(99,102,241,0.8)}}.player-controls{display:flex;align-items:center;gap:4px;padding:2px 2px 0 2px}.control-btn{font-size:0.58rem;color:var(--accent)}.player-timeline{flex-grow:1;height:3px;background:rgba(255,255,255,0.1);border-radius:2px;position:relative}.timeline-fill{position:absolute;top:0;left:0;height:100%;background:var(--accent);border-radius:2px;width:60%;animation:theater-grow 6s infinite linear}.timeline-knob{position:absolute;top:-2px;left:60%;width:7px;height:7px;border-radius:50%;background:white;box-shadow:0 0 4px rgba(0,0,0,0.5);transform:translateX(-50%);animation:theater-knob-grow 6s infinite linear}@keyframes theater-grow{0%{width:0%}100%{width:100%}}@keyframes theater-knob-grow{0%{left:0%}100%{left:100%}}.control-time{font-size:0.5rem;color:var(--text-muted);font-family:monospace}.illus-sync-bridge{flex-grow:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;position:relative;z-index:1}.illus-sync-bridge .sync-line{width:100%;height:2px;background:rgba(255,255,255,0.06);position:relative;overflow:hidden}.illus-sync-bridge .sync-beam{position:absolute;top:0;left:-100%;width:50px;height:100%;background:linear-gradient(90deg,transparent,var(--accent),var(--success),transparent);animation:sync-flow 2.5s infinite linear}@keyframes sync-flow{0%{left:-100%}100%{left:100%}}.sync-status-badge{background:rgba(34,197,94,0.12);border:1px solid rgba(34,197,94,0.25);color:#22c55e;font-size:0.5rem;font-weight:800;letter-spacing:0.5px;padding:2px 6px;border-radius:6px;white-space:nowrap;animation:active-pulse-green 2s infinite alternate}@keyframes active-pulse-green{0%{box-shadow:0 0 3px rgba(34,197,94,0.1)}100%{box-shadow:0 0 8px rgba(34,197,94,0.4)}}.terminal-container{max-width:850px;margin:3rem auto 0 auto;background:#0f172a;border:1px solid rgba(255,255,255,0.08);border-radius:16px;overflow:hidden;box-shadow:0 20px 45px rgba(0,0,0,0.5);text-align:left}.terminal-header{background:#1e293b;padding:0.85rem 1.25rem;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid rgba(255,255,255,0.06)}.terminal-dots{display:flex;gap:6px}.terminal-dot{width:10px;height:10px;border-radius:50%}.terminal-dot.red{background:#ef4444}.terminal-dot.yellow{background:#f59e0b}.terminal-dot.green{background:#10b981}.terminal-tabs{display:flex;gap:0.5rem}.terminal-tab-btn{background:none;border:none;color:var(--text-muted);font-weight:600;font-size:0.8rem;padding:0.35rem 0.75rem;border-radius:6px;cursor:pointer;transition:color 0.2s,background-color 0.2s}.terminal-tab-btn:hover{color:var(--text);background:rgba(255,255,255,0.03)}.terminal-tab-btn.active{color:var(--accent);background:rgba(99,102,241,0.1);border:1px solid rgba(99,102,241,0.2)}.terminal-body{position:relative;padding:1.5rem}.terminal-pane{display:none;margin:0}.terminal-pane.active{display:block}.terminal-pane pre{margin:0;overflow-x:auto}.terminal-pane code{font-family:Consolas,Monaco,"Andale Mono","Ubuntu Mono",monospace;font-size:0.85rem;line-height:1.6;color:#e2e8f0}.t-comment{color:#64748b;font-style:italic}.t-key{color:#f472b6}.t-val{color:#38bdf8}.t-str{color:#34d399}.t-num{color:#fbbf24}.terminal-copy-btn{position:absolute;top:1rem;right:1.5rem;background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.08);color:var(--text-muted);padding:0.35rem 0.75rem;font-size:0.75rem;font-weight:600;border-radius:6px;cursor:pointer;transition:background-color 0.2s,color 0.2s,opacity 0.2s;display:flex;align-items:center;gap:0.3rem}.terminal-copy-btn:hover{background:rgba(255,255,255,0.08);color:var(--text);border-color:rgba(255,255,255,0.15)}.terminal-copy-btn:active{transform:scale(0.97)}footer{padding:4rem 0;border-top:1px solid var(--glass-border);text-align:center;color:var(--text-muted)}[data-reveal]{opacity:0;transform:translateY(30px);transition:opacity 0.8s cubic-bezier(0.4,0,0.2,1),transform 0.8s cubic-bezier(0.4,0,0.2,1)}[data-reveal].revealed{opacity:1;transform:translateY(0)}.legal-content{max-width:800px;margin:8rem auto 4rem auto;padding:0 2rem}.legal-card{background:var(--card);padding:3rem;border-radius:24px;border:1px solid var(--glass-border)}.legal-card h1{font-size:2.5rem;margin-bottom:2rem;text-align:center}.legal-card h2{font-size:1.25rem;margin-top:1rem;margin-bottom:0.5rem;color:var(--accent)}.legal-card p{color:var(--text-muted);margin-bottom:0.5rem;font-size:0.95rem}.legal-card section{padding:0 !important;margin-bottom:0.75rem}.join-card{max-width:450px;margin:6rem auto;text-align:center}.room-badge{display:inline-block;background:rgba(99,102,241,0.1);color:var(--accent);padding:0.5rem 1rem;border-radius:99px;font-size:0.8rem;font-weight:700;margin-bottom:1rem;border:1px solid rgba(99,102,241,0.2)}@media (max-width:768px){.hero-grid,.step{grid-template-columns:1fr;text-align:center}.hero-text h1{font-size:2.5rem}.cta-group{justify-content:center;flex-wrap:wrap}.nav-links{display:none;position:absolute;top:100%;left:0;right:0;flex-direction:column;background:rgba(15,23,42,0.95);backdrop-filter:blur(12px);padding:1rem 2rem;gap:1rem;border-bottom:1px solid var(--glass-border)}.nav-links.open{display:flex}.hamburger{display:flex}.legal-card{padding:1.5rem}}html.lang-de [lang="en"]{display:none !important}html:not(.lang-de) [lang="de"]{display:none !important}.lang-select-container{position:relative;display:inline-flex;align-items:center;gap:8px;background:rgba(30,41,59,0.4);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.08);border-radius:9999px;padding:6px 14px 6px 12px;transition:background-color 0.3s cubic-bezier(0.4,0,0.2,1),border-color 0.3s cubic-bezier(0.4,0,0.2,1),color 0.3s cubic-bezier(0.4,0,0.2,1),box-shadow 0.3s cubic-bezier(0.4,0,0.2,1);color:var(--text-muted)}.lang-select-container:hover{background:rgba(30,41,59,0.6);border-color:rgba(99,102,241,0.3);color:var(--text);box-shadow:0 0 15px rgba(99,102,241,0.1)}.lang-select-container .globe-icon{width:16px;height:16px;flex-shrink:0;opacity:0.8;transition:transform 0.5s ease}.lang-select-container:hover .globe-icon{transform:rotate(15deg);opacity:1}.lang-select-container .chevron-icon{width:12px;height:12px;flex-shrink:0;pointer-events:none;opacity:0.6;margin-left:-2px}.lang-select-container:hover .chevron-icon{opacity:1}.lang-dropdown{appearance:none;-webkit-appearance:none;-moz-appearance:none;background:transparent;border:none;outline:none;font-family:inherit;font-size:0.8rem;font-weight:600;color:currentColor;cursor:pointer;padding:0 12px 0 0;margin:0;width:auto}.lang-dropdown option{background:#0f172a;color:white;font-family:inherit;font-size:0.9rem}.hamburger{display:none;align-items:center;justify-content:center;background:none;border:none;color:var(--text);font-size:1.5rem;cursor:pointer;padding:0.25rem;line-height:1}.feature-card:nth-child(1){--card-accent:rgba(99,102,241,0.06)}.feature-card:nth-child(2){--card-accent:rgba(139,92,246,0.06)}.feature-card:nth-child(3){--card-accent:rgba(34,197,94,0.06)}.feature-card:nth-child(4){--card-accent:rgba(56,189,248,0.06)}.feature-card:nth-child(5){--card-accent:rgba(245,158,11,0.06)}.feature-card:nth-child(6){--card-accent:rgba(236,72,153,0.06)}.feature-card{background:linear-gradient(135deg,var(--card-accent,transparent),var(--card))}.compat-section{padding:1rem 0 3.5rem 0;text-align:center;background:rgba(255,255,255,0.01);border-bottom:1px solid var(--glass-border)}.compat-mascot{display:block;margin:0 auto 0.5rem auto;max-width:368px;width:100%;height:auto;transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.compat-mascot:hover{transform:scale(1.05) translateY(-5px) rotate(1deg)}.compat-heading{font-size:1rem;font-weight:600;color:var(--text-muted);letter-spacing:0.08em;text-transform:uppercase;margin-bottom:2rem}.compat-row{display:flex;justify-content:center;align-items:center;gap:3rem;flex-wrap:wrap}.compat-logo{display:flex;flex-direction:column;align-items:center;gap:0.5rem;font-size:0.75rem;font-weight:700;color:var(--text-muted);transition:opacity 0.3s;opacity:0.55}.compat-logo:hover{opacity:0.85}.compat-logo img{width:28px;height:28px;display:block}.compat-more{opacity:0.4;cursor:help;flex-direction:row;gap:0.35rem;position:relative}.compat-more:hover{opacity:0.6}.compat-more-icon{font-size:1.1rem;font-weight:700;color:var(--accent);line-height:1}.compat-tooltip{display:none;position:absolute;bottom:calc(100% + 10px);left:50%;transform:translateX(-50%);background:var(--card);color:var(--text-muted);padding:0.6rem 0.9rem;border-radius:8px;font-size:0.72rem;font-weight:500;white-space:nowrap;border:1px solid var(--glass-border);box-shadow:0 8px 20px rgba(0,0,0,0.4);z-index:10;line-height:1.4}.compat-tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:var(--glass-border)}.compat-more:hover .compat-tooltip{display:block}.join-spinner{width:36px;height:36px;border:3px solid rgba(99,102,241,0.2);border-top-color:var(--accent);border-radius:50%;animation:spin 0.8s linear infinite;margin:0 auto 0.75rem}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important}[data-reveal]{opacity:1;transform:none}.blob{animation:none}.illus-typing-text::after{animation:none}.illus-timeline-progress{animation:none;width:60%}.illus-sync-pulse{animation:none}.illus-extension-icon{animation:none}}.use-cases-section{padding:6rem 0;position:relative;border-bottom:1px solid var(--glass-border)}.use-cases-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:2rem;margin-top:1rem}.use-case-card{background:rgba(30,41,59,0.4);border:1px solid var(--glass-border);border-radius:16px;padding:1.2rem 1.6rem 1.7rem 1.6rem;text-align:left;transition:transform 0.3s cubic-bezier(0.16,1,0.3,1),box-shadow 0.3s ease;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:flex;flex-direction:column;gap:0.8rem;position:relative;overflow:hidden}.use-case-card::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,transparent,var(--card-accent-border,var(--accent)),transparent);opacity:0;transition:opacity 0.3s ease}.use-case-card:nth-child(1){--card-accent-border:#f59e0b}.use-case-card:nth-child(2){--card-accent-border:#38bdf8}.use-case-card:nth-child(3){--card-accent-border:#ec4899}.use-case-card:hover{transform:translateY(-5px);box-shadow:0 12px 30px rgba(0,0,0,0.35);border-color:rgba(255,255,255,0.15)}.use-case-card:hover::before{opacity:1}.use-case-image{display:block;width:100%;max-width:272px;height:150px;object-fit:contain;border-radius:8px;margin:0 auto 0 auto}.cta-github-mascot{display:block;width:100%;max-width:250px;height:auto;margin:1.5rem auto}.features-questions-mascot{display:block;width:100%;max-width:250px;height:auto;margin:-1.5rem auto 0.2rem auto;transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.features-questions-mascot:hover{transform:scale(1.05) translateY(-4px) rotate(-1.5deg)}.comparison-mascot{display:block;width:100%;max-width:260px;height:auto;margin:-2.2rem auto 0.2rem auto;transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.comparison-mascot:hover{transform:scale(1.05) translateY(-4px) rotate(1deg)}.use-case-icon{font-size:1.6rem;margin-right:0.6rem;display:inline-block;vertical-align:middle;filter:drop-shadow(0 2px 8px rgba(0,0,0,0.2))}.use-case-card h3{font-size:1.25rem;font-weight:700;margin:0;color:white}.use-case-card p{font-size:0.9rem;line-height:1.6;color:var(--text-muted);margin:0}.comparison-section{padding:6rem 0;background:rgba(255,255,255,0.01);border-bottom:1px solid var(--glass-border)}.comparison-table-wrapper{overflow-x:auto;background:rgba(30,41,59,0.35);border:1px solid var(--glass-border);border-radius:16px;box-shadow:0 10px 30px rgba(0,0,0,0.2);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);margin-top:1rem}.comparison-table{width:100%;border-collapse:collapse;text-align:left;font-size:0.95rem}.comparison-table th,.comparison-table td{padding:1.25rem 1.5rem;border-bottom:1px solid rgba(255,255,255,0.06)}.comparison-table th{background:rgba(15,23,42,0.6);font-weight:700;color:white;text-transform:uppercase;font-size:0.8rem;letter-spacing:0.08em}.comparison-table th.highlight,.comparison-table td.highlight{background:rgba(99,102,241,0.08)}.comparison-table tbody tr:hover{background:rgba(255,255,255,0.02)}.comparison-table tbody tr:last-child td{border-bottom:none}.feat-name{display:flex;flex-direction:column;gap:0.25rem}.feat-name strong{color:white;font-weight:600}.feat-desc{font-size:0.8rem;color:var(--text-muted)}.check{color:#22c55e;font-weight:700}.cross{color:#ef4444;font-weight:500;opacity:0.8}@media (max-width:768px){.comparison-table th,.comparison-table td{padding:1rem;font-size:0.85rem}.feat-desc{display:none}}.source-link{color:var(--accent);text-decoration:none;font-size:0.72rem;font-weight:700;margin-left:0.25rem;display:inline-flex;align-items:center;vertical-align:super;opacity:0.6;transition:opacity 0.2s ease,color 0.2s ease,transform 0.2s ease}.source-link:hover{opacity:1;color:#38bdf8;transform:translateY(-1px)}.table-footnotes{padding:0.8rem 1.25rem;background:rgba(15,23,42,0.45);border-top:1px solid rgba(255,255,255,0.05);font-size:0.72rem;color:var(--text-muted);line-height:1.5;opacity:0.65;transition:opacity 0.2s ease}.table-footnotes:hover{opacity:0.95}.table-footnotes p{margin:0;display:flex;align-items:baseline;gap:0.4rem}.table-footnotes p:not(:last-child){margin-bottom:0.4rem}.table-footnotes a{color:var(--accent);text-decoration:none;font-weight:500;transition:color 0.2s ease,text-decoration 0.2s ease}.table-footnotes a:hover{color:#38bdf8;text-decoration:underline}.table-footnotes sup{font-weight:700;color:var(--accent)}@media (max-width:768px){.table-footnotes{padding:0.75rem 1rem;font-size:0.68rem}}.join-status-visual{margin-bottom:2rem;position:relative;height:200px;display:flex;align-items:center;justify-content:center}.join-status-mascot{display:block;width:140px;height:auto;z-index:2;filter:drop-shadow(0 4px 12px rgba(0,0,0,0.15))}.join-status-mascot.searching-mascot{width:175px}.join-status-pulse{animation:mascot-gentle-pulse 2s ease-in-out infinite}@keyframes mascot-gentle-pulse{0%{transform:scale(0.96);filter:drop-shadow(0 4px 10px rgba(99,102,241,0.15))}50%{transform:scale(1.04);filter:drop-shadow(0 8px 20px rgba(99,102,241,0.35))}100%{transform:scale(0.96);filter:drop-shadow(0 4px 10px rgba(99,102,241,0.15))}}.legal-mascot{display:block;width:180px;height:auto;margin:-0.75rem auto 0.4rem auto;filter:drop-shadow(0 4px 12px rgba(0,0,0,0.15));transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.legal-mascot:hover{transform:scale(1.06) translateY(-4px) rotate(1.5deg)}.selfhost-mascot{display:block;width:300px;height:auto;margin:0 auto;filter:drop-shadow(0 4px 12px rgba(0,0,0,0.15));transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.selfhost-mascot:hover{transform:scale(1.05) translateY(-4px) rotate(-1deg)}.status-ring{position:absolute;width:90px;height:90px;border-radius:50%;background:rgba(99,102,241,0.05);border:2px dashed rgba(99,102,241,0.25);z-index:1}.status-ring.active-pulse{animation:radar-pulse 3s cubic-bezier(0.25,0.8,0.25,1) infinite}@keyframes radar-pulse{0%{transform:scale(0.85);opacity:0.9;border-color:rgba(99,102,241,0.3);box-shadow:0 0 0 0px rgba(99,102,241,0.15)}50%{transform:scale(1.18);opacity:0.35;border-color:rgba(56,189,248,0.2);box-shadow:0 0 0 15px rgba(56,189,248,0)}100%{transform:scale(0.85);opacity:0.9;border-color:rgba(99,102,241,0.3);box-shadow:0 0 0 0px rgba(99,102,241,0.15)}}.join-card-actions{display:flex;flex-direction:column;gap:0.75rem;width:100%}.join-card-actions .btn{width:100%;justify-content:center;padding:1.1rem;font-size:0.88rem;font-weight:700;letter-spacing:0.04em;text-transform:uppercase}.join-card-actions .btn svg{margin-right:0.3rem;flex-shrink:0}.join-card-actions .btn img{margin-right:0.3rem;flex-shrink:0}.btn-success{background:#22c55e;color:white !important;box-shadow:0 10px 15px -3px rgba(34,197,94,0.3)}.btn-success:hover{background:#16a34a;transform:translateY(-2px);box-shadow:0 20px 25px -5px rgba(34,197,94,0.4)}.feature-card:focus-visible,.use-case-card:focus-visible,.compat-logo:focus-visible{outline:2px solid var(--accent);outline-offset:4px;transform:translateY(-5px)}.feature-card,.use-case-card,.compat-logo{scroll-margin-top:100px}.skip-link{position:absolute;left:-9999px;top:0;background:var(--accent);color:white;padding:0.75rem 1.25rem;border-radius:0 0 8px 0;font-weight:700;z-index:9999;text-decoration:none}.skip-link:focus{left:0}@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important;scroll-behavior:auto !important}.blob{animation:none}.join-status-pulse{animation:none}.status-ring.active-pulse{animation:none}}.blob,.join-status-pulse,.status-ring.active-pulse,.hero-mockup-wrapper,.cta-group .btn{will-change:transform,opacity}@media (prefers-reduced-motion:reduce){.blob,.join-status-pulse,.status-ring.active-pulse,.hero-mockup-wrapper,.cta-group .btn{will-change:auto}} \ No newline at end of file diff --git a/website/www/style.min.css b/website/www/style.min.css deleted file mode 100644 index 861229d..0000000 --- a/website/www/style.min.css +++ /dev/null @@ -1 +0,0 @@ -:root{--bg:#0f172a;--card:#1e293b;--accent:#6366f1;--accent-glow:rgba(99,102,241,0.3);--text:#f8fafc;--text-muted:#cbd5e1;--success:#22c55e;--glass:rgba(30,41,59,0.4);--glass-border:rgba(255,255,255,0.05)}.invite-banner{background:var(--accent);color:white;padding:0.75rem 0;text-align:center;font-weight:600;font-size:0.9rem;position:relative;z-index:2000;box-shadow:0 4px 12px rgba(0,0,0,0.3)}.btn-banner{background:white;color:var(--accent);padding:4px 12px;border-radius:6px;text-decoration:none;font-size:0.8rem;font-weight:700;margin-left:12px;cursor:pointer;border:none;transition:transform 0.2s}.btn-banner:hover{transform:scale(1.05)}*{margin:0;padding:0;box-sizing:border-box}:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:6px}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";background-color:var(--bg);color:var(--text);line-height:1.6;overflow-x:hidden;position:relative}.bg-blobs{position:fixed;top:0;left:0;width:100%;height:100%;z-index:-1;overflow:hidden;background:radial-gradient(circle at 50% 50%,#1e1b4b 0%,#0f172a 100%)}.blob{position:absolute;width:600px;height:600px;background:radial-gradient(circle,var(--accent-glow) 0%,transparent 70%);filter:blur(80px);border-radius:50%;opacity:0.5;animation:move 25s infinite alternate ease-in-out}.blob-1{top:-100px;left:-100px;animation-delay:0s}.blob-2{bottom:-100px;right:-100px;animation-delay:-5s;background:radial-gradient(circle,rgba(139,92,246,0.2) 0%,transparent 70%)}.blob-3{top:40%;left:30%;animation-duration:35s;animation-delay:-10s}@keyframes move{0%{transform:translate(0,0) scale(1)}33%{transform:translate(100px,100px) scale(1.2)}66%{transform:translate(-50px,200px) scale(0.8)}100%{transform:translate(0,0) scale(1)}}.container{max-width:1100px;margin:0 auto;padding:0 2rem}section{padding:6rem 0}.use-cases-section,#features,#self-hosting,.comparison-section{content-visibility:auto;contain-intrinsic-size:auto 1400px}nav{position:fixed;top:0;width:100%;z-index:1000;background:var(--glass);backdrop-filter:blur(12px);border-bottom:1px solid var(--glass-border);padding:1rem 0}.nav-content{display:flex;justify-content:space-between;align-items:center}.logo-area{display:flex;align-items:center;gap:0.75rem;font-weight:800;font-size:1.5rem;letter-spacing:-0.5px}.logo-area img{height:40px;width:40px}.nav-ext-status{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:rgba(16,185,129,0.15);border:1px solid rgba(16,185,129,0.3);color:#10b981;border-radius:12px;font-size:0.55rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;box-shadow:0 0 10px rgba(16,185,129,0.1);animation:fade-in 0.4s ease-out;margin-left:0.2rem}@keyframes fade-in{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.nav-links{display:flex;gap:2rem}.nav-links a{color:var(--text-muted);text-decoration:none;font-weight:500;transition:color 0.3s}.nav-links a:hover{color:var(--accent)}.hero{min-height:100vh;display:flex;align-items:center;padding-top:8rem;padding-bottom:4rem}.hero-grid{display:grid;grid-template-columns:1.2fr 1fr;align-items:center;gap:4rem;text-align:left;width:100%}.hero-text h1{font-size:4.5rem;font-weight:800;line-height:1.1;margin-bottom:1.5rem;background:linear-gradient(to bottom,#fff 40%,#6366f1);-webkit-background-clip:text;-webkit-text-fill-color:transparent}.hero-text p,.hero-subtitle{font-size:1.25rem;color:var(--text-muted);margin-bottom:2.5rem;max-width:600px;font-weight:400;line-height:1.6}.hero-mascot-container{display:block;margin-bottom:-0.5rem;margin-left:2.2rem}.hero-lookdown-mascot{display:block;width:90px;height:auto}@media (max-width:768px){.hero-mascot-container{margin-left:0;display:flex;justify-content:center}}.cta-group{display:flex;gap:1rem;flex-wrap:wrap}.btn{padding:0.85rem 1.75rem;border-radius:12px;font-weight:600;text-decoration:none;transition:all 0.3s cubic-bezier(0.4,0,0.2,1);display:inline-flex;align-items:center;gap:0.5rem;font-size:0.95rem}.btn-primary{background:var(--accent);color:white;box-shadow:0 10px 15px -3px var(--accent-glow)}.btn-primary:hover{transform:translateY(-2px);box-shadow:0 20px 25px -5px var(--accent-glow)}.btn-firefox{background:#e66000;color:white;box-shadow:0 10px 15px -3px rgba(230,96,0,0.3)}.btn-firefox:hover{background:#ff7300;transform:translateY(-2px);box-shadow:0 20px 25px -5px rgba(230,96,0,0.4)}.btn-secondary{background:var(--card);color:var(--text);border:1px solid var(--glass-border)}.btn-secondary:hover{background:#2d3748;transform:translateY(-2px)}.version-badge{display:inline-block;background:rgba(99,102,241,0.1);color:var(--accent);padding:0.4rem 1rem;border-radius:99px;font-size:0.8rem;font-weight:700;margin-bottom:1.5rem;border:1px solid rgba(99,102,241,0.3);letter-spacing:0.05em;text-transform:uppercase}.hero-mockup-wrapper{display:flex;justify-content:center;align-items:center;width:100%}.extension-mockup{width:320px;height:520px;background:#0f172a;border-radius:20px;border:1px solid rgba(255,255,255,0.08);box-shadow:0 20px 40px rgba(0,0,0,0.4),0 0 20px rgba(99,102,241,0.15);display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;overflow:hidden;position:relative;user-select:none;padding:16px;padding-bottom:0;box-sizing:border-box}.mock-header-row{display:flex;align-items:center;margin-bottom:16px;flex-shrink:0}.mock-header-title{font-size:18px;margin:0;color:var(--accent);letter-spacing:1px;text-transform:uppercase;display:inline-flex;align-items:center;gap:8px;font-weight:800}.mock-header-title img{width:24px;height:24px;object-fit:contain;border-radius:4px}.mock-version-link{margin-left:auto;display:flex;align-items:center;gap:4px;font-size:10px;color:var(--text-muted);text-decoration:none;opacity:0.5;transition:opacity 0.2s,color 0.2s;cursor:pointer}.mock-version-link:hover{opacity:1;color:var(--accent)}.mock-tabs{display:flex;gap:4px;background:#1e293b;padding:4px;border-radius:12px;margin-bottom:20px;flex-shrink:0}.mock-tab{flex:1;background:none;border:none;color:var(--text-muted);font-size:0.75rem;font-weight:600;padding:8px 4px;cursor:pointer;border-radius:8px;transition:all 0.2s;text-align:center}.mock-tab:hover{color:var(--text)}.mock-tab.active{background:var(--accent);color:white}.mock-body{flex:1;overflow-y:auto;padding:0;padding-bottom:16px;display:flex;flex-direction:column;font-size:0.8rem;scrollbar-width:none}.mock-body::-webkit-scrollbar{display:none}.mock-screen{display:none;flex-direction:column;gap:12px}.mock-screen.active{display:flex}.mock-card{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:12px}.mock-label{font-size:0.65rem;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:0.4rem}.mock-input{background:#1e293b;border:1px solid #334155;border-radius:8px;color:white;padding:8px 10px;font-size:0.75rem;width:100%;outline:none}.mock-btn{background:var(--accent);color:white;border:none;border-radius:6px;padding:0.5rem;font-weight:600;font-size:0.75rem;cursor:pointer;transition:background 0.2s;text-align:center}.mock-btn:hover{background:#4f46e5}.mock-joined-room{display:flex;justify-content:space-between;align-items:center;background:rgba(99,102,241,0.1);border:1px solid rgba(99,102,241,0.2);border-radius:8px;padding:0.6rem 0.75rem}.mock-room-name{font-weight:700;color:var(--accent);font-size:0.85rem}.mock-server-badge{background:rgba(99,102,241,0.2);color:var(--accent);font-size:0.6rem;font-weight:700;padding:2px 6px;border-radius:4px}.mock-invite-box{display:flex;gap:0.4rem}.mock-invite-box input{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mock-peer-list{display:flex;flex-direction:column;gap:0.5rem}.mock-peer-item{display:flex;flex-direction:column;background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.03);border-radius:8px;padding:0.5rem 0.6rem}.mock-peer-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:0.25rem}.mock-peer-name{font-weight:700;color:var(--text)}.mock-peer-meta{font-size:0.65rem;color:var(--text-muted)}.mock-peer-tab{font-size:0.7rem;color:var(--accent);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mock-peer-status{font-size:0.65rem;color:var(--text-muted);display:flex;align-items:center;gap:0.25rem}.mock-target-box{display:flex;align-items:center;gap:0.4rem;background:rgba(234,179,8,0.1);border:1px solid rgba(234,179,8,0.2);color:#facc15;padding:0.5rem 0.6rem;border-radius:8px;font-weight:600;font-size:0.7rem}.mock-ctrl-buttons{display:grid;grid-template-columns:1fr 1fr;gap:0.5rem}.mock-btn-play{background:#22c55e}.mock-btn-play:hover{background:#16a34a}.mock-btn-pause{background:#ef4444}.mock-btn-pause:hover{background:#dc2626}.mock-btn-force{background:var(--accent);grid-column:span 2}.mock-status-display{display:flex;align-items:center;justify-content:space-between}.mock-status-pill{display:inline-flex;align-items:center;gap:0.3rem;background:rgba(34,197,94,0.1);border:1px solid rgba(34,197,94,0.2);color:#22c55e;padding:2px 8px;border-radius:99px;font-size:0.65rem;font-weight:700}.mock-log-item{font-size:0.7rem;color:var(--text-muted);border-left:2px solid var(--accent);padding-left:0.4rem;margin-top:0.4rem}.mock-settings-row{display:flex;align-items:flex-start;gap:0.5rem;margin-bottom:0.6rem}.mock-settings-row input[type="checkbox"]{margin-top:0.2rem;cursor:pointer}.mock-settings-row label{cursor:pointer;font-weight:600}.mock-settings-row p{font-size:0.65rem;color:var(--text-muted);margin-top:0.1rem}.mock-toggle-switch{position:relative;display:inline-block;width:36px;height:20px;flex-shrink:0}.mock-toggle-switch input{opacity:0;width:0;height:0}.mock-slider{position:absolute;cursor:default;top:0;left:0;right:0;bottom:0;background-color:#334155;transition:.3s;border-radius:20px}.mock-slider:before{position:absolute;content:"";height:14px;width:14px;left:3px;bottom:3px;background-color:#94a3b8;transition:.3s;border-radius:50%}input:checked + .mock-slider{background-color:var(--accent)}input:checked + .mock-slider:before{transform:translateX(16px);background-color:white}.mock-diagnostic-grid{display:grid;grid-template-columns:1fr 1fr;gap:0.4rem}.mock-diag-box{background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.04);border-radius:6px;padding:0.4rem}.mock-diag-box .diag-val{font-family:monospace;font-weight:700;color:var(--accent);font-size:0.75rem}.features-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem;margin-top:4rem}.feature-card{background:rgba(30,41,59,0.45);backdrop-filter:blur(16px) saturate(120%);-webkit-backdrop-filter:blur(16px) saturate(120%);padding:2.5rem;border-radius:24px;border:1px solid rgba(255,255,255,0.08);box-shadow:0 8px 32px 0 rgba(0,0,0,0.3);transition:all 0.3s cubic-bezier(0.4,0,0.2,1);position:relative;overflow:hidden}.feature-card::before{content:'';position:absolute;top:0;left:0;right:0;bottom:0;border-radius:24px;padding:1px;background:linear-gradient(to bottom right,rgba(255,255,255,0.12),transparent);-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none}.feature-card:hover{transform:translateY(-5px);box-shadow:0 15px 30px rgba(99,102,241,0.2);border-color:rgba(99,102,241,0.3)}.feature-card:hover::before{background:linear-gradient(to bottom right,rgba(99,102,241,0.3),transparent)}.feature-icon-svg{display:flex;flex-shrink:0;align-items:center;justify-content:center;width:44px;height:44px;background:rgba(99,102,241,0.12);color:var(--accent);border-radius:12px;margin-right:14px;transition:all 0.3s ease}.feature-card:hover .feature-icon-svg{background:var(--accent);color:white;box-shadow:0 0 15px var(--accent-glow);transform:scale(1.05)}.bento-icon{width:22px;height:22px;display:block;flex-shrink:0}.feature-card h3{margin-bottom:1rem;font-size:1.25rem;font-weight:700;display:flex;align-items:center}.feature-card p{color:var(--text-muted);font-size:0.95rem;line-height:1.6}.feature-card.bento-large{grid-column:span 2;background:linear-gradient(135deg,rgba(30,41,59,0.45) 0%,rgba(99,102,241,0.08) 100%);padding:3rem 3.5rem;display:grid;grid-template-columns:1fr 2fr;gap:3rem;align-items:center}.feature-card.bento-large h3{flex-direction:column;align-items:center;text-align:center;gap:1rem;margin-bottom:0;font-size:1.25rem}.feature-card.bento-large .feature-icon,.feature-card.bento-large .feature-icon-svg{width:52px;height:52px;border-radius:14px;margin-right:0;flex-shrink:0}.feature-card.bento-large .bento-icon{width:24px;height:24px}.feature-card.bento-large p{font-size:1rem;line-height:1.7;margin:0}.feature-card.bento-large::after{content:'';position:absolute;top:0;left:2.5rem;right:2.5rem;height:2px;background:linear-gradient(90deg,transparent,rgba(99,102,241,0.4),transparent);opacity:0;transition:opacity 0.3s ease}.feature-card.bento-large:hover::after{opacity:1}@media (max-width:900px){.features-grid{grid-template-columns:repeat(2,1fr);gap:1.25rem}.feature-card.bento-large{grid-column:span 2;padding:2.5rem;gap:2rem}.feature-card.bento-large h3{font-size:1.15rem}}@media (max-width:600px){.features-grid{grid-template-columns:1fr;gap:1rem}.feature-card.bento-large{grid-column:span 1;display:flex;flex-direction:column;padding:1.75rem;gap:1rem}.feature-card.bento-large h3{flex-direction:row;align-items:center;text-align:left;gap:0.75rem;margin-bottom:0;font-size:1.15rem}.feature-card.bento-large .feature-icon,.feature-card.bento-large .feature-icon-svg{width:40px;height:40px;border-radius:10px;margin-right:0}.feature-card.bento-large .bento-icon{width:18px;height:18px}.feature-card.bento-large p{font-size:0.9rem;line-height:1.6}.feature-card.bento-large::after{display:none}.feature-card{padding:1.75rem}.feature-card h3{font-size:1.1rem}.feature-icon-svg{width:40px;height:40px;border-radius:10px;margin-right:12px}.bento-icon{width:18px;height:18px}}.steps{display:flex;flex-direction:column;gap:6rem}.step{display:grid;grid-template-columns:1fr 1.1fr;gap:6rem;align-items:center}.step:nth-child(even) .step-text{order:2}.step-num{font-size:4rem;font-weight:800;color:rgba(99,102,241,0.15);line-height:1;margin-bottom:0.5rem}.step-text h3{font-size:1.85rem;margin-bottom:1rem;font-weight:800}.step-text p{color:var(--text-muted);font-size:1.05rem;line-height:1.6}.step-illustration-1,.step-illustration-2,.step-illustration-3{background:radial-gradient(circle at top left,#1e293b,#0f172a);height:280px;border-radius:24px;border:1px solid var(--glass-border);position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;box-shadow:0 20px 40px rgba(0,0,0,0.4),inset 0 1px 0 rgba(255,255,255,0.05);transition:all 0.4s cubic-bezier(0.16,1,0.3,1)}.step-illustration-1:hover,.step-illustration-2:hover,.step-illustration-3:hover{transform:translateY(-6px) scale(1.02);border-color:rgba(99,102,241,0.25);box-shadow:0 25px 50px rgba(99,102,241,0.15),inset 0 1px 0 rgba(255,255,255,0.1)}.illus-browser-container{width:90%;height:80%;background:#090d16;border:1px solid rgba(255,255,255,0.05);border-radius:12px;overflow:hidden;box-shadow:0 15px 30px rgba(0,0,0,0.5);display:flex;flex-direction:column}.illus-browser-header{background:#131924;padding:0.6rem 0.8rem;display:flex;align-items:center;border-bottom:1px solid rgba(255,255,255,0.05)}.illus-browser-dots{display:flex;gap:6px;margin-right:1.5rem}.illus-browser-dot{width:8px;height:8px;border-radius:50%;opacity:0.6}.illus-browser-dot:nth-child(1){background:#ef4444}.illus-browser-dot:nth-child(2){background:#fbbf24}.illus-browser-dot:nth-child(3){background:#22c55e}.illus-browser-address-bar{background:#090d16;border:1px solid rgba(255,255,255,0.08);border-radius:6px;color:var(--text-muted);font-size:0.68rem;padding:3px 12px;flex-grow:1;max-width:60%;text-align:center;font-family:monospace;letter-spacing:0.2px}.illus-browser-address-bar .url-protocol{color:#22c55e;font-weight:600}.illus-browser-toolbar{display:flex;margin-left:auto}.illus-extension-btn{width:22px;height:22px;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all 0.3s}.illus-extension-btn.active{background:rgba(99,102,241,0.2);border:1px solid var(--accent);box-shadow:0 0 10px rgba(99,102,241,0.4);animation:active-pulse 2s infinite alternate}@keyframes active-pulse{0%{transform:scale(1);box-shadow:0 0 5px rgba(99,102,241,0.4)}100%{transform:scale(1.08);box-shadow:0 0 12px rgba(99,102,241,0.7)}}.illus-browser-content{flex-grow:1;padding:1rem;position:relative;display:flex;align-items:flex-start}.illus-store-card{background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.04);border-radius:12px;padding:0.8rem;width:65%;display:flex;flex-direction:column;gap:10px}.illus-store-card-header{display:flex;align-items:center;gap:8px}.illus-large-logo{width:30px;height:30px;object-fit:contain;border-radius:6px;box-shadow:0 0 10px rgba(99,102,241,0.2)}.illus-store-info{display:flex;flex-direction:column}.illus-store-title{font-size:0.88rem;font-weight:800;color:var(--text);line-height:1.1}.illus-store-desc{font-size:0.58rem;color:var(--text-muted);line-height:1.2;margin-top:2px}.illus-store-buttons{display:flex;flex-direction:column;gap:6px}.illus-store-btn{display:inline-flex;align-items:center;gap:6px;padding:5px 8px;border-radius:8px;font-size:0.58rem;font-weight:700;color:white;border:1px solid rgba(255,255,255,0.05);background:rgba(255,255,255,0.03);box-shadow:0 2px 5px rgba(0,0,0,0.2);cursor:default;transition:all 0.2s}.illus-store-btn img{width:11px;height:11px;display:block}.illus-store-btn.chrome{border-color:rgba(99,102,241,0.25);background:rgba(99,102,241,0.08);box-shadow:0 0 10px rgba(99,102,241,0.05)}.illus-store-btn.firefox{border-color:rgba(249,115,22,0.25);background:rgba(249,115,22,0.08);box-shadow:0 0 10px rgba(249,115,22,0.05)}.install-breathe{animation:install-breathe 2.5s ease-in-out infinite;z-index:2;position:relative}@keyframes install-breathe{0%,100%{transform:scale(1);box-shadow:0 0 15px rgba(99,102,241,0.2)}50%{transform:scale(1.05);box-shadow:0 0 25px rgba(99,102,241,0.5)}}.install-breathe.firefox,.btn-firefox.install-breathe{animation-name:install-breathe-ff}@keyframes install-breathe-ff{0%,100%{transform:scale(1);box-shadow:0 0 15px rgba(249,115,22,0.2)}50%{transform:scale(1.05);box-shadow:0 0 25px rgba(249,115,22,0.5)}}.illus-extension-popup{position:absolute;top:0.6rem;right:0.6rem;width:145px;background:rgba(30,41,59,0.75);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,0.12);border-radius:12px;padding:0.6rem 0.8rem;box-shadow:0 10px 25px rgba(0,0,0,0.5),inset 0 1px 0 rgba(255,255,255,0.1);animation:popup-float 4s ease-in-out infinite;z-index:5}@keyframes popup-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}.illus-extension-popup .popup-title{display:flex;align-items:center;gap:5px;font-size:0.72rem;font-weight:700;color:var(--text);margin-bottom:6px;border-bottom:1px solid rgba(255,255,255,0.08);padding-bottom:4px}.illus-extension-popup .popup-title img{width:12px;height:12px}.illus-extension-popup .popup-status{margin-bottom:4px}.status-badge-success{background:rgba(34,197,94,0.12);color:#22c55e;font-size:0.6rem;font-weight:700;padding:2px 6px;border-radius:4px;border:1px solid rgba(34,197,94,0.2);display:inline-flex;align-items:center;gap:3px;animation:status-glow 2s infinite alternate}@keyframes status-glow{0%{box-shadow:0 0 0 rgba(34,197,94,0)}100%{box-shadow:0 0 6px rgba(34,197,94,0.3)}}.illus-extension-popup .popup-quick-start{font-size:0.55rem;color:var(--text-muted);font-weight:500;line-height:1.2}.illus-popup-card{width:220px;background:rgba(30,41,59,0.75);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.08);border-radius:16px;padding:0.95rem;box-shadow:0 15px 35px rgba(0,0,0,0.5),inset 0 1px 0 rgba(255,255,255,0.1);display:flex;flex-direction:column;gap:0.75rem;animation:popup-float 4s ease-in-out infinite;animation-delay:-1s}.illus-popup-header{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid rgba(255,255,255,0.06);padding-bottom:8px}.illus-popup-brand{display:flex;align-items:center;gap:6px;font-size:0.82rem;font-weight:800;letter-spacing:-0.2px}.illus-popup-version{font-size:0.58rem;color:var(--text-muted)}.illus-popup-tabs{display:flex;gap:4px;background:rgba(9,13,22,0.4);padding:3px;border-radius:8px;border:1px solid rgba(255,255,255,0.03)}.illus-popup-tab{flex:1;text-align:center;font-size:0.62rem;padding:4px 0;border-radius:6px;color:var(--text-muted);font-weight:600}.illus-popup-tab.active{background:var(--card);color:var(--accent);box-shadow:0 2px 5px rgba(0,0,0,0.2)}.illus-popup-body{display:flex;flex-direction:column;gap:0.75rem;position:relative}.illus-popup-btn{background:linear-gradient(135deg,var(--accent),#8b5cf6);border-radius:8px;padding:9px;color:white;font-weight:700;font-size:0.7rem;text-align:center;box-shadow:0 4px 12px rgba(99,102,241,0.3);position:relative;overflow:hidden;cursor:default;animation:create-btn-pulse 2s infinite alternate}@keyframes create-btn-pulse{0%{transform:scale(1);box-shadow:0 4px 12px rgba(99,102,241,0.3)}100%{transform:scale(1.03);box-shadow:0 6px 16px rgba(99,102,241,0.5)}}.illus-btn-shine{position:absolute;top:0;left:-100%;width:50%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.25),transparent);transform:skewX(-20deg);animation:shimmer-sweep 3s infinite ease-in-out}@keyframes shimmer-sweep{0%{left:-100%}50%,100%{left:150%}}.illus-collapsed-details{background:rgba(9,13,22,0.4);border:1px solid rgba(255,255,255,0.05);border-radius:8px;padding:7px 12px;font-size:0.56rem;color:var(--text-muted);font-weight:700;text-transform:uppercase;display:flex;align-items:center;gap:6px;letter-spacing:0.2px}.details-arrow{font-size:0.48rem;color:var(--text-muted);opacity:0.7}.illus-floating-success{position:absolute;bottom:-1.2rem;left:50%;transform:translateX(-50%);background:rgba(9,13,22,0.9);border:1px solid rgba(34,197,94,0.3);border-radius:20px;padding:3px 10px;display:flex;align-items:center;gap:4px;box-shadow:0 4px 10px rgba(0,0,0,0.4);animation:floating-success-fade 5s infinite;white-space:nowrap;z-index:10}@keyframes floating-success-fade{0%,100%,75%{opacity:0;transform:translate(-50%,5px) scale(0.9)}15%,60%{opacity:1;transform:translate(-50%,0) scale(1)}}.illus-floating-success .success-icon{font-size:0.65rem}.illus-floating-success span[lang]{font-size:0.58rem;color:#22c55e;font-weight:700}.illus-sync-theater{width:95%;display:flex;align-items:center;justify-content:center;position:relative;gap:0.6rem}.illus-player-card{width:145px;background:rgba(15,23,42,0.7);border:1px solid rgba(255,255,255,0.05);border-radius:12px;padding:6px;box-shadow:0 10px 25px rgba(0,0,0,0.4);display:flex;flex-direction:column;gap:4px;position:relative;z-index:2}.illus-player-card.player-a{animation:popup-float 4s ease-in-out infinite;animation-delay:-2s}.illus-player-card.player-b{animation:popup-float 4s ease-in-out infinite;animation-delay:-3s}.player-header{display:flex;justify-content:space-between;align-items:center;font-size:0.55rem}.player-user{font-weight:700;color:var(--text)}.player-badge{font-size:0.42rem;font-weight:800;padding:1px 3px;border-radius:3px}.player-badge.active{background:rgba(34,197,94,0.15);color:#22c55e;border:1px solid rgba(34,197,94,0.25)}.player-video-canvas{height:70px;border-radius:8px;background:linear-gradient(135deg,#1e1b4b,#311042);position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255,255,255,0.02)}.player-video-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:radial-gradient(circle at center,rgba(139,92,246,0.1) 0%,transparent 80%)}.player-play-pulse{width:24px;height:24px;border-radius:50%;background:rgba(99,102,241,0.85);color:white;font-size:0.65rem;display:flex;align-items:center;justify-content:center;box-shadow:0 0 10px rgba(99,102,241,0.5);z-index:3;animation:play-pulse 2s infinite alternate}@keyframes play-pulse{0%{transform:scale(1);box-shadow:0 0 6px rgba(99,102,241,0.4)}100%{transform:scale(1.15);box-shadow:0 0 15px rgba(99,102,241,0.8)}}.player-controls{display:flex;align-items:center;gap:4px;padding:2px 2px 0 2px}.control-btn{font-size:0.58rem;color:var(--accent)}.player-timeline{flex-grow:1;height:3px;background:rgba(255,255,255,0.1);border-radius:2px;position:relative}.timeline-fill{position:absolute;top:0;left:0;height:100%;background:var(--accent);border-radius:2px;width:60%;animation:theater-grow 6s infinite linear}.timeline-knob{position:absolute;top:-2px;left:60%;width:7px;height:7px;border-radius:50%;background:white;box-shadow:0 0 4px rgba(0,0,0,0.5);transform:translateX(-50%);animation:theater-knob-grow 6s infinite linear}@keyframes theater-grow{0%{width:0%}100%{width:100%}}@keyframes theater-knob-grow{0%{left:0%}100%{left:100%}}.control-time{font-size:0.5rem;color:var(--text-muted);font-family:monospace}.illus-sync-bridge{flex-grow:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;position:relative;z-index:1}.illus-sync-bridge .sync-line{width:100%;height:2px;background:rgba(255,255,255,0.06);position:relative;overflow:hidden}.illus-sync-bridge .sync-beam{position:absolute;top:0;left:-100%;width:50px;height:100%;background:linear-gradient(90deg,transparent,var(--accent),var(--success),transparent);animation:sync-flow 2.5s infinite linear}@keyframes sync-flow{0%{left:-100%}100%{left:100%}}.sync-status-badge{background:rgba(34,197,94,0.12);border:1px solid rgba(34,197,94,0.25);color:#22c55e;font-size:0.5rem;font-weight:800;letter-spacing:0.5px;padding:2px 6px;border-radius:6px;white-space:nowrap;animation:active-pulse-green 2s infinite alternate}@keyframes active-pulse-green{0%{box-shadow:0 0 3px rgba(34,197,94,0.1)}100%{box-shadow:0 0 8px rgba(34,197,94,0.4)}}.terminal-container{max-width:850px;margin:3rem auto 0 auto;background:#0f172a;border:1px solid rgba(255,255,255,0.08);border-radius:16px;overflow:hidden;box-shadow:0 20px 45px rgba(0,0,0,0.5);text-align:left}.terminal-header{background:#1e293b;padding:0.85rem 1.25rem;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid rgba(255,255,255,0.06)}.terminal-dots{display:flex;gap:6px}.terminal-dot{width:10px;height:10px;border-radius:50%}.terminal-dot.red{background:#ef4444}.terminal-dot.yellow{background:#f59e0b}.terminal-dot.green{background:#10b981}.terminal-tabs{display:flex;gap:0.5rem}.terminal-tab-btn{background:none;border:none;color:var(--text-muted);font-weight:600;font-size:0.8rem;padding:0.35rem 0.75rem;border-radius:6px;cursor:pointer;transition:all 0.2s}.terminal-tab-btn:hover{color:var(--text);background:rgba(255,255,255,0.03)}.terminal-tab-btn.active{color:var(--accent);background:rgba(99,102,241,0.1);border:1px solid rgba(99,102,241,0.2)}.terminal-body{position:relative;padding:1.5rem}.terminal-pane{display:none;margin:0}.terminal-pane.active{display:block}.terminal-pane pre{margin:0;overflow-x:auto}.terminal-pane code{font-family:Consolas,Monaco,"Andale Mono","Ubuntu Mono",monospace;font-size:0.85rem;line-height:1.6;color:#e2e8f0}.t-comment{color:#64748b;font-style:italic}.t-key{color:#f472b6}.t-val{color:#38bdf8}.t-str{color:#34d399}.t-num{color:#fbbf24}.terminal-copy-btn{position:absolute;top:1rem;right:1.5rem;background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.08);color:var(--text-muted);padding:0.35rem 0.75rem;font-size:0.75rem;font-weight:600;border-radius:6px;cursor:pointer;transition:all 0.2s;display:flex;align-items:center;gap:0.3rem}.terminal-copy-btn:hover{background:rgba(255,255,255,0.08);color:var(--text);border-color:rgba(255,255,255,0.15)}.terminal-copy-btn:active{transform:scale(0.97)}footer{padding:4rem 0;border-top:1px solid var(--glass-border);text-align:center;color:var(--text-muted)}[data-reveal]{opacity:0;transform:translateY(30px);transition:all 0.8s cubic-bezier(0.4,0,0.2,1)}[data-reveal].revealed{opacity:1;transform:translateY(0)}.legal-content{max-width:800px;margin:8rem auto 4rem auto;padding:0 2rem}.legal-card{background:var(--card);padding:3rem;border-radius:24px;border:1px solid var(--glass-border)}.legal-card h1{font-size:2.5rem;margin-bottom:2rem;text-align:center}.legal-card h2{font-size:1.25rem;margin-top:1rem;margin-bottom:0.5rem;color:var(--accent)}.legal-card p{color:var(--text-muted);margin-bottom:0.5rem;font-size:0.95rem}.legal-card section{padding:0 !important;margin-bottom:0.75rem}.join-card{max-width:450px;margin:6rem auto;text-align:center}.room-badge{display:inline-block;background:rgba(99,102,241,0.1);color:var(--accent);padding:0.5rem 1rem;border-radius:99px;font-size:0.8rem;font-weight:700;margin-bottom:1rem;border:1px solid rgba(99,102,241,0.2)}@media (max-width:768px){.hero-grid,.step{grid-template-columns:1fr;text-align:center}.hero-text h1{font-size:2.5rem}.cta-group{justify-content:center;flex-wrap:wrap}.nav-links{display:none;position:absolute;top:100%;left:0;right:0;flex-direction:column;background:rgba(15,23,42,0.95);backdrop-filter:blur(12px);padding:1rem 2rem;gap:1rem;border-bottom:1px solid var(--glass-border)}.nav-links.open{display:flex}.hamburger{display:flex}.legal-card{padding:1.5rem}}html.lang-de [lang="en"]{display:none !important}html:not(.lang-de) [lang="de"]{display:none !important}.lang-select-container{position:relative;display:inline-flex;align-items:center;gap:8px;background:rgba(30,41,59,0.4);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.08);border-radius:9999px;padding:6px 14px 6px 12px;transition:all 0.3s cubic-bezier(0.4,0,0.2,1);color:var(--text-muted)}.lang-select-container:hover{background:rgba(30,41,59,0.6);border-color:rgba(99,102,241,0.3);color:var(--text);box-shadow:0 0 15px rgba(99,102,241,0.1)}.lang-select-container .globe-icon{width:16px;height:16px;flex-shrink:0;opacity:0.8;transition:transform 0.5s ease}.lang-select-container:hover .globe-icon{transform:rotate(15deg);opacity:1}.lang-select-container .chevron-icon{width:12px;height:12px;flex-shrink:0;pointer-events:none;opacity:0.6;margin-left:-2px}.lang-select-container:hover .chevron-icon{opacity:1}.lang-dropdown{appearance:none;-webkit-appearance:none;-moz-appearance:none;background:transparent;border:none;outline:none;font-family:inherit;font-size:0.8rem;font-weight:600;color:currentColor;cursor:pointer;padding:0 12px 0 0;margin:0;width:auto}.lang-dropdown option{background:#0f172a;color:white;font-family:inherit;font-size:0.9rem}.hamburger{display:none;align-items:center;justify-content:center;background:none;border:none;color:var(--text);font-size:1.5rem;cursor:pointer;padding:0.25rem;line-height:1}.feature-card:nth-child(1){--card-accent:rgba(99,102,241,0.06)}.feature-card:nth-child(2){--card-accent:rgba(139,92,246,0.06)}.feature-card:nth-child(3){--card-accent:rgba(34,197,94,0.06)}.feature-card:nth-child(4){--card-accent:rgba(56,189,248,0.06)}.feature-card:nth-child(5){--card-accent:rgba(245,158,11,0.06)}.feature-card:nth-child(6){--card-accent:rgba(236,72,153,0.06)}.feature-card{background:linear-gradient(135deg,var(--card-accent,transparent),var(--card))}.compat-section{padding:1rem 0 3.5rem 0;text-align:center;background:rgba(255,255,255,0.01);border-bottom:1px solid var(--glass-border)}.compat-mascot{display:block;margin:0 auto 0.5rem auto;max-width:368px;width:100%;height:auto;transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.compat-mascot:hover{transform:scale(1.05) translateY(-5px) rotate(1deg)}.compat-heading{font-size:1rem;font-weight:600;color:var(--text-muted);letter-spacing:0.08em;text-transform:uppercase;margin-bottom:2rem}.compat-row{display:flex;justify-content:center;align-items:center;gap:3rem;flex-wrap:wrap}.compat-logo{display:flex;flex-direction:column;align-items:center;gap:0.5rem;font-size:0.75rem;font-weight:700;color:var(--text-muted);transition:opacity 0.3s;opacity:0.55}.compat-logo:hover{opacity:0.85}.compat-logo img{width:28px;height:28px;display:block}.compat-more{opacity:0.4;cursor:help;flex-direction:row;gap:0.35rem;position:relative}.compat-more:hover{opacity:0.6}.compat-more-icon{font-size:1.1rem;font-weight:700;color:var(--accent);line-height:1}.compat-tooltip{display:none;position:absolute;bottom:calc(100% + 10px);left:50%;transform:translateX(-50%);background:var(--card);color:var(--text-muted);padding:0.6rem 0.9rem;border-radius:8px;font-size:0.72rem;font-weight:500;white-space:nowrap;border:1px solid var(--glass-border);box-shadow:0 8px 20px rgba(0,0,0,0.4);z-index:10;line-height:1.4}.compat-tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:var(--glass-border)}.compat-more:hover .compat-tooltip{display:block}.join-spinner{width:36px;height:36px;border:3px solid rgba(99,102,241,0.2);border-top-color:var(--accent);border-radius:50%;animation:spin 0.8s linear infinite;margin:0 auto 0.75rem}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important}[data-reveal]{opacity:1;transform:none}.blob{animation:none}.illus-typing-text::after{animation:none}.illus-timeline-progress{animation:none;width:60%}.illus-sync-pulse{animation:none}.illus-extension-icon{animation:none}}.use-cases-section{padding:6rem 0;position:relative;border-bottom:1px solid var(--glass-border)}.use-cases-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:2rem;margin-top:1rem}.use-case-card{background:rgba(30,41,59,0.4);border:1px solid var(--glass-border);border-radius:16px;padding:1.2rem 1.6rem 1.7rem 1.6rem;text-align:left;transition:transform 0.3s cubic-bezier(0.16,1,0.3,1),box-shadow 0.3s ease;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:flex;flex-direction:column;gap:0.8rem;position:relative;overflow:hidden}.use-case-card::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,transparent,var(--card-accent-border,var(--accent)),transparent);opacity:0;transition:opacity 0.3s ease}.use-case-card:nth-child(1){--card-accent-border:#f59e0b}.use-case-card:nth-child(2){--card-accent-border:#38bdf8}.use-case-card:nth-child(3){--card-accent-border:#ec4899}.use-case-card:hover{transform:translateY(-5px);box-shadow:0 12px 30px rgba(0,0,0,0.35);border-color:rgba(255,255,255,0.15)}.use-case-card:hover::before{opacity:1}.use-case-image{display:block;width:100%;max-width:272px;height:150px;object-fit:contain;border-radius:8px;margin:0 auto 0 auto}.cta-github-mascot{display:block;width:100%;max-width:250px;height:auto;margin:1.5rem auto}.features-questions-mascot{display:block;width:100%;max-width:250px;height:auto;margin:-1.5rem auto 0.2rem auto;transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.features-questions-mascot:hover{transform:scale(1.05) translateY(-4px) rotate(-1.5deg)}.comparison-mascot{display:block;width:100%;max-width:260px;height:auto;margin:-2.2rem auto 0.2rem auto;transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.comparison-mascot:hover{transform:scale(1.05) translateY(-4px) rotate(1deg)}.use-case-icon{font-size:1.6rem;margin-right:0.6rem;display:inline-block;vertical-align:middle;filter:drop-shadow(0 2px 8px rgba(0,0,0,0.2))}.use-case-card h3{font-size:1.25rem;font-weight:700;margin:0;color:white}.use-case-card p{font-size:0.9rem;line-height:1.6;color:var(--text-muted);margin:0}.comparison-section{padding:6rem 0;background:rgba(255,255,255,0.01);border-bottom:1px solid var(--glass-border)}.comparison-table-wrapper{overflow-x:auto;background:rgba(30,41,59,0.35);border:1px solid var(--glass-border);border-radius:16px;box-shadow:0 10px 30px rgba(0,0,0,0.2);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);margin-top:1rem}.comparison-table{width:100%;border-collapse:collapse;text-align:left;font-size:0.95rem}.comparison-table th,.comparison-table td{padding:1.25rem 1.5rem;border-bottom:1px solid rgba(255,255,255,0.06)}.comparison-table th{background:rgba(15,23,42,0.6);font-weight:700;color:white;text-transform:uppercase;font-size:0.8rem;letter-spacing:0.08em}.comparison-table th.highlight,.comparison-table td.highlight{background:rgba(99,102,241,0.08)}.comparison-table tbody tr:hover{background:rgba(255,255,255,0.02)}.comparison-table tbody tr:last-child td{border-bottom:none}.feat-name{display:flex;flex-direction:column;gap:0.25rem}.feat-name strong{color:white;font-weight:600}.feat-desc{font-size:0.8rem;color:var(--text-muted)}.check{color:#22c55e;font-weight:700}.cross{color:#ef4444;font-weight:500;opacity:0.8}@media (max-width:768px){.comparison-table th,.comparison-table td{padding:1rem;font-size:0.85rem}.feat-desc{display:none}}.source-link{color:var(--accent);text-decoration:none;font-size:0.72rem;font-weight:700;margin-left:0.25rem;display:inline-flex;align-items:center;vertical-align:super;opacity:0.6;transition:opacity 0.2s ease,color 0.2s ease,transform 0.2s ease}.source-link:hover{opacity:1;color:#38bdf8;transform:translateY(-1px)}.table-footnotes{padding:0.8rem 1.25rem;background:rgba(15,23,42,0.45);border-top:1px solid rgba(255,255,255,0.05);font-size:0.72rem;color:var(--text-muted);line-height:1.5;opacity:0.65;transition:opacity 0.2s ease}.table-footnotes:hover{opacity:0.95}.table-footnotes p{margin:0;display:flex;align-items:baseline;gap:0.4rem}.table-footnotes p:not(:last-child){margin-bottom:0.4rem}.table-footnotes a{color:var(--accent);text-decoration:none;font-weight:500;transition:color 0.2s ease,text-decoration 0.2s ease}.table-footnotes a:hover{color:#38bdf8;text-decoration:underline}.table-footnotes sup{font-weight:700;color:var(--accent)}@media (max-width:768px){.table-footnotes{padding:0.75rem 1rem;font-size:0.68rem}}.join-status-visual{margin-bottom:2rem;position:relative;height:200px;display:flex;align-items:center;justify-content:center}.join-status-mascot{display:block;width:140px;height:auto;z-index:2;filter:drop-shadow(0 4px 12px rgba(0,0,0,0.15))}.join-status-mascot.searching-mascot{width:175px}.join-status-pulse{animation:mascot-gentle-pulse 2s ease-in-out infinite}@keyframes mascot-gentle-pulse{0%{transform:scale(0.96);filter:drop-shadow(0 4px 10px rgba(99,102,241,0.15))}50%{transform:scale(1.04);filter:drop-shadow(0 8px 20px rgba(99,102,241,0.35))}100%{transform:scale(0.96);filter:drop-shadow(0 4px 10px rgba(99,102,241,0.15))}}.legal-mascot{display:block;width:180px;height:auto;margin:-0.75rem auto 0.4rem auto;filter:drop-shadow(0 4px 12px rgba(0,0,0,0.15));transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.legal-mascot:hover{transform:scale(1.06) translateY(-4px) rotate(1.5deg)}.selfhost-mascot{display:block;width:300px;height:auto;margin:0 auto;filter:drop-shadow(0 4px 12px rgba(0,0,0,0.15));transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.selfhost-mascot:hover{transform:scale(1.05) translateY(-4px) rotate(-1deg)}.status-ring{position:absolute;width:90px;height:90px;border-radius:50%;background:rgba(99,102,241,0.05);border:2px dashed rgba(99,102,241,0.25);z-index:1}.status-ring.active-pulse{animation:radar-pulse 3s cubic-bezier(0.25,0.8,0.25,1) infinite}@keyframes radar-pulse{0%{transform:scale(0.85);opacity:0.9;border-color:rgba(99,102,241,0.3);box-shadow:0 0 0 0px rgba(99,102,241,0.15)}50%{transform:scale(1.18);opacity:0.35;border-color:rgba(56,189,248,0.2);box-shadow:0 0 0 15px rgba(56,189,248,0)}100%{transform:scale(0.85);opacity:0.9;border-color:rgba(99,102,241,0.3);box-shadow:0 0 0 0px rgba(99,102,241,0.15)}}.join-card-actions{display:flex;flex-direction:column;gap:0.75rem;width:100%}.join-card-actions .btn{width:100%;justify-content:center;padding:1.1rem;font-size:0.88rem;font-weight:700;letter-spacing:0.04em;text-transform:uppercase}.join-card-actions .btn svg{margin-right:0.3rem;flex-shrink:0}.join-card-actions .btn img{margin-right:0.3rem;flex-shrink:0}.btn-success{background:#22c55e;color:white !important;box-shadow:0 10px 15px -3px rgba(34,197,94,0.3)}.btn-success:hover{background:#16a34a;transform:translateY(-2px);box-shadow:0 20px 25px -5px rgba(34,197,94,0.4)} \ No newline at end of file