diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..9dfdae9 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,8044 @@ +{ + "name": "edbridge-scholars", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "edbridge-scholars", + "version": "0.0.0", + "dependencies": { + "@radix-ui/react-avatar": "^1.1.11", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", + "@react-three/drei": "^10.7.7", + "@react-three/fiber": "^9.5.0", + "@tailwindcss/vite": "^4.1.18", + "@tanstack/react-table": "^8.21.3", + "canvas-confetti": "^1.9.4", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "embla-carousel-react": "^8.6.0", + "framer-motion": "^12.30.0", + "katex": "^0.16.28", + "leva": "^0.10.1", + "lucide-react": "^0.562.0", + "radix-ui": "^1.4.3", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-katex": "^3.1.0", + "react-router-dom": "^7.12.0", + "tailwind-merge": "^3.4.0", + "tailwindcss": "^4.1.18", + "three": "^0.183.2", + "vaul": "^1.1.2", + "zustand": "^5.0.9" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/node": "^24.10.1", + "@types/react": "^19.2.5", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "tw-animate-css": "^1.4.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.4", + "vite": "^7.2.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "license": "Apache-2.0" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.4", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.5", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.4", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.7", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.5" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mediapipe/tasks-vision": { + "version": "0.10.17", + "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", + "integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==", + "license": "Apache-2.0" + }, + "node_modules/@monogrid/gainmap-js": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.4.0.tgz", + "integrity": "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==", + "license": "MIT", + "dependencies": { + "promise-worker-transferable": "^1.0.4" + }, + "peerDependencies": { + "three": ">= 0.159.0" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accessible-icon": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu": { + "version": "2.2.16", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form": { + "version": "0.1.8", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.15", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.16", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-one-time-password-field": { + "version": "0.1.8", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-one-time-password-field/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-one-time-password-field/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-one-time-password-field/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-password-toggle-field": { + "version": "0.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-password-toggle-field/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-password-toggle-field/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-password-toggle-field/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.8", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider": { + "version": "1.3.6", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.15", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-toggle-group": "1.1.11" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/@react-three/drei": { + "version": "10.7.7", + "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-10.7.7.tgz", + "integrity": "sha512-ff+J5iloR0k4tC++QtD/j9u3w5fzfgFAWDtAGQah9pF2B1YgOq/5JxqY0/aVoQG5r3xSZz0cv5tk2YuBob4xEQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mediapipe/tasks-vision": "0.10.17", + "@monogrid/gainmap-js": "^3.0.6", + "@use-gesture/react": "^10.3.1", + "camera-controls": "^3.1.0", + "cross-env": "^7.0.3", + "detect-gpu": "^5.0.56", + "glsl-noise": "^0.0.0", + "hls.js": "^1.5.17", + "maath": "^0.10.8", + "meshline": "^3.3.1", + "stats-gl": "^2.2.8", + "stats.js": "^0.17.0", + "suspend-react": "^0.1.3", + "three-mesh-bvh": "^0.8.3", + "three-stdlib": "^2.35.6", + "troika-three-text": "^0.52.4", + "tunnel-rat": "^0.1.2", + "use-sync-external-store": "^1.4.0", + "utility-types": "^3.11.0", + "zustand": "^5.0.1" + }, + "peerDependencies": { + "@react-three/fiber": "^9.0.0", + "react": "^19", + "react-dom": "^19", + "three": ">=0.159" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.5.0.tgz", + "integrity": "sha512-FiUzfYW4wB1+PpmsE47UM+mCads7j2+giRBltfwH7SNhah95rqJs3ltEs9V3pP8rYdS0QlNne+9Aj8dS/SiaIA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8", + "@types/webxr": "*", + "base64-js": "^1.5.1", + "buffer": "^6.0.3", + "its-fine": "^2.0.0", + "react-use-measure": "^2.1.7", + "scheduler": "^0.27.0", + "suspend-react": "^0.1.3", + "use-sync-external-store": "^1.4.0", + "zustand": "^5.0.3" + }, + "peerDependencies": { + "expo": ">=43.0", + "expo-asset": ">=8.4", + "expo-file-system": ">=11.0", + "expo-gl": ">=11.0", + "react": ">=19 <19.3", + "react-dom": ">=19 <19.3", + "react-native": ">=0.78", + "three": ">=0.156" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + }, + "expo-asset": { + "optional": true + }, + "expo-file-system": { + "optional": true + }, + "expo-gl": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@stitches/react": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@stitches/react/-/react-1.2.8.tgz", + "integrity": "sha512-9g9dWI4gsSVe8bNLlb+lMkBYsnIKCZTmvqvDG+Avnn69XfmHZKiaMrx7cgTaddq7aTPPmXiTsbFcUy0xgI4+wA==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16.3.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.18", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.18", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.0", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.18", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.18", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "tailwindcss": "4.1.18" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/draco3d": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz", + "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.10.13", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-reconciler": { + "version": "0.28.9", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", + "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.183.1", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.183.1.tgz", + "integrity": "sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==", + "license": "MIT", + "dependencies": { + "@dimforge/rapier3d-compat": "~0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": ">=0.5.17", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~1.0.1" + } + }, + "node_modules/@types/webxr": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", + "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.55.0", + "@typescript-eslint/type-utils": "8.55.0", + "@typescript-eslint/utils": "8.55.0", + "@typescript-eslint/visitor-keys": "8.55.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.55.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.55.0", + "@typescript-eslint/types": "8.55.0", + "@typescript-eslint/typescript-estree": "8.55.0", + "@typescript-eslint/visitor-keys": "8.55.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.55.0", + "@typescript-eslint/types": "^8.55.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.55.0", + "@typescript-eslint/visitor-keys": "8.55.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.55.0", + "@typescript-eslint/typescript-estree": "8.55.0", + "@typescript-eslint/utils": "8.55.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.55.0", + "@typescript-eslint/tsconfig-utils": "8.55.0", + "@typescript-eslint/types": "8.55.0", + "@typescript-eslint/visitor-keys": "8.55.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.4", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.55.0", + "@typescript-eslint/types": "8.55.0", + "@typescript-eslint/typescript-estree": "8.55.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.55.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@use-gesture/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", + "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", + "license": "MIT" + }, + "node_modules/@use-gesture/react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", + "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", + "license": "MIT", + "dependencies": { + "@use-gesture/core": "10.3.1" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@webgpu/types": { + "version": "0.1.69", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz", + "integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/acorn": { + "version": "8.15.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/attr-accept": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz", + "integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camera-controls": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-3.1.2.tgz", + "integrity": "sha512-xkxfpG2ECZ6Ww5/9+kf4mfg1VEYAoe9aDSY+IwF0UEs7qEzwy0aVRfs2grImIECs/PoBtWFrh7RXsQkwG922JA==", + "license": "MIT", + "engines": { + "node": ">=22.0.0", + "npm": ">=10.5.1" + }, + "peerDependencies": { + "three": ">=0.126.1" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001770", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/canvas-confetti": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.4.tgz", + "integrity": "sha512-yxQbJkAVrFXWNbTUjPqjF7G+g6pDotOUHGbkZq2NELZUMDpiJ85rIEazVb8GTaAptNW2miJAXbs1BtioA251Pw==", + "license": "ISC", + "funding": { + "type": "donate", + "url": "https://www.paypal.me/kirilvatev" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "8.3.0", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-gpu": { + "version": "5.0.70", + "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.70.tgz", + "integrity": "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==", + "license": "MIT", + "dependencies": { + "webgl-constants": "^1.1.1" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/draco3d": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", + "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", + "license": "Apache-2.0" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.286", + "dev": true, + "license": "ISC" + }, + "node_modules/embla-carousel": { + "version": "8.6.0", + "license": "MIT" + }, + "node_modules/embla-carousel-react": { + "version": "8.6.0", + "license": "MIT", + "dependencies": { + "embla-carousel": "8.6.0", + "embla-carousel-reactive-utils": "8.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/embla-carousel-reactive-utils": { + "version": "8.6.0", + "license": "MIT", + "peerDependencies": { + "embla-carousel": "8.6.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.19.0", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.26", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-selector": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.5.0.tgz", + "integrity": "sha512-s8KNnmIDTBoD0p9uJ9uD0XY38SCeBOtj0UMXyQSLg1Ypfrfj8+dAvwsLjYQkQ2GjhVtp2HrnF5cJzMhBjfD8HA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "dev": true, + "license": "ISC" + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/framer-motion": { + "version": "12.34.0", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.34.0", + "motion-utils": "^12.29.2", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glsl-noise": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", + "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==", + "license": "MIT" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/hls.js": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.15.tgz", + "integrity": "sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==", + "license": "Apache-2.0" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/its-fine": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-2.0.0.tgz", + "integrity": "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==", + "license": "MIT", + "dependencies": { + "@types/react-reconciler": "^0.28.9" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/katex": { + "version": "0.16.28", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/leva": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/leva/-/leva-0.10.1.tgz", + "integrity": "sha512-BcjnfUX8jpmwZUz2L7AfBtF9vn4ggTH33hmeufDULbP3YgNZ/C+ss/oO3stbrqRQyaOmRwy70y7BGTGO81S3rA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-portal": "^1.1.4", + "@radix-ui/react-tooltip": "^1.1.8", + "@stitches/react": "^1.2.8", + "@use-gesture/react": "^10.2.5", + "colord": "^2.9.2", + "dequal": "^2.0.2", + "merge-value": "^1.0.0", + "react-colorful": "^5.5.1", + "react-dropzone": "^12.0.0", + "v8n": "^1.3.3", + "zustand": "^3.6.9" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/leva/node_modules/zustand": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", + "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", + "license": "MIT", + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.562.0", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/maath": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/maath/-/maath-0.10.8.tgz", + "integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==", + "license": "MIT", + "peerDependencies": { + "@types/three": ">=0.134.0", + "three": ">=0.134.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/merge-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/merge-value/-/merge-value-1.0.0.tgz", + "integrity": "sha512-fJMmvat4NeKz63Uv9iHWcPDjCWcCkoiRoajRTEO8hlhUC6rwaHg0QCF9hBOTjZmm4JuglPckPSTtcuJL5kp0TQ==", + "license": "MIT", + "dependencies": { + "get-value": "^2.0.6", + "is-extendable": "^1.0.0", + "mixin-deep": "^1.2.0", + "set-value": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meshline": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/meshline/-/meshline-3.3.1.tgz", + "integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==", + "license": "MIT", + "peerDependencies": { + "three": ">=0.137" + } + }, + "node_modules/meshoptimizer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.0.1.tgz", + "integrity": "sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "license": "MIT", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/motion-dom": { + "version": "12.34.0", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.29.2" + } + }, + "node_modules/motion-utils": { + "version": "12.29.2", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", + "license": "ISC" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/promise-worker-transferable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz", + "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==", + "license": "Apache-2.0", + "dependencies": { + "is-promise": "^2.1.0", + "lie": "^3.0.2" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/radix-ui": { + "version": "1.4.3", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-accessible-icon": "1.1.7", + "@radix-ui/react-accordion": "1.2.12", + "@radix-ui/react-alert-dialog": "1.1.15", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-aspect-ratio": "1.1.7", + "@radix-ui/react-avatar": "1.1.10", + "@radix-ui/react-checkbox": "1.3.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-context-menu": "2.2.16", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-dropdown-menu": "2.1.16", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-form": "0.1.8", + "@radix-ui/react-hover-card": "1.1.15", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-menubar": "1.1.16", + "@radix-ui/react-navigation-menu": "1.2.14", + "@radix-ui/react-one-time-password-field": "0.1.8", + "@radix-ui/react-password-toggle-field": "0.1.3", + "@radix-ui/react-popover": "1.1.15", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-progress": "1.1.7", + "@radix-ui/react-radio-group": "1.3.8", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-scroll-area": "1.2.10", + "@radix-ui/react-select": "2.2.6", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-slider": "1.3.6", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-switch": "1.2.6", + "@radix-ui/react-tabs": "1.1.13", + "@radix-ui/react-toast": "1.2.15", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-toggle-group": "1.1.11", + "@radix-ui/react-toolbar": "1.1.11", + "@radix-ui/react-tooltip": "1.2.8", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-escape-keydown": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-avatar": { + "version": "1.1.10", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react": { + "version": "19.2.4", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-dropzone": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-12.1.0.tgz", + "integrity": "sha512-iBYHA1rbopIvtzokEX4QubO6qk5IF/x3BtKGu74rF2JkQDXnwC4uO/lHKpaw4PJIV6iIAYOlwLv2FpiGyqHNog==", + "license": "MIT", + "dependencies": { + "attr-accept": "^2.2.2", + "file-selector": "^0.5.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/react-katex": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "katex": "^0.16.0" + }, + "peerDependencies": { + "prop-types": "^15.8.1", + "react": ">=15.3.2 <20" + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "7.13.0", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.13.0", + "license": "MIT", + "dependencies": { + "react-router": "7.13.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-use-measure": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz", + "integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.13", + "react-dom": ">=16.13" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "license": "MIT" + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stats-gl": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.4.2.tgz", + "integrity": "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==", + "license": "MIT", + "dependencies": { + "@types/three": "*", + "three": "^0.170.0" + }, + "peerDependencies": { + "@types/three": "*", + "three": "*" + } + }, + "node_modules/stats-gl/node_modules/three": { + "version": "0.170.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.170.0.tgz", + "integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==", + "license": "MIT" + }, + "node_modules/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==", + "license": "MIT" + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/suspend-react": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz", + "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=17.0" + } + }, + "node_modules/tailwind-merge": { + "version": "3.4.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.18", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/three": { + "version": "0.183.2", + "resolved": "https://registry.npmjs.org/three/-/three-0.183.2.tgz", + "integrity": "sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==", + "license": "MIT" + }, + "node_modules/three-mesh-bvh": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.8.3.tgz", + "integrity": "sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg==", + "license": "MIT", + "peerDependencies": { + "three": ">= 0.159.0" + } + }, + "node_modules/three-stdlib": { + "version": "2.36.1", + "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.36.1.tgz", + "integrity": "sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg==", + "license": "MIT", + "dependencies": { + "@types/draco3d": "^1.4.0", + "@types/offscreencanvas": "^2019.6.4", + "@types/webxr": "^0.5.2", + "draco3d": "^1.4.1", + "fflate": "^0.6.9", + "potpack": "^1.0.1" + }, + "peerDependencies": { + "three": ">=0.128.0" + } + }, + "node_modules/three-stdlib/node_modules/fflate": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/troika-three-text": { + "version": "0.52.4", + "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.4.tgz", + "integrity": "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==", + "license": "MIT", + "dependencies": { + "bidi-js": "^1.0.2", + "troika-three-utils": "^0.52.4", + "troika-worker-utils": "^0.52.0", + "webgl-sdf-generator": "1.1.1" + }, + "peerDependencies": { + "three": ">=0.125.0" + } + }, + "node_modules/troika-three-utils": { + "version": "0.52.4", + "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.52.4.tgz", + "integrity": "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==", + "license": "MIT", + "peerDependencies": { + "three": ">=0.125.0" + } + }, + "node_modules/troika-worker-utils": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz", + "integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==", + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, + "node_modules/tunnel-rat": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz", + "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", + "license": "MIT", + "dependencies": { + "zustand": "^4.3.2" + } + }, + "node_modules/tunnel-rat/node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.55.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.55.0", + "@typescript-eslint/parser": "8.55.0", + "@typescript-eslint/typescript-estree": "8.55.0", + "@typescript-eslint/utils": "8.55.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "devOptional": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/v8n": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/v8n/-/v8n-1.5.1.tgz", + "integrity": "sha512-LdabyT4OffkyXFCe9UT+uMkxNBs5rcTVuZClvxQr08D5TUgo1OFKkoT65qYRCsiKBl/usHjpXvP4hHMzzDRj3A==", + "license": "MIT" + }, + "node_modules/vaul": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", + "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/webgl-constants": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", + "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" + }, + "node_modules/webgl-sdf-generator": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", + "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==", + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/zustand": { + "version": "5.0.11", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json index 159657e..cf3ce67 100644 --- a/package.json +++ b/package.json @@ -15,13 +15,17 @@ "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", + "@react-three/drei": "^10.7.7", + "@react-three/fiber": "^9.5.0", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-table": "^8.21.3", + "canvas-confetti": "^1.9.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "embla-carousel-react": "^8.6.0", "framer-motion": "^12.30.0", "katex": "^0.16.28", + "leva": "^0.10.1", "lucide-react": "^0.562.0", "radix-ui": "^1.4.3", "react": "^19.2.0", @@ -30,6 +34,8 @@ "react-router-dom": "^7.12.0", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.18", + "three": "^0.183.2", + "vaul": "^1.1.2", "zustand": "^5.0.9" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d26eb1f..48a0d2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: '@tanstack/react-table': specifier: ^8.21.3 version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + canvas-confetti: + specifier: ^1.9.4 + version: 1.9.4 class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -68,6 +71,9 @@ importers: tailwindcss: specifier: ^4.1.18 version: 4.1.18 + vaul: + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) zustand: specifier: ^5.0.9 version: 5.0.9(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)) @@ -1544,6 +1550,9 @@ packages: caniuse-lite@1.0.30001762: resolution: {integrity: sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==} + canvas-confetti@1.9.4: + resolution: {integrity: sha512-yxQbJkAVrFXWNbTUjPqjF7G+g6pDotOUHGbkZq2NELZUMDpiJ85rIEazVb8GTaAptNW2miJAXbs1BtioA251Pw==} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -2215,6 +2224,12 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + vaul@1.1.2: + resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + vite@7.3.0: resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3706,6 +3721,8 @@ snapshots: caniuse-lite@1.0.30001762: {} + canvas-confetti@1.9.4: {} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -4377,6 +4394,15 @@ snapshots: dependencies: react: 19.2.3 + vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2): dependencies: esbuild: 0.27.2 diff --git a/src/App.tsx b/src/App.tsx index febc8e6..8f07a0d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,7 +19,8 @@ import { StudentLayout } from "./pages/student/StudentLayout"; import { TargetedPractice } from "./pages/student/targeted-practice/page"; import { Drills } from "./pages/student/drills/page"; import { HardTestModules } from "./pages/student/hard-test-modules/page"; -import { Analytics } from "./pages/student/Analytics"; +import { QuestMap } from "./pages/student/QuestMap"; +import { Register } from "./pages/auth/Register"; function App() { const router = createBrowserRouter([ @@ -27,12 +28,17 @@ function App() { path: "/login", element: , }, + { + path: "/register", + element: , + }, { path: "/student", element: , children: [ { element: , + children: [ { path: "home", @@ -55,8 +61,8 @@ function App() { element: , }, { - path: "analytics", - element: , + path: "quests", + element: , }, { path: "practice/:sheetId", diff --git a/src/components/AppSidebar.tsx b/src/components/AppSidebar.tsx index 2167cb6..0c2c28e 100644 --- a/src/components/AppSidebar.tsx +++ b/src/components/AppSidebar.tsx @@ -1,5 +1,4 @@ import { - Sidebar, SidebarContent, SidebarHeader, SidebarFooter, @@ -15,202 +14,561 @@ import { ChevronDown, BookOpen, Home, - Video, - User, Target, Zap, Trophy, - LayoutGrid, + Map, + SquareLibrary, } from "lucide-react"; import { useState } from "react"; import logo from "../assets/ed_logo1.png"; -import { NavLink } from "react-router-dom"; +import { NavLink, useNavigate, useLocation } from "react-router-dom"; import { useAuthStore } from "../stores/authStore"; import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar"; export function AppSidebar() { - const [open, setOpen] = useState(true); + const [open, setOpen] = useState(false); const user = useAuthStore((s) => s.user); + const navigate = useNavigate(); + const location = useLocation(); + const isQuestPage = location.pathname.startsWith("/student/quests"); + + const STYLES = ` + /* ══ DEFAULT sidebar (cream frosted glass) ══ */ + .as-sidebar-container { + position: fixed; + top: 0.5rem; + bottom: 0.5rem; + left: 0.5rem; + width: 16rem; + z-index: 10; + border-radius: 1.75rem; + overflow: hidden; + pointer-events: auto; + background: rgba(255,251,244,0.72); + backdrop-filter: blur(24px) saturate(180%); + -webkit-backdrop-filter: blur(24px) saturate(180%); + border: 1.5px solid rgba(255,255,255,0.7); + box-shadow: + 0 8px 32px rgba(0,0,0,0.12), + 0 2px 8px rgba(0,0,0,0.06), + inset 0 1px 0 rgba(255,255,255,0.8); + transition: + background 0.4s ease, + border-color 0.4s ease, + box-shadow 0.4s ease, + z-index 0.3s ease; + display: flex; + flex-direction: column; + height: calc(100vh - 1rem); + } + + /* ══ QUEST mode sidebar (dark navy pirate + gold) ══ */ + .as-sidebar-container.quest-mode { + background: linear-gradient( + 180deg, + rgba(251,191,36,0.12) 0%, + rgba(251,191,36,0.08) 50%, + rgba(251,191,36,0.1) 100% + ); + background-size: 100% 200%; + animation: asSweepDown 3s linear infinite; + border-color: rgba(251,191,36,0.28); + box-shadow: + 0 8px 32px rgba(0,0,0,0.25), + 0 2px 8px rgba(0,0,0,0.15), + inset 0 1px 0 rgba(255,255,255,0.08); + } + + /* Shimmer animation from top to bottom */ + @keyframes asSweepDown { + 0% { background-position: 0% 200%; } + 100% { background-position: 0% -200%; } + } + + /* On quest page, sidebar stays visible above content */ + .as-sidebar-container.quest-mode { + z-index: 40; + } + + .as-sidebar-inner { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + height: 100%; + } + + .as-gradient-overlay { + position: absolute; + inset: 0; + pointer-events: none; + z-index: 0; + } + + .as-gradient-overlay.default { + background: radial-gradient( + circle at top, + rgba(168,85,247,0.18), + transparent 55% + ), + radial-gradient( + circle at bottom, + rgba(249,115,22,0.1), + transparent 55% + ); + } + + .as-gradient-overlay.quest { + background: transparent; + } + + /* Ensure Sidebar sub-components are transparent */ + .as-sidebar-inner > * { + background: transparent; + } + + .as-sidebar-inner [class*="SidebarHeader"], + .as-sidebar-inner [class*="SidebarContent"], + .as-sidebar-inner [class*="SidebarFooter"], + .as-sidebar-inner [class*="SidebarGroup"], + .as-sidebar-inner [class*="SidebarMenu"] { + background: transparent; + } + + /* Quest mode text visibility */ + .as-sidebar-container.quest-mode [class*="SidebarGroupLabel"] { + color: rgba(255, 255, 255, 0.4) !important; + } + + .as-sidebar-container.quest-mode a { + color: rgba(255, 255, 255, 0.6) !important; + background: transparent !important; + } + + .as-sidebar-container.quest-mode a:hover { + color: rgba(255, 255, 255, 0.85) !important; + background: rgba(255, 255, 255, 0.08) !important; + } + + .as-sidebar-container.quest-mode a.active { + color: #fbbf24 !important; + } + + .as-sidebar-container.quest-mode span { + color: inherit; + } + + /* Quest header text */ + .as-sidebar-container.quest-mode .text-slate-900 { + color: rgba(255, 255, 255, 0.9) !important; + } + + .as-sidebar-container.quest-mode .text-slate-400 { + color: rgba(255, 255, 255, 0.4) !important; + } + + /* Quest mode removes white hover background from menu buttons */ + .as-sidebar-container.quest-mode [class*="SidebarMenuButton"]:hover { + background: transparent !important; + } + + .as-sidebar-container.quest-mode [class*="SidebarMenuButton"] { + background: transparent !important; + } + + /* Prevent group-hover from adding white background in quest mode */ + .as-sidebar-container.quest-mode .group:hover { + background: transparent !important; + } + + /* Quest mode footer button styling */ + .as-sidebar-container.quest-mode [class*="SidebarFooter"] button { + background: rgba(255, 255, 255, 0.08) !important; + --tw-ring-color: rgba(255, 255, 255, 0.05) !important; + border-color: rgba(255, 255, 255, 0.05) !important; + } + + .as-sidebar-container.quest-mode [class*="SidebarFooter"] button:hover { + background: rgba(255, 255, 255, 0.12) !important; + } + + /* Override Tailwind bg-white and ring classes for quest mode */ + .as-sidebar-container.quest-mode button[class*="bg-white"] { + background-color: rgba(255, 255, 255, 0.08) !important; + } + + .as-sidebar-container.quest-mode button[class*="ring-white"]:not(:hover) { + --tw-ring-color: rgba(255, 255, 255, 0.05) !important; + border-color: rgba(255, 255, 255, 0.05) !important; + } + + .as-sidebar-container.quest-mode button:hover[class*="hover:bg-white"] { + background-color: rgba(255, 255, 255, 0.12) !important; + } + + .as-sidebar-container.quest-mode a:hover { + --tw-ring-color: rgba(255, 255, 255, 0.05) !important; + } + `; return ( - - {/* HEADER */} - -
-
-
- Logo -
+ <> + +
+
-
- - Edbridge Scholars - - - Student - -
-
- -
- - - {/* CONTENT */} - - - - Platform - - - - - - - isActive - ? "bg-zinc-800 text-white" - : "text-zinc-400 hover:bg-zinc-800" - } - > - - Home - - - - - - setOpen(!open)} - > -
- - Practice - - + {/* HEADER */} + +
+
+
+ Logo
- - {open && ( - - - - - Practice your way - - - - - - Targeted Practice - - +
+ + Edbridge Scholars + + + Student + +
+
+
+
- + + + PLATFORM + + + + {/* HOME */} + + - - Drills - - + `flex items-center gap-2.5 text-sm font-satoshi rounded-2xl px-2 py-2.5 transition-all duration-200 ${ + isActive + ? "text-slate-900" + : "text-slate-500 group-hover:text-slate-900" + }` + } + > + {({ isActive }) => ( + <> + + + Home + + + )} + + + + + {/* PRACTICE */} + setOpen(true)} + onMouseLeave={() => setOpen(false)} + > + - - - Hard Test Modules - - - - )} - + + `flex items-center gap-2.5 text-sm font-satoshi rounded-2xl px-2 py-2.5 transition-all duration-200 ${ + isActive + ? "text-slate-900" + : "text-slate-500 group-hover:text-slate-900" + }` + } + > + {({ isActive }) => ( + <> + + + Practice + + + + )} + + + {open && ( + + + `flex items-center gap-2.5 rounded-2xl px-2 py-2 text-sm font-satoshi transition-colors duration-200 ${ + isActive + ? "bg-white text-slate-900" + : "text-slate-500 hover:bg-white hover:text-slate-900" + }` + } + > + + Targeted Practice + + + `flex items-center gap-2.5 rounded-2xl px-2 py-2 text-sm font-satoshi transition-colors duration-200 ${ + isActive + ? "bg-white text-slate-900" + : "text-slate-500 hover:bg-white hover:text-slate-900" + }` + } + > + + Drills + + + `flex items-center gap-2.5 rounded-2xl px-2 py-2 text-sm font-satoshi transition-colors duration-200 ${ + isActive + ? "bg-white text-slate-900" + : "text-slate-500 hover:bg-white hover:text-slate-900" + }` + } + > + + Hard Test Modules + + + )} + - {/* DOCS */} - - - isActive - ? "bg-zinc-800 text-white" - : "text-zinc-400 hover:bg-zinc-800" - } - > - - - - + {/* QUESTS */} + + + { + if (isActive && isQuestPage) { + return "flex items-center gap-2.5 text-sm rounded-2xl px-2 py-2.5 transition-all duration-200"; + } + if (isActive) { + return "flex items-center gap-2.5 text-sm font-satoshi rounded-2xl px-2 py-2.5 transition-all duration-200 text-slate-900"; + } + return "flex items-center gap-2.5 text-sm font-satoshi rounded-2xl px-2 py-2.5 transition-all duration-200 text-slate-500 group-hover:text-slate-900"; + }} + > + {({ isActive }) => ( + <> + + + Quests + + + )} + + + - {/* SETTINGS */} - - - isActive - ? "bg-zinc-800 text-white" - : "text-zinc-400 hover:bg-zinc-800" - } - > - - - Rewards - - - - - - isActive - ? "bg-zinc-800 text-white" - : "text-zinc-400 hover:bg-zinc-800" - } - > - - - Profile - - - - - - + {/* LESSONS */} + + + + `flex items-center gap-2.5 text-sm font-satoshi rounded-2xl px-2 py-2.5 transition-all duration-200 ${ + isActive + ? "text-slate-900" + : "text-slate-500 group-hover:text-slate-900" + }` + } + > + {({ isActive }) => ( + <> + + + Lessons + + + )} + + + - {/* FOOTER */} - -
- - - - {user?.name.slice(0, 1)} - - -
- {user?.name} - {user?.email} -
- + {/* REWARDS */} + + + + `flex items-center gap-2.5 text-sm font-satoshi rounded-2xl px-2 py-2.5 transition-all duration-200 ${ + isActive + ? "text-slate-900" + : "text-slate-500 group-hover:text-slate-900" + }` + } + > + {({ isActive }) => ( + <> + + + Rewards + + + )} + + + + + + + + {/* FOOTER – links to profile */} + + +
-
- +
+ ); } diff --git a/src/components/Calculator.tsx b/src/components/Calculator.tsx new file mode 100644 index 0000000..b343f49 --- /dev/null +++ b/src/components/Calculator.tsx @@ -0,0 +1,250 @@ +import { useEffect, useRef, useState } from "react"; +import { createPortal } from "react-dom"; +import { X, Calculator, Maximize2, Minimize2 } from "lucide-react"; + +// ─── GeoGebra type shim ─────────────────────────────────────────────────────── +declare global { + interface Window { + GGBApplet: new ( + params: Record, + defer?: boolean, + ) => { + inject: (containerId: string) => void; + }; + ggbApplet?: { + reset: () => void; + setXML: (xml: string) => void; + }; + } +} + +// ─── Hook: load GeoGebra script once ───────────────────────────────────────── +const GEOGEBRA_SCRIPT = "https://www.geogebra.org/apps/deployggb.js"; + +const useGeoGebraScript = () => { + const [ready, setReady] = useState(false); + + useEffect(() => { + if (document.querySelector(`script[src="${GEOGEBRA_SCRIPT}"]`)) { + if (window.GGBApplet) setReady(true); + return; + } + const script = document.createElement("script"); + script.src = GEOGEBRA_SCRIPT; + script.async = true; + script.onload = () => setReady(true); + document.head.appendChild(script); + }, []); + + return ready; +}; + +// ─── GeoGebra Calculator ────────────────────────────────────────────────────── +const GeoGebraCalculator = ({ containerId }: { containerId: string }) => { + const scriptReady = useGeoGebraScript(); + const injected = useRef(false); + const wrapperRef = useRef(null); + const [dims, setDims] = useState<{ w: number; h: number } | null>(null); + + // Measure the wrapper first — GeoGebra needs explicit px dimensions + useEffect(() => { + const el = wrapperRef.current; + if (!el) return; + const ro = new ResizeObserver((entries) => { + for (const entry of entries) { + const { width, height } = entry.contentRect; + if (width > 0 && height > 0) { + setDims({ w: Math.floor(width), h: Math.floor(height) }); + } + } + }); + ro.observe(el); + return () => ro.disconnect(); + }, []); + + useEffect(() => { + if (!scriptReady || !dims || injected.current) return; + injected.current = true; + + const params = { + appName: "graphing", + width: dims.w, + height: dims.h, + showToolBar: true, + showAlgebraInput: true, + showMenuBar: false, + enableLabelDrags: true, + enableShiftDragZoom: true, + enableRightClick: true, + showZoomButtons: true, + capturingThreshold: null, + showFullscreenButton: false, + + scale: 1, + disableAutoScale: false, + allowUpscale: false, + clickToLoad: false, + appletOnLoad: () => {}, + useBrowserForJS: false, + showLogging: false, + errorDialogsActive: true, + showTutorialLink: false, + showSuggestionButtons: false, + language: "en", + id: "ggbApplet", + }; + + try { + const applet = new window.GGBApplet(params, true); + applet.inject(containerId); + } catch (e) { + console.error("GeoGebra init error:", e); + } + }, [scriptReady, dims, containerId]); + + return ( +
+ {!dims && ( +
+ + + + + Loading calculator... +
+ )} +
+
+ ); +}; + +// ─── Modal ──────────────────────────────────────────────────────────────────── +interface GraphCalculatorModalProps { + open: boolean; + onClose: () => void; +} + +const GraphCalculatorModal = ({ open, onClose }: GraphCalculatorModalProps) => { + const [fullscreen, setFullscreen] = useState(false); + const containerId = "geogebra-container"; + + // Trap focus & keyboard dismiss + useEffect(() => { + if (!open) return; + const onKey = (e: KeyboardEvent) => { + if (e.key === "Escape") onClose(); + }; + window.addEventListener("keydown", onKey); + return () => window.removeEventListener("keydown", onKey); + }, [open, onClose]); + + // Prevent body scroll while open + useEffect(() => { + document.body.style.overflow = open ? "hidden" : ""; + return () => { + document.body.style.overflow = ""; + }; + }, [open]); + + if (!open) return null; + + return createPortal( +
+ {/* Backdrop */} +
+ + {/* Panel */} +
e.stopPropagation()} + > + {/* Header */} +
+
+
+ +
+ + Graph Calculator + + + Powered by GeoGebra + +
+ +
+ + +
+
+ + {/* GeoGebra canvas area */} +
+ +
+
+
, + document.body, + ); +}; + +// ─── Trigger button + modal — drop this wherever you need it ────────────────── +export const GraphCalculatorButton = () => { + const [open, setOpen] = useState(false); + + return ( + <> + + + setOpen(false)} /> + + ); +}; + +// ─── Standalone modal export if you need to control it externally ───────────── +export { GraphCalculatorModal }; diff --git a/src/components/ChestOpenModal.tsx b/src/components/ChestOpenModal.tsx new file mode 100644 index 0000000..317ff6e --- /dev/null +++ b/src/components/ChestOpenModal.tsx @@ -0,0 +1,750 @@ +import { useState, useEffect, useRef } from "react"; +import type { QuestNode, ClaimedRewardResponse } from "../types/quest"; + +// ─── Styles ─────────────────────────────────────────────────────────────────── +const S = ` + @import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@700;900&family=Nunito:wght@800;900&display=swap'); + + /* ══ FULL SCREEN OVERLAY ══ */ + .com-overlay { + position:fixed; inset:0; z-index:80; + display:flex; flex-direction:column; + align-items:center; justify-content:center; + overflow:hidden; + } + + /* ── Sky/sea background that animates in ── */ + .com-bg { + position:absolute; inset:0; + background: + radial-gradient(ellipse 80% 60% at 50% 80%, rgba(0,60,120,0.9) 0%, transparent 70%), + radial-gradient(ellipse 60% 40% at 50% 20%, rgba(80,0,160,0.7) 0%, transparent 60%), + linear-gradient(180deg, #050010 0%, #0a0520 40%, #020818 100%); + animation: comBgIn 0.5s ease both; + } + @keyframes comBgIn { + from{ opacity:0; } to{ opacity:1; } + } + + /* ── Stars in background ── */ + .com-star { + position:absolute; border-radius:50%; + background:white; pointer-events:none; + animation:comStarTwinkle var(--sdur) ease-in-out infinite; + animation-delay:var(--sdelay); + } + @keyframes comStarTwinkle { + 0%,100%{ opacity:0.3; transform:scale(1); } + 50% { opacity:1; transform:scale(1.4); } + } + + /* ── Gold radial burst (appears on open) ── */ + .com-burst { + position:absolute; inset:0; + display:flex; align-items:center; justify-content:center; + pointer-events:none; z-index:2; + } + .com-burst-ring { + position:absolute; border-radius:50%; + border:3px solid rgba(251,191,36,0.6); + animation: comBurstRing var(--brdur) ease-out forwards; + animation-delay: var(--brdelay); + opacity:0; + } + @keyframes comBurstRing { + 0% { opacity:0.9; transform:scale(0.1); } + 100%{ opacity:0; transform:scale(var(--brs)); } + } + + /* ── Ray beams (crepuscular rays) ── */ + .com-rays { + position:absolute; inset:0; + display:flex; align-items:center; justify-content:center; + pointer-events:none; z-index:1; + } + .com-ray { + position:absolute; + width:3px; + height:55vh; + border-radius:100px; + background:linear-gradient(180deg,rgba(251,191,36,0.5) 0%,transparent 100%); + transform-origin:50% 100%; + bottom:50%; + left:calc(50% - 1.5px); + transform:rotate(var(--angle)) scaleY(0); + animation:comRayIn 0.6s ease-out forwards; + animation-delay:var(--raydelay); + } + @keyframes comRayIn { + 0% { transform:rotate(var(--angle)) scaleY(0); opacity:0; } + 40% { opacity:0.8; } + 100%{ transform:rotate(var(--angle)) scaleY(1); opacity:0.15; } + } + + /* ── Particle explosion ── */ + .com-particle { + position:absolute; border-radius:50%; + pointer-events:none; z-index:4; + animation:comParticleOut var(--pdur) cubic-bezier(0.25,0.8,0.35,1) forwards; + animation-delay:var(--pdelay); + opacity:0; + } + @keyframes comParticleOut { + 0% { opacity:1; transform:translate(0,0) scale(1) rotate(0deg); } + 80% { opacity:0.7; } + 100%{ opacity:0; transform:translate(var(--ptx),var(--pty)) scale(0.2) rotate(var(--prot)); } + } + + /* ── Coin emojis bursting ── */ + .com-coin { + position:absolute; + font-size:var(--csize); + pointer-events:none; z-index:4; + animation:comCoinOut var(--cdur) cubic-bezier(0.2,0.9,0.3,1) forwards; + animation-delay:var(--cdelay); + opacity:0; + } + @keyframes comCoinOut { + 0% { opacity:0; transform:translate(0,0) rotate(0deg) scale(0.3); } + 12% { opacity:1; } + 100%{ opacity:0; transform:translate(var(--ctx),var(--cty)) rotate(var(--crot)) scale(1.1); } + } + + /* ── Floating sparkles (stay on screen) ── */ + .com-sparkle { + position:absolute; pointer-events:none; z-index:3; + font-size:var(--spsize); + animation:comSparkleFloat var(--spdur) ease-in-out infinite; + animation-delay:var(--spdelay); + opacity:0.7; + } + @keyframes comSparkleFloat { + 0%,100%{ transform:translateY(0) rotate(0deg) scale(1); opacity:0.6; } + 50% { transform:translateY(-18px) rotate(180deg) scale(1.2); opacity:1; } + } + + /* ── XP number that flies up from chest ── */ + .com-xp-blast { + position:absolute; pointer-events:none; z-index:5; + top:50%; left:50%; + font-family:'Cinzel',serif; + font-size:2.6rem; font-weight:900; + color:#fbbf24; + text-shadow:0 0 30px rgba(251,191,36,1),0 0 60px rgba(251,191,36,0.7),0 0 100px rgba(251,191,36,0.3); + white-space:nowrap; + animation:comXPBlast 2s cubic-bezier(0.2,0.8,0.3,1) forwards; + } + @keyframes comXPBlast { + 0% { opacity:0; transform:translate(-50%,-40%) scale(0.4); filter:blur(4px); } + 15% { opacity:1; transform:translate(-50%,-60%) scale(1.3); filter:blur(0); } + 60% { opacity:1; transform:translate(-50%,-90%) scale(1); } + 100%{ opacity:0; transform:translate(-50%,-130%) scale(0.8); } + } + + /* ── Main card ── */ + .com-card { + position:relative; z-index:6; + width:calc(100% - 2.5rem); max-width:340px; + border-radius:28px; overflow:hidden; + display:flex; flex-direction:column; align-items:center; + padding:0; + box-shadow:0 0 80px rgba(251,191,36,0.2), 0 24px 64px rgba(0,0,0,0.7); + animation:comCardIn 0.5s cubic-bezier(0.34,1.56,0.64,1) both; + animation-delay:0.1s; + } + @keyframes comCardIn { + from{ opacity:0; transform:scale(0.8) translateY(24px); } + to { opacity:1; transform:scale(1) translateY(0); } + } + + /* Gold shimmer top border */ + .com-card::before { + content:''; position:absolute; top:0; left:0; right:0; height:2px; z-index:1; + background:linear-gradient(90deg,transparent 0%,#f59e0b 30%,#fbbf24 50%,#f59e0b 70%,transparent 100%); + background-size:200% 100%; + animation:comShimmer 2s linear infinite; + } + @keyframes comShimmer { + 0% { background-position:200% 0; } + 100%{ background-position:-200% 0; } + } + + /* Card inner bg */ + .com-card-inner { + width:100%; padding:1.75rem 1.6rem 1.6rem; + background:linear-gradient(160deg,#12083a 0%,#0c0525 60%,#090320 100%); + border:1.5px solid rgba(251,191,36,0.25); + border-radius:28px; + display:flex; flex-direction:column; align-items:center; gap:0; + } + + /* ── Phase label ── */ + .com-label { + font-family:'Cinzel',serif; + font-size:0.62rem; font-weight:700; letter-spacing:0.2em; + text-transform:uppercase; color:rgba(251,191,36,0.55); + margin-bottom:1.2rem; text-align:center; + } + + /* ── Chest area ── */ + .com-chest-area { + position:relative; width:140px; height:140px; + display:flex; align-items:center; justify-content:center; + margin-bottom:1.25rem; cursor:pointer; + } + + /* Glow platform beneath chest */ + .com-glow-pad { + position:absolute; bottom:6px; left:50%; + transform:translateX(-50%); + width:100px; height:24px; border-radius:50%; + background:radial-gradient(ellipse at center,rgba(251,191,36,0.45) 0%,transparent 70%); + animation:comGlowPad 1.8s ease-in-out infinite; + filter:blur(4px); + } + @keyframes comGlowPad { + 0%,100%{ transform:translateX(-50%) scaleX(1); opacity:0.7; } + 50% { transform:translateX(-50%) scaleX(1.2); opacity:1; } + } + + /* Orbit ring */ + .com-orbit { + position:absolute; inset:8px; border-radius:50%; + border:1.5px dashed rgba(251,191,36,0.2); + animation:comOrbit 8s linear infinite; + } + @keyframes comOrbit { from{transform:rotate(0deg);} to{transform:rotate(360deg);} } + .com-orbit-dot { + position:absolute; top:-5px; left:50%; transform:translateX(-50%); + width:8px; height:8px; border-radius:50%; + background:#fbbf24; box-shadow:0 0 10px #fbbf24; + } + + /* The chest emoji */ + .com-chest { + font-size:5.5rem; position:relative; z-index:2; + filter:drop-shadow(0 8px 20px rgba(251,191,36,0.45)); + transition:filter 0.2s; + } + .com-chest.idle { + animation:comChestIdle 3s ease-in-out infinite; + } + @keyframes comChestIdle { + 0%,100%{ transform:translateY(0) rotate(-2deg); } + 50% { transform:translateY(-6px) rotate(2deg); } + } + .com-chest.shake { + animation:comChestShake 0.55s cubic-bezier(0.36,0.07,0.19,0.97) both; + } + @keyframes comChestShake { + 0%,100%{ transform:rotate(0deg) scale(1); } + 10% { transform:rotate(-14deg) scale(1.06); } + 25% { transform:rotate(14deg) scale(1.1); } + 40% { transform:rotate(-10deg) scale(1.07); } + 55% { transform:rotate(10deg) scale(1.12); } + 70% { transform:rotate(-6deg) scale(1.06); } + 85% { transform:rotate(6deg) scale(1.04); } + } + .com-chest.opening { + animation:comChestOpen 0.5s cubic-bezier(0.34,1.56,0.64,1) both; + } + @keyframes comChestOpen { + 0% { transform:scale(0.7); filter:brightness(0.4) drop-shadow(0 8px 20px rgba(251,191,36,0.3)); } + 50% { transform:scale(1.25); filter:brightness(1.8) drop-shadow(0 0 50px rgba(251,191,36,1)); } + 100%{ transform:scale(1); filter:brightness(1) drop-shadow(0 8px 30px rgba(251,191,36,0.6)); } + } + + /* ── Tap prompt ── */ + .com-tap-title { + font-family:'Cinzel',serif; + font-size:1.2rem; font-weight:900; color:white; + text-align:center; margin-bottom:0.3rem; + animation:comPulse 1.8s ease-in-out infinite; + } + @keyframes comPulse { + 0%,100%{ opacity:1; transform:scale(1); } + 50% { opacity:0.65; transform:scale(0.97); } + } + .com-tap-sub { + font-family:'Nunito',sans-serif; + font-size:0.75rem; font-weight:800; + color:rgba(255,255,255,0.35); text-align:center; margin-bottom:1.5rem; + letter-spacing:0.06em; + } + + /* ── Shaking text ── */ + .com-shake-text { + font-family:'Cinzel',serif; + font-size:1.1rem; font-weight:900; color:#fbbf24; + text-align:center; margin-bottom:0.3rem; + animation:comShakeText 0.3s ease-in-out infinite alternate; + } + @keyframes comShakeText { + from{ transform:translateX(-3px); } + to { transform:translateX(3px); } + } + .com-shake-dots { + font-size:1.4rem; text-align:center; margin-bottom:1.5rem; + animation:comShakeText 0.25s ease-in-out infinite alternate; + } + + /* ── Reward rows ── */ + .com-rewards-title { + font-family:'Cinzel',serif; + font-size:0.65rem; font-weight:700; letter-spacing:0.18em; + text-transform:uppercase; color:rgba(251,191,36,0.5); + text-align:center; margin-bottom:0.85rem; + } + .com-rewards { display:flex; flex-direction:column; gap:0.55rem; width:100%; margin-bottom:1.1rem; } + .com-reward-row { + display:flex; align-items:center; gap:0.85rem; + padding:0.8rem 1rem; + background:rgba(255,255,255,0.04); + border:1px solid rgba(251,191,36,0.18); + border-radius:16px; + animation:comRowIn 0.5s cubic-bezier(0.34,1.56,0.64,1) both; + } + @keyframes comRowIn { + from{ opacity:0; transform:translateY(18px) scale(0.88); } + to { opacity:1; transform:translateY(0) scale(1); } + } + .com-reward-icon { font-size:1.5rem; flex-shrink:0; filter:drop-shadow(0 2px 8px rgba(251,191,36,0.5)); } + .com-reward-lbl { + font-family:'Cinzel',serif; + font-size:0.65rem; font-weight:700; letter-spacing:0.1em; text-transform:uppercase; + color:rgba(255,255,255,0.4); margin-bottom:0.12rem; + } + .com-reward-val { + font-family:'Nunito',sans-serif; + font-size:1.05rem; font-weight:900; + color:#fbbf24; + text-shadow:0 0 16px rgba(251,191,36,0.6); + } + + /* Special XP row highlight */ + .com-reward-row.xp-row { + border-color:rgba(251,191,36,0.35); + background:rgba(251,191,36,0.06); + } + + /* Loading state inside reward area */ + .com-rewards-loading { + font-family:'Cinzel',serif; + font-size:0.72rem; font-weight:700; color:rgba(251,191,36,0.4); + text-align:center; padding:1rem 0; letter-spacing:0.1em; + animation:comPulse 1.2s ease-in-out infinite; + } + + /* ── CTA button ── */ + .com-cta { + width:100%; padding:1rem; + background:linear-gradient(135deg,#fbbf24,#f59e0b); + border:none; border-radius:16px; cursor:pointer; + font-family:'Cinzel',serif; + font-size:1rem; font-weight:900; color:#1a0800; + letter-spacing:0.05em; + box-shadow:0 5px 0 #b45309, 0 8px 24px rgba(251,191,36,0.4); + transition:all 0.12s ease; + animation:comRowIn 0.5s cubic-bezier(0.34,1.56,0.64,1) both; + } + .com-cta:hover { transform:translateY(-3px); box-shadow:0 8px 0 #b45309, 0 14px 32px rgba(251,191,36,0.5); } + .com-cta:active { transform:translateY(2px); box-shadow:0 3px 0 #b45309; } + + /* ── Skip hint ── */ + .com-skip { + position:absolute; bottom:1.5rem; + font-family:'Nunito',sans-serif; + font-size:0.65rem; font-weight:700; + color:rgba(255,255,255,0.2); letter-spacing:0.1em; + text-transform:uppercase; cursor:pointer; z-index:7; + transition:color 0.2s; + } + .com-skip:hover { color:rgba(255,255,255,0.5); } +`; + +// ─── Config ─────────────────────────────────────────────────────────────────── +const PARTICLE_COLORS = [ + "#fbbf24", + "#f59e0b", + "#ef4444", + "#ec4899", + "#a855f7", + "#6366f1", + "#22d3ee", + "#4ade80", + "#fb923c", +]; +const COIN_EMOJIS = ["🪙", "💰", "✨", "⭐", "💎", "🌟", "💫", "🏅"]; +const SPARKLE_EMOJIS = ["✨", "⭐", "💫", "🌟"]; + +const RAYS = Array.from({ length: 12 }, (_, i) => ({ + id: i, + angle: `${(i / 12) * 360}deg`, + delay: `${i * 0.04}s`, +})); + +const BURST_RINGS = [ + { id: 0, size: "3", dur: "0.7s", delay: "0s" }, + { id: 1, size: "5", dur: "0.9s", delay: "0.1s" }, + { id: 2, size: "8", dur: "1.1s", delay: "0.2s" }, + { id: 3, size: "12", dur: "1.4s", delay: "0.3s" }, +]; + +const STARS = Array.from({ length: 40 }, (_, i) => ({ + id: i, + w: 1 + ((i * 7) % 3), + top: `${(i * 17 + 3) % 95}%`, + left: `${(i * 23 + 11) % 97}%`, + dur: `${2 + ((i * 3) % 4)}s`, + delay: `${(i * 7) % 3}s`, +})); + +const SPARKLES = Array.from({ length: 8 }, (_, i) => ({ + id: i, + emoji: SPARKLE_EMOJIS[i % 4], + size: `${0.9 + (i % 3) * 0.35}rem`, + top: `${10 + ((i * 12) % 75)}%`, + left: `${5 + ((i * 14) % 85)}%`, + dur: `${2 + (i % 3) * 1.2}s`, + delay: `${i * 0.3}s`, +})); + +type Phase = "idle" | "shaking" | "opening" | "revealed"; + +interface Props { + node: QuestNode; + claimResult: ClaimedRewardResponse | null; + onClose: () => void; +} + +export const ChestOpenModal = ({ claimResult, onClose }: Props) => { + const [phase, setPhase] = useState("idle"); + const [showXP, setShowXP] = useState(false); + const timerRef = useRef | null>(null); + + // Stable particle arrays computed once per mount + const particles = useRef( + Array.from({ length: 55 }, (_, i) => ({ + id: i, + color: PARTICLE_COLORS[i % PARTICLE_COLORS.length], + w: 3 + (i % 3) * 4, + tx: ((i % 2 === 0 ? 1 : -1) * (40 + i * 7)) % 200, + ty: -(30 + ((i * 11) % 190)), + rot: ((i * 23) % 720) - 360, + dur: `${0.7 + ((i * 7) % 10) / 10}s`, + delay: `${((i * 3) % 8) / 30}s`, + })), + ).current; + + const coins = useRef( + Array.from({ length: 18 }, (_, i) => ({ + id: i, + emoji: COIN_EMOJIS[i % COIN_EMOJIS.length], + size: `${1 + (i % 3) * 0.45}rem`, + tx: (i % 2 === 0 ? 1 : -1) * (30 + ((i * 9) % 180)), + ty: -(40 + ((i * 13) % 200)), + rot: ((i * 31) % 540) - 270, + dur: `${0.75 + ((i * 7) % 8) / 10}s`, + delay: `${((i * 5) % 10) / 30}s`, + })), + ).current; + + const tap = () => { + if (phase !== "idle") return; + setPhase("shaking"); + timerRef.current = setTimeout(() => { + setPhase("opening"); + setShowXP(true); + timerRef.current = setTimeout(() => { + setShowXP(false); + setPhase("revealed"); + }, 1800); + }, 650); + }; + + useEffect( + () => () => { + if (timerRef.current) clearTimeout(timerRef.current); + }, + [], + ); + + // ── Build reward rows from ClaimedRewardResponse ────────────────────────── + // claimResult may be null while the API call is in flight; we show a loading + // state in that case rather than crashing or showing stale data. + const xpAwarded = claimResult?.xp_awarded ?? 0; + + // Defensively coerce to arrays — the API may return null, a single object, + // or omit these fields entirely rather than returning an empty array. + const titlesAwarded = Array.isArray(claimResult?.title_unlocked) + ? claimResult!.title_unlocked + : claimResult?.title_unlocked + ? [claimResult.title_unlocked] + : []; + const itemsAwarded = Array.isArray(claimResult?.items_awarded) + ? claimResult!.items_awarded + : claimResult?.items_awarded + ? [claimResult.items_awarded] + : []; + + const rewards = claimResult + ? [ + // XP row — always present + { + key: "xp", + cls: "xp-row", + icon: "⚡", + lbl: "XP Gained", + val: `+${xpAwarded} XP`, + delay: "0.05s", + }, + // One row per unlocked title (usually 0 or 1) + ...titlesAwarded.map((t, i) => ({ + key: `title-${t.id}`, + cls: "", + icon: "🏴‍☠️", + lbl: "Crew Title", + val: t.name, + delay: `${0.1 + i * 0.1}s`, + })), + // One row per awarded item + ...itemsAwarded.map((inv, i) => ({ + key: `item-${inv.id}`, + cls: "", + icon: "🎁", + lbl: inv.item.type ?? "Item", + val: inv.item.name, + delay: `${0.1 + (titlesAwarded.length + i) * 0.1}s`, + })), + ] + : []; + + const chestClass = + phase === "idle" + ? "idle" + : phase === "shaking" + ? "shake" + : phase === "opening" + ? "opening" + : ""; + const chestEmoji = phase === "opening" || phase === "revealed" ? "📬" : "📦"; + + return ( +
+ + + {/* Background */} +
+ + {/* Stars */} + {STARS.map((s) => ( +
+ ))} + + {/* Crepuscular rays */} + {(phase === "opening" || phase === "revealed") && ( +
+ {RAYS.map((r) => ( +
+ ))} +
+ )} + + {/* Burst rings */} + {(phase === "opening" || phase === "revealed") && ( +
+ {BURST_RINGS.map((r) => ( +
+ ))} +
+ )} + + {/* Particle explosion */} + {(phase === "opening" || phase === "revealed") && ( + <> + {particles.map((p) => ( +
+ ))} + {coins.map((c) => ( +
+ {c.emoji} +
+ ))} + + )} + + {/* Floating sparkles in revealed state */} + {phase === "revealed" && + SPARKLES.map((sp) => ( +
+ {sp.emoji} +
+ ))} + + {/* XP blast — uses xp_awarded from claimResult */} + {showXP && ( +
+ {xpAwarded > 0 ? `+${xpAwarded} XP` : "✨"} +
+ )} + + {/* Card */} +
e.stopPropagation()}> +
+

+ {phase === "revealed" ? "⚓ Treasure Claimed" : "📦 Treasure Chest"} +

+ + {/* Chest */} +
+ {phase !== "revealed" &&
} + {phase !== "revealed" && ( +
+
+
+ )} + {chestEmoji} +
+ + {/* Phase content */} + {phase === "idle" && ( + <> +

Tap to Open!

+

YOUR HARD WORK HAS PAID OFF, PIRATE

+ + )} + + {phase === "shaking" && ( + <> +

The chest stirs...

+

⚡ ⚡ ⚡

+ + )} + + {phase === "revealed" && ( + <> +

⚓ Spoils of Victory

+
+ {/* claimResult not yet available — API still in flight */} + {!claimResult && ( +

+ ⚡ Counting your spoils... +

+ )} + {rewards.map((r) => ( +
+ {r.icon} +
+

{r.lbl}

+

{r.val}

+
+
+ ))} +
+ + + )} +
+
+ + {/* Skip link */} + {phase === "revealed" && ( +

+ tap anywhere to continue +

+ )} +
+ ); +}; diff --git a/src/components/ChoiceCard.tsx b/src/components/ChoiceCard.tsx index 0055a72..4df3019 100644 --- a/src/components/ChoiceCard.tsx +++ b/src/components/ChoiceCard.tsx @@ -1,4 +1,126 @@ -import { Badge } from "./ui/badge"; +const STYLES = ` + @import url('https://fonts.googleapis.com/css2?family=Nunito:wght@700;800;900&family=Nunito+Sans:wght@600;700&display=swap'); + + .cc-btn { + width: 100%; + background: white; + border: 2.5px solid #f3f4f6; + border-radius: 18px; + padding: 0.85rem 1rem; + text-align: left; + cursor: pointer; + display: flex; + flex-direction: column; + gap: 0.2rem; + box-shadow: 0 3px 10px rgba(0,0,0,0.04); + transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease, background 0.15s ease; + font-family: 'Nunito', sans-serif; + position: relative; + overflow: hidden; + -webkit-tap-highlight-color: transparent; + } + + .cc-btn:hover:not(.cc-selected) { + transform: translateY(-2px); + box-shadow: 0 8px 20px rgba(0,0,0,0.07); + border-color: #e5e7eb; + } + + .cc-btn:active { + transform: translateY(1px); + box-shadow: 0 2px 6px rgba(0,0,0,0.05); + } + + /* Selected state */ + .cc-btn.cc-selected { + border-color: #c4b5fd; + background: #fdf4ff; + box-shadow: 0 6px 0 #e9d5ff, 0 8px 20px rgba(168,85,247,0.1); + } + + /* Selected shimmer bar on left edge */ + .cc-btn.cc-selected::before { + content: ''; + position: absolute; + left: 0; top: 0; bottom: 0; + width: 4px; + background: linear-gradient(180deg, #a855f7, #7c3aed); + border-radius: 0 2px 2px 0; + } + + /* Top row */ + .cc-top { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + } + + .cc-label { + font-size: 0.9rem; + font-weight: 900; + color: #1e1b4b; + line-height: 1.2; + flex: 1; + transition: color 0.15s ease; + } + .cc-btn.cc-selected .cc-label { color: #7c3aed; } + + /* Section badge */ + .cc-section-badge { + font-size: 0.6rem; + font-weight: 800; + letter-spacing: 0.1em; + text-transform: uppercase; + border-radius: 100px; + padding: 0.2rem 0.6rem; + flex-shrink: 0; + border: 2px solid transparent; + } + .cc-section-badge.ebrw { + background: #eff6ff; + border-color: #bfdbfe; + color: #2563eb; + } + .cc-section-badge.math { + background: #fff1f2; + border-color: #fecdd3; + color: #e11d48; + } + + /* Sub label */ + .cc-sublabel { + font-family: 'Nunito Sans', sans-serif; + font-size: 0.75rem; + font-weight: 600; + color: #9ca3af; + line-height: 1.3; + padding-left: 0.05rem; + transition: color 0.15s ease; + } + .cc-btn.cc-selected .cc-sublabel { color: #a855f7; } + + /* Checkmark */ + .cc-check { + position: absolute; + top: 0.65rem; + right: 0.75rem; + width: 20px; height: 20px; + border-radius: 50%; + border: 2px solid #e5e7eb; + display: flex; align-items: center; justify-content: center; + flex-shrink: 0; + transition: all 0.2s cubic-bezier(0.34,1.56,0.64,1); + background: white; + } + .cc-btn.cc-selected .cc-check { + background: #a855f7; + border-color: #a855f7; + transform: scale(1.1); + } +`; + +let stylesInjected = false; export const ChoiceCard = ({ label, @@ -12,23 +134,51 @@ export const ChoiceCard = ({ subLabel?: string; section?: string; onClick: () => void; -}) => ( - -); +}) => { + if (!stylesInjected) { + const tag = document.createElement("style"); + tag.textContent = STYLES; + document.head.appendChild(tag); + stylesInjected = true; + } + + const sectionClass = + section === "EBRW" + ? "ebrw" + : section === "Math" || section === "MATH" + ? "math" + : ""; + + return ( + + ); +}; diff --git a/src/components/CircularLevelProgress.tsx b/src/components/CircularLevelProgress.tsx index f080c0a..0d64073 100644 --- a/src/components/CircularLevelProgress.tsx +++ b/src/components/CircularLevelProgress.tsx @@ -11,26 +11,187 @@ type Props = { level: number; }; +const STYLES = ` + @import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;800;900&family=Nunito+Sans:wght@400;600&display=swap'); + + .clp-wrap { + width: 100%; + font-family: 'Nunito', sans-serif; + } + + /* Outer card — full width */ + .clp-card { + width: 100%; + background: white; + border: 2.5px solid #f3f4f6; + border-radius: 24px; + padding: 1.25rem 1.5rem; + box-shadow: 0 6px 24px rgba(0,0,0,0.05); + display: flex; + flex-direction: column; + gap: 0.85rem; + box-sizing: border-box; + } + + /* Top row: level badge + XP gained chip */ + .clp-top-row { + display: flex; + align-items: center; + justify-content: space-between; + } + + .clp-level-badge { + display: flex; + align-items: center; + gap: 0.6rem; + } + + .clp-level-bubble { + width: 52px; height: 52px; + border-radius: 50%; + background: linear-gradient(135deg, #c084fc, #a855f7); + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 4px 0 #7e22ce44; + flex-shrink: 0; + } + + .clp-level-num { + font-size: 1.5rem; + font-weight: 900; + color: white; + line-height: 1; + letter-spacing: -0.02em; + } + + .clp-level-text { + display: flex; + flex-direction: column; + gap: 1px; + } + + .clp-level-word { + font-size: 0.62rem; + font-weight: 800; + letter-spacing: 0.14em; + text-transform: uppercase; + color: #9ca3af; + } + + .clp-level-title { + font-size: 1rem; + font-weight: 900; + color: #1e1b4b; + line-height: 1; + } + + /* XP gained chip */ + .clp-xp-chip { + display: flex; + align-items: center; + gap: 0.35rem; + background: #fff7ed; + border: 2px solid #fed7aa; + border-radius: 100px; + padding: 0.4rem 0.9rem; + font-size: 0.82rem; + font-weight: 800; + color: #f97316; + } + + /* Bar section */ + .clp-bar-wrap { + width: 100%; + display: flex; + flex-direction: column; + gap: 0.4rem; + } + + .clp-bar-labels { + display: flex; + justify-content: space-between; + font-size: 0.66rem; + font-weight: 700; + color: #9ca3af; + } + + .clp-bar-track { + width: 100%; + height: 12px; + background: #f3f4f6; + border-radius: 100px; + overflow: hidden; + } + + .clp-bar-fill { + height: 100%; + border-radius: 100px; + background: linear-gradient(90deg, #c084fc, #f97316); + transition: width 1.2s cubic-bezier(0.4,0,0.2,1); + } + + /* XP total */ + .clp-xp-pill { + display: flex; + align-items: center; + gap: 0.4rem; + font-size: 0.72rem; + font-weight: 700; + color: #9ca3af; + animation: clpFadeUp 0.5s cubic-bezier(0.34,1.56,0.64,1) both; + } + + .clp-xp-pill .xp-dot { + width: 7px; height: 7px; + border-radius: 50%; + background: #f97316; + flex-shrink: 0; + } + + /* Level-up banner */ + .clp-levelup { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + background: #fdf4ff; + border: 2.5px solid #e9d5ff; + border-radius: 14px; + padding: 0.6rem 1rem; + font-size: 0.85rem; + font-weight: 900; + color: #9333ea; + animation: clpPop 0.45s cubic-bezier(0.34,1.56,0.64,1) both; + box-shadow: 0 4px 12px rgba(147,51,234,0.1); + } + + @keyframes clpPop { + from { opacity:0; transform: scale(0.8); } + to { opacity:1; transform: scale(1); } + } + @keyframes clpFadeUp { + from { opacity:0; transform: translateY(6px); } + to { opacity:1; transform: translateY(0); } + } +`; + export const CircularLevelProgress = ({ - size = 300, - strokeWidth = 16, previousXP, gainedXP, levelMinXP, levelMaxXP, level, }: Props) => { - const radius = (size - strokeWidth) / 2; - const circumference = 2 * Math.PI * radius; const levelRange = levelMaxXP - levelMinXP; const normalize = (xp: number) => Math.min(Math.max(xp - levelMinXP, 0), levelRange) / levelRange; - const [progress, setProgress] = useState(normalize(previousXP)); + const [barProgress, setBarProgress] = useState(normalize(previousXP)); const [currentLevel, setCurrentLevel] = useState(level); const [showLevelUp, setShowLevelUp] = useState(false); - const [showThresholdText, setShowThresholdText] = useState(false); + const [showXPTotal, setShowXPTotal] = useState(false); useEffect(() => { let animationFrame: number; @@ -38,28 +199,23 @@ export const CircularLevelProgress = ({ const availableXP = previousXP + gainedXP; const crossesLevel = availableXP >= levelMaxXP; - - const phase1Target = crossesLevel ? 1 : normalize(previousXP + gainedXP); - + const phase1Target = crossesLevel ? 1 : normalize(availableXP); const leftoverXP = crossesLevel ? availableXP - levelMaxXP : 0; - const duration = 1200; const animatePhase1 = (timestamp: number) => { if (!start) start = timestamp; const t = Math.min((timestamp - start) / duration, 1); - - setProgress( + setBarProgress( normalize(previousXP) + t * (phase1Target - normalize(previousXP)), ); - if (t < 1) { animationFrame = requestAnimationFrame(animatePhase1); } else if (crossesLevel) { setShowLevelUp(true); setTimeout(startPhase2, 1200); } else { - setShowThresholdText(true); + setShowXPTotal(true); } }; @@ -67,78 +223,77 @@ export const CircularLevelProgress = ({ start = null; setShowLevelUp(false); setCurrentLevel((l) => l + 1); - setProgress(0); - + setBarProgress(0); const target = Math.min(leftoverXP / levelRange, 1); const animatePhase2 = (timestamp: number) => { if (!start) start = timestamp; const t = Math.min((timestamp - start) / duration, 1); - - setProgress(t * target); - + setBarProgress(t * target); if (t < 1) { animationFrame = requestAnimationFrame(animatePhase2); } else { - setShowThresholdText(true); + setShowXPTotal(true); } }; - animationFrame = requestAnimationFrame(animatePhase2); }; animationFrame = requestAnimationFrame(animatePhase1); - return () => cancelAnimationFrame(animationFrame); }, []); - const offset = circumference * (1 - progress); + const barPct = Math.round(barProgress * 100); + const totalXP = previousXP + gainedXP; return ( -
+
+ {showLevelUp && } -
- - - - - - {currentLevel} +
+ {/* Top row */} +
+
+
+ {currentLevel} +
+
+ Current Level + Level {currentLevel} +
+
- {showThresholdText && ( - - Total XP: {previousXP + gainedXP} - - )} +
⚡ +{gainedXP} XP
+
- {showLevelUp && ( - - 🎉 You leveled up! - - )} - + {/* Progress bar */} +
+
+ {levelMinXP} XP + {barPct}% + {levelMaxXP} XP +
+
+
+
+
+ + {/* Footer state */} + {showLevelUp && ( +
+ 🎉 You leveled up! Welcome to Level {currentLevel}! +
+ )} + {showXPTotal && !showLevelUp && ( +
+
+ Total XP:{" "} + + {totalXP} + +
+ )}
); diff --git a/src/components/FetchLessonPage.tsx b/src/components/FetchLessonPage.tsx new file mode 100644 index 0000000..9a70c2e --- /dev/null +++ b/src/components/FetchLessonPage.tsx @@ -0,0 +1,178 @@ +// lessonRegistry.tsx + +import { lazy, type ComponentType } from "react"; +// lessonTypes.ts + +export type LessonId = + // ---- EBRW ---- + | "ebrw-words-in-context" + | "ebrw-text-structure-purpose" + | "ebrw-cross-text-connections" + | "ebrw-central-ideas-details" + | "ebrw-inferences" + | "ebrw-command-of-evidence" + | "ebrw-boundaries" + | "ebrw-form-structure-sense" + | "ebrw-transitions" + | "ebrw-rhetorical-synthesis" + + // ---- MATH ---- + | "alg-linear-eq-1var" + | "alg-linear-eq-2var" + | "alg-linear-functions" + | "alg-systems" + | "alg-linear-inequalities" + | "adv-equivalent-expr" + | "adv-nonlinear-eq" + | "adv-systems-2var" + | "adv-nonlinear-func" + | "data-ratios-rates" + | "data-percentages" + | "data-one-var" + | "data-two-var" + | "data-probability" + | "data-sample-stats" + | "data-eval-claims" + | "geom-area-volume" + | "geom-lines-angles" + | "geom-right-tri-trig" + | "geom-circles"; + +// ---- EBRW ---- +const EBRWWordsInContext = lazy( + () => import("../pages/student/lessons/EBRWWordsInContextLesson"), +); + +const EBRWTextStructurePurpose = lazy( + () => import("../pages/student/lessons/EBRWTextStructurePurposeLesson"), +); + +const EBRWCrossText = lazy( + () => import("../pages/student/lessons/EBRWCrossTextLesson"), +); + +const EBRWCentralIdeas = lazy( + () => import("../pages/student/lessons/EBRWCentralIdeasLesson"), +); + +const EBRWInferences = lazy( + () => import("../pages/student/lessons/EBRWInferencesLesson"), +); + +const EBRWCommandEvidence = lazy( + () => import("../pages/student/lessons/EBRWCommandEvidenceLesson"), +); + +const EBRWBoundaries = lazy( + () => import("../pages/student/lessons/EBRWBoundariesLesson"), +); + +const EBRWFormStructureSense = lazy( + () => import("../pages/student/lessons/EBRWFormStructureSenseLesson"), +); + +const EBRWTransitions = lazy( + () => import("../pages/student/lessons/EBRWTransitionsLesson"), +); + +const EBRWRhetoricalSynthesis = lazy( + () => import("../pages/student/lessons/EBRWRhetoricalSynthesisLesson"), +); +// ---- MATH ---- +const AlgLinearEq1Var = lazy( + () => import("../pages/student/lessons/LinearEq1VarLesson"), +); +const AlgLinearEq2Var = lazy( + () => import("../pages/student/lessons/LinearEq2VarLesson"), +); +const AlgLinearFunctions = lazy( + () => import("../pages/student/lessons/LinearFunctionsLesson"), +); +const AlgSystems = lazy( + () => import("../pages/student/lessons/SystemsEquationsLesson"), +); +const AlgLinearInequalities = lazy( + () => import("../pages/student/lessons/LinearInequalitiesLesson"), +); +const AdvEquivalentExpr = lazy( + () => import("../pages/student/lessons/EquivalentExpressionsLesson"), +); +const AdvNonlinearEq = lazy( + () => import("../pages/student/lessons/NonlinearEq1VarLesson"), +); +const AdvSystems2Var = lazy( + () => import("../pages/student/lessons/SystemsEq2VarLesson"), +); +const AdvNonlinearFunc = lazy( + () => import("../pages/student/lessons/NonlinearFunctionsLesson"), +); +const DataRatiosRates = lazy( + () => import("../pages/student/lessons/RatiosRatesLesson"), +); +const DataPercentages = lazy( + () => import("../pages/student/lessons/PercentagesLesson"), +); +const DataOneVar = lazy( + () => import("../pages/student/lessons/OneVariableDataLesson"), +); +const DataTwoVar = lazy( + () => import("../pages/student/lessons/TwoVariableDataLesson"), +); +const DataProbability = lazy( + () => import("../pages/student/lessons/ProbabilityLesson"), +); +const DataSampleStats = lazy( + () => import("../pages/student/lessons/SampleStatsLesson"), +); +const DataEvalClaims = lazy( + () => import("../pages/student/lessons/EvalStatisticalClaimsLesson"), +); +const GeomAreaVolume = lazy( + () => import("../pages/student/lessons/AreaVolumeLesson"), +); +const GeomLinesAngles = lazy( + () => import("../pages/student/lessons/LinesAnglesLesson"), +); +const GeomRightTriTrig = lazy( + () => import("../pages/student/lessons/RightTrianglesTrigLesson"), +); +const GeomCircles = lazy( + () => import("../pages/student/lessons/CirclesLesson"), +); + +// ---- Registry Map ---- +export const LESSON_COMPONENT_MAP: Record = { + // ---- EBRW ---- + "ebrw-words-in-context": EBRWWordsInContext, + "ebrw-text-structure-purpose": EBRWTextStructurePurpose, + "ebrw-cross-text-connections": EBRWCrossText, + "ebrw-central-ideas-details": EBRWCentralIdeas, + "ebrw-inferences": EBRWInferences, + "ebrw-command-of-evidence": EBRWCommandEvidence, + "ebrw-boundaries": EBRWBoundaries, + "ebrw-form-structure-sense": EBRWFormStructureSense, + "ebrw-transitions": EBRWTransitions, + "ebrw-rhetorical-synthesis": EBRWRhetoricalSynthesis, + + // ---- MATH ---- + "alg-linear-eq-1var": AlgLinearEq1Var, + "alg-linear-eq-2var": AlgLinearEq2Var, + "alg-linear-functions": AlgLinearFunctions, + "alg-systems": AlgSystems, + "alg-linear-inequalities": AlgLinearInequalities, + "adv-equivalent-expr": AdvEquivalentExpr, + "adv-nonlinear-eq": AdvNonlinearEq, + "adv-systems-2var": AdvSystems2Var, + "adv-nonlinear-func": AdvNonlinearFunc, + "data-ratios-rates": DataRatiosRates, + "data-percentages": DataPercentages, + "data-one-var": DataOneVar, + "data-two-var": DataTwoVar, + "data-probability": DataProbability, + "data-sample-stats": DataSampleStats, + "data-eval-claims": DataEvalClaims, + "geom-area-volume": GeomAreaVolume, + "geom-lines-angles": GeomLinesAngles, + "geom-right-tri-trig": GeomRightTriTrig, + "geom-circles": GeomCircles, +}; diff --git a/src/components/GeoGebraGraph.tsx b/src/components/GeoGebraGraph.tsx deleted file mode 100644 index a89fc61..0000000 --- a/src/components/GeoGebraGraph.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { useEffect, useRef } from "react"; - -declare global { - interface Window { - GGBApplet: any; - } -} - -interface GraphProps { - width?: string; - height?: string; - commands?: string[]; - defaultZoom?: number; -} - -export function Graph({ - width = "w-full", - height = "h-30", - commands = [], - defaultZoom = 1, -}: GraphProps) { - const containerRef = useRef(null); - const appRef = useRef(null); - - useEffect(() => { - if (!(window as any).GGBApplet) { - console.error("GeoGebra library not loaded"); - return; - } - - const applet = new window.GGBApplet( - { - appName: "graphing", - width: 480, - height: 320, - scale: 1.4, - - showToolBar: false, - showAlgebraInput: false, - showMenuBar: false, - showResetIcon: false, - - enableRightClick: false, - enableLabelDrags: false, - enableShiftDragZoom: true, - showZoomButtons: true, - - appletOnLoad(api: any) { - appRef.current = api; - - api.setPerspective("G"); - api.setMode(0); - api.setAxesVisible(true, true); - api.setGridVisible(true); - - api.setCoordSystem(-5, 5, -5, 5); - - commands.forEach((command, i) => { - const name = `f${i}`; - api.evalCommand(`${name}: ${command}`); - api.setFixed(name, true); - }); - - // Inside appletOnLoad: - }, - }, - true, - ); - - applet.inject("ggb-container"); - }, [commands, defaultZoom]); - - useEffect(() => { - const resize = () => { - if (!containerRef.current || !appRef.current) return; - appRef.current.setSize( - containerRef.current.offsetWidth, - containerRef.current.offsetHeight, - ); - }; - - window.addEventListener("resize", resize); - resize(); // initial resize - - return () => window.removeEventListener("resize", resize); - }, []); - - return ( -
-
-
- ); -} diff --git a/src/components/InfoHeader.tsx b/src/components/InfoHeader.tsx new file mode 100644 index 0000000..dfb2338 --- /dev/null +++ b/src/components/InfoHeader.tsx @@ -0,0 +1,904 @@ +import { useEffect, useRef, useState } from "react"; +import { ChevronDown, ChevronRight, Gauge, Map } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { useAuthStore } from "../stores/authStore"; +import { + useQuestStore, + getQuestSummary, + getCrewRank, +} from "../stores/useQuestStore"; +import type { + QuestNode, + QuestArc, + ClaimedRewardResponse, +} from "../types/quest"; +import { CREW_RANKS } from "../types/quest"; +import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar"; +import { Drawer, DrawerContent, DrawerTrigger } from "./ui/drawer"; +import { PredictedScoreCard } from "./PredictedScoreCard"; +import { ChestOpenModal } from "./ChestOpenModal"; +import { generateArcTheme } from "../pages/student/QuestMap"; +import { InventoryButton } from "./InventoryButton"; + +// ─── Requirement helpers ────────────────────────────────────────────────────── +const REQ_EMOJI: Record = { + questions: "❓", + accuracy: "🎯", + streak: "🔥", + sessions: "📚", + topics: "🗺️", + xp: "⚡", + leaderboard: "🏆", +}; + +const REQ_LABEL: Record = { + questions: "questions answered", + accuracy: "% accuracy", + streak: "day streak", + sessions: "sessions", + topics: "topics covered", + xp: "XP earned", + leaderboard: "leaderboard rank", +}; + +// ─── Styles ─────────────────────────────────────────────────────────────────── +const STYLES = ` + @import url('https://fonts.googleapis.com/css2?family=Nunito:wght@700;800;900&family=Nunito+Sans:wght@400;600;700&family=Cinzel:wght@700;900&display=swap'); + + /* ════ SHARED ANIMATION ════ */ + @keyframes hcIn { + from { opacity:0; transform:translateY(10px) scale(0.97); } + to { opacity:1; transform:translateY(0) scale(1); } + } + + /* ════ WHITE CARD (DEFAULT / LEVEL / QUEST_COMPACT) ════ */ + .hc-card { + background: white; + border: 2.5px solid #f3f4f6; + border-radius: 26px; + box-shadow: 0 4px 20px rgba(0,0,0,0.06); + overflow: hidden; + animation: hcIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both; + } + + /* Identity */ + .hc-top { + display: flex; align-items: center; + justify-content: space-between; gap: 0.75rem; + padding: 1.1rem 1.2rem 0.9rem; + } + .hc-identity { display: flex; align-items: center; gap: 0.7rem; flex: 1; min-width: 0; } + .hc-av-wrap { position: relative; flex-shrink: 0; } + .hc-av-pip { + position: absolute; bottom: -3px; right: -3px; + min-width: 18px; height: 18px; border-radius: 9px; padding: 0 4px; + background: linear-gradient(135deg, #a855f7, #7c3aed); + border: 2px solid white; + display: flex; align-items: center; justify-content: center; + font-family: 'Nunito', sans-serif; + font-size: 0.55rem; font-weight: 900; color: white; + } + .hc-nameblock { flex: 1; min-width: 0; } + .hc-greeting { + font-family: 'Nunito', sans-serif; + font-size: 0.98rem; font-weight: 900; color: #1e1b4b; + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.2; + } + .hc-greeting em { font-style: normal; color: #a855f7; } + .hc-role { + font-family: 'Nunito Sans', sans-serif; + font-size: 0.63rem; font-weight: 700; letter-spacing: 0.09em; + text-transform: uppercase; color: #9ca3af; margin-top: 0.05rem; + } + .hc-score-btn { + display: flex; align-items: center; gap: 0.3rem; + background: #f7ffe4; border: 2px solid #d9f99d; border-radius: 100px; + padding: 0.42rem 0.72rem; font-family: 'Nunito', sans-serif; + font-size: 0.76rem; font-weight: 800; color: #65a30d; + cursor: pointer; flex-shrink: 0; + transition: transform 0.15s, box-shadow 0.15s; + box-shadow: 0 2px 8px rgba(0,0,0,0.04); + } + .hc-score-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.07); } + .hc-sep { height: 1px; margin: 0 1.2rem; background: #f3f4f6; } + + /* XP bar */ + .hc-xp-row { display: flex; align-items: center; gap: 0.75rem; padding: 0.85rem 1.2rem; } + .hc-lvl-tag { + font-family: 'Nunito', sans-serif; font-size: 0.7rem; font-weight: 900; + color: #a855f7; flex-shrink: 0; background: #f3e8ff; + border-radius: 8px; padding: 0.22rem 0.5rem; white-space: nowrap; + } + .hc-bar-wrap { flex: 1; display: flex; flex-direction: column; gap: 0.22rem; } + .hc-track { height: 8px; background: #f3f4f6; border-radius: 100px; overflow: hidden; } + .hc-fill { + height: 100%; border-radius: 100px; + background: linear-gradient(90deg, #a855f7, #f97316); + transition: width 1.1s cubic-bezier(0.34,1.56,0.64,1); + position: relative; overflow: hidden; + } + .hc-fill::after { + content: ''; position: absolute; inset: 0; + background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent); + transform: translateX(-100%); + animation: hcShimmer 2.6s ease-in-out 1s infinite; + } + @keyframes hcShimmer { to { transform: translateX(200%); } } + .hc-xp-label { + font-family: 'Nunito Sans', sans-serif; + font-size: 0.6rem; font-weight: 700; color: #9ca3af; + display: flex; justify-content: space-between; + } + .hc-xp-label span:first-child { color: #a855f7; font-weight: 900; } + + /* Rank row (compact) */ + .hc-rank-row { + display: flex; align-items: center; gap: 0.6rem; + padding: 0.75rem 1.2rem; cursor: pointer; + transition: background 0.15s; border-top: 1px solid #f3f4f6; + } + .hc-rank-row:first-child { border-top: none; } + .hc-rank-row:hover { background: #fafafa; } + .hc-rank-emoji { font-size: 1.15rem; flex-shrink: 0; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1)); } + .hc-rank-text { flex: 1; min-width: 0; } + .hc-rank-name { + font-family: 'Cinzel', serif; font-size: 0.8rem; font-weight: 700; color: #1e1b4b; + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + } + .hc-rank-progress-label { + font-family: 'Nunito Sans', sans-serif; font-size: 0.58rem; font-weight: 700; + color: #9ca3af; margin-top: 0.08rem; + } + .hc-rank-right { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; } + .hc-streak-pill { + display: flex; align-items: center; gap: 0.22rem; + background: #fff5f5; border: 1.5px solid #fecaca; border-radius: 100px; + padding: 0.2rem 0.5rem; font-family: 'Nunito', sans-serif; + font-size: 0.7rem; font-weight: 900; color: #ef4444; + } + .hc-chest-badge { + display: flex; align-items: center; gap: 0.18rem; + background: #fef3c7; border: 1.5px solid #fde68a; border-radius: 100px; + padding: 0.2rem 0.5rem; font-family: 'Nunito', sans-serif; + font-size: 0.7rem; font-weight: 900; color: #b45309; + animation: hcPop 1.8s ease-in-out infinite; + } + @keyframes hcPop { 0%,100%{transform:scale(1);} 50%{transform:scale(1.07);} } + .hc-chevron { color: #d1d5db; transition: transform 0.3s cubic-bezier(0.34,1.56,0.64,1), color 0.2s; } + .hc-chevron.open { transform: rotate(180deg); color: #a855f7; } + + /* Collapsible quest panel */ + .hc-quests-wrap { + overflow: hidden; max-height: 0; + transition: max-height 0.38s cubic-bezier(0.4,0,0.2,1); + background: #fafafa; border-top: 1px solid #f3f4f6; + } + .hc-quests-wrap.open { max-height: 480px; } + .hc-quest-list { display: flex; flex-direction: column; padding: 0.35rem 0; } + .hc-quest-row { + display: flex; align-items: center; gap: 0.6rem; + padding: 0.65rem 1.2rem; cursor: pointer; transition: background 0.13s; position: relative; + } + .hc-quest-row:hover { background: #f3f4f6; } + .hc-quest-row::before { + content: ''; position: absolute; left: 0; top: 20%; bottom: 20%; + width: 3px; border-radius: 0 3px 3px 0; background: var(--ac); + } + .hc-q-icon { + width: 34px; height: 34px; border-radius: 10px; flex-shrink: 0; + display: flex; align-items: center; justify-content: center; + font-size: 1rem; background: white; border: 1.5px solid #f3f4f6; + transition: transform 0.15s; + } + .hc-quest-row:hover .hc-q-icon { transform: scale(1.08) rotate(-4deg); } + .hc-q-icon.claimable { background: #fef3c7; border-color: #fde68a; animation: hcWiggle 2s ease-in-out infinite; } + @keyframes hcWiggle { 0%,100%{transform:rotate(0);} 30%{transform:rotate(-7deg) scale(1.05);} 70%{transform:rotate(7deg) scale(1.05);} } + .hc-q-body { flex: 1; min-width: 0; } + .hc-q-name { font-family: 'Nunito', sans-serif; font-size: 0.8rem; font-weight: 800; color: #1e1b4b; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .hc-q-sub { font-family: 'Nunito Sans', sans-serif; font-size: 0.62rem; font-weight: 600; color: #9ca3af; margin-top: 0.1rem; } + .hc-q-claimable { font-family: 'Nunito Sans', sans-serif; font-size: 0.62rem; font-weight: 700; color: #d97706; margin-top: 0.1rem; } + .hc-claim-btn { + padding: 0.28rem 0.62rem; border: none; border-radius: 100px; cursor: pointer; + background: linear-gradient(135deg, #fbbf24, #f59e0b); + font-family: 'Nunito', sans-serif; font-size: 0.65rem; font-weight: 900; color: #1a0800; + box-shadow: 0 2px 0 #d97706; flex-shrink: 0; transition: all 0.12s; + } + .hc-claim-btn:hover { transform: translateY(-1px); } + .hc-claim-btn:active { transform: translateY(1px); } + .hc-empty { padding: 1rem 1.2rem; text-align: center; font-family: 'Nunito', sans-serif; font-size: 0.82rem; font-weight: 700; color: #9ca3af; } + .hc-map-link { + display: flex; align-items: center; justify-content: center; gap: 0.3rem; + padding: 0.6rem 1.2rem; border-top: 1px solid #f3f4f6; + cursor: pointer; transition: background 0.13s; + font-family: 'Nunito', sans-serif; font-size: 0.7rem; font-weight: 800; color: #a855f7; + } + .hc-map-link:hover { background: #fdf4ff; } + + /* ════ DARK OCEAN CARD (QUEST_EXTENDED) ════ */ + .hc-ext { + background: linear-gradient(160deg, #0b1a35 0%, #060e1f 55%, #0d1530 100%); + border-radius: 26px; overflow: hidden; position: relative; + box-shadow: 0 8px 32px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.06); + animation: hcIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both; + margin-bottom: 12px; + } + .hc-ext::before { + content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 0; + background: + repeating-linear-gradient(105deg, transparent 55%, rgba(56,189,248,0.018) 56%, transparent 57%), + repeating-linear-gradient(75deg, transparent 70%, rgba(56,189,248,0.012) 71%, transparent 72%); + background-size: 320% 320%, 260% 260%; + animation: hcExtSea 14s ease-in-out infinite alternate; + } + @keyframes hcExtSea { + 0% { background-position: 0% 0%, 100% 0%; } + 100% { background-position: 100% 100%, 0% 100%; } + } + .hc-ext::after { + content: ''; position: absolute; top: -40px; right: -30px; z-index: 0; + width: 180px; height: 180px; border-radius: 50%; + background: radial-gradient(circle, rgba(251,191,36,0.1), transparent 70%); + pointer-events: none; + } + .hc-ext-header { + position: relative; z-index: 2; + display: flex; align-items: center; justify-content: space-between; + padding: 1rem 1.2rem 0.3rem; + } + .hc-ext-title { + font-family: 'Cinzel', serif; font-size: 0.6rem; font-weight: 700; + letter-spacing: 0.2em; text-transform: uppercase; color: rgba(251,191,36,0.65); + } + .hc-ext-earned { + font-family: 'Nunito', sans-serif; font-size: 0.7rem; font-weight: 900; + color: #fbbf24; background: rgba(251,191,36,0.1); + border: 1px solid rgba(251,191,36,0.18); border-radius: 100px; + padding: 0.2rem 0.6rem; + } + + /* ── Rank ladder scroll container ── + Always scrollable on mobile. On desktop (≥1024px) we lock the width and + disable scrolling — nodes are spaced by percentage so no overflow occurs. */ + .hc-ext-scroll { + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: none; + -webkit-overflow-scrolling: touch; + cursor: grab; + position: relative; + z-index: 2; + } + .hc-ext-scroll::-webkit-scrollbar { display: none; } + .hc-ext-scroll:active { cursor: grabbing; } + + /* ── Rank ladder inner track ── + On mobile: fixed pixel width (fits all 6 nodes without squishing). + On desktop: 100% width, nodes spaced purely by percentage. */ + .hc-ext-inner { + display: flex; + align-items: flex-end; + position: relative; + height: 110px; + /* Mobile: fixed width so nodes have room and scroll kicks in */ + width: 520px; + } + + @media (min-width: 1024px) { + .hc-ext-scroll { + overflow-x: hidden; + cursor: default; + } + .hc-ext-inner { + /* Desktop: fill the card width; percentage positions work correctly */ + width: 100%; + } + /* Upscale fonts for desktop readability */ + .hc-ext-title { font-size: 0.72rem; } + .hc-ext-earned { font-size: 0.82rem; } + .hc-ext-label-name { font-size: 0.56rem; } + .hc-ext-label-xp { font-size: 0.5rem; } + .hc-ext-node { width: 56px; height: 56px; font-size: 1.5rem; } + .hc-ext-ship { font-size: 1.7rem; } + } + + /* ── Baseline and progress line ── + Use percentage-based left/right so they align with percentage-positioned nodes + regardless of container width. A small inset (half a node width as %) keeps + the line from starting/ending at the very edge of the outer nodes. */ + .hc-ext-baseline { + position: absolute; + top: 56px; + /* Inset matches half the outer col width relative to inner width */ + left: 4%; + right: 4%; + height: 2px; + background: rgba(255,255,255,0.07); + border-radius: 2px; + z-index: 0; + } + .hc-ext-progress-line { + position: absolute; + top: 56px; + left: 4%; + height: 2px; + background: linear-gradient(90deg, #fbbf24, #f59e0b); + box-shadow: 0 0 10px rgba(251,191,36,0.5); + border-radius: 2px; + z-index: 1; + /* Width is set inline as a % of the 92% usable span (100% - 4% - 4%) */ + transition: width 1.2s cubic-bezier(0.34,1.56,0.64,1); + } + .hc-ext-progress-line::after { + content: ""; + position: absolute; + right: -6px; top: -3px; + width: 10px; height: 10px; + background: #fbbf24; + border-radius: 50%; + box-shadow: 0 0 10px rgba(251,191,36,0.9); + } + + .hc-ext-ship-wrap { + position: absolute; + top: 20px; z-index: 10; pointer-events: none; + display: flex; flex-direction: column; align-items: center; + transition: left 1.2s cubic-bezier(0.34,1.56,0.64,1); + transform: translateX(-50%); + } + .hc-ext-ship { + font-size: 1.5rem; + filter: drop-shadow(0 2px 12px rgba(251,191,36,0.6)); + animation: hcShipBob 2.8s ease-in-out infinite; + display: block; + } + @keyframes hcShipBob { + 0%,100% { transform: translateY(0) rotate(-3deg); } + 50% { transform: translateY(-6px) rotate(3deg); } + } + .hc-ext-ship-tether { + width: 1px; height: 14px; + background: linear-gradient(to bottom, rgba(251,191,36,0.5), transparent); + } + + /* ── Node columns ── + Each col takes an equal share; absolute positioning within .hc-ext-inner + is replaced by evenly-spaced flex. The node itself is centred in the col. */ + .hc-ext-col { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + position: relative; + z-index: 2; + } + .hc-ext-node { + width: 52px; height: 52px; border-radius: 50%; flex-shrink: 0; + display: flex; align-items: center; justify-content: center; + font-size: 1.4rem; position: relative; z-index: 2; + margin-top: 30px; + } + .hc-ext-node.reached { + background: linear-gradient(145deg, #1e0e4a, #3730a3); + border: 2px solid rgba(251,191,36,0.45); + box-shadow: 0 0 18px rgba(251,191,36,0.2), 0 4px 0 rgba(20,10,50,0.7); + } + .hc-ext-node.current { + background: linear-gradient(145deg, #6d28d9, #a855f7); + border: 2.5px solid #fbbf24; + box-shadow: + 0 0 0 4px rgba(251,191,36,0.12), + 0 0 22px rgba(168,85,247,0.45), + 0 4px 0 rgba(80,30,150,0.5); + animation: hcExtNodePulse 2.2s ease-in-out infinite; + } + @keyframes hcExtNodePulse { + 0%,100% { box-shadow: 0 0 0 4px rgba(251,191,36,0.12), 0 0 22px rgba(168,85,247,0.45), 0 4px 0 rgba(80,30,150,0.5); } + 50% { box-shadow: 0 0 0 7px rgba(251,191,36,0.06), 0 0 30px rgba(168,85,247,0.6), 0 4px 0 rgba(80,30,150,0.5); } + } + .hc-ext-node.locked { + background: rgba(0,0,0,0.4); + border: 2px solid rgba(255,255,255,0.09); + filter: grayscale(0.7) opacity(0.45); + } + .hc-ext-label { + margin-top: 7px; + display: flex; flex-direction: column; align-items: center; gap: 2px; + } + .hc-ext-label-name { + font-family: 'Cinzel', serif; font-size: 0.48rem; font-weight: 700; + text-align: center; line-height: 1.3; letter-spacing: 0.03em; max-width: 70px; + } + .hc-ext-label-name.reached { color: #fbbf24; } + .hc-ext-label-name.current { color: #c084fc; } + .hc-ext-label-name.locked { color: rgba(255,255,255,0.2); } + .hc-ext-label-xp { + font-family: 'Nunito Sans', sans-serif; font-size: 0.42rem; font-weight: 700; + text-align: center; + } + .hc-ext-label-xp.reached { color: rgba(251,191,36,0.4); } + .hc-ext-label-xp.current { color: rgba(192,132,252,0.6); } + .hc-ext-label-xp.locked { color: rgba(255,255,255,0.15); } + .hc-ext-footer { + position: relative; z-index: 2; + display: flex; align-items: center; justify-content: center; gap: 0.3rem; + padding: 0.5rem 1.2rem 0.85rem; margin-top: 0.2rem; + border-top: 1px solid rgba(255,255,255,0.06); + cursor: pointer; transition: opacity 0.15s; + font-family: 'Nunito', sans-serif; font-size: 0.68rem; font-weight: 800; + color: rgba(251,191,36,0.55); letter-spacing: 0.04em; + } + .hc-ext-footer:hover { opacity: 0.75; } +`; + +// ─── Helpers ────────────────────────────────────────────────────────────────── +function getActiveQuests(arcs: QuestArc[]) { + const out: { node: QuestNode; arc: QuestArc }[] = []; + for (const arc of arcs) + for (const node of arc.nodes) + if (node.status === "claimable" || node.status === "active") + out.push({ node, arc }); + out.sort((a, b) => + a.node.status === "claimable" && b.node.status !== "claimable" + ? -1 + : b.node.status === "claimable" && a.node.status !== "claimable" + ? 1 + : 0, + ); + return out.slice(0, 2); +} + +// ─── QUEST_EXTENDED sub-component ──────────────────────────────────────────── +const RankLadder = ({ + earnedXP, +}: { + earnedXP: number; + onViewAll: () => void; +}) => { + const scrollRef = useRef(null); + const ladder = [...CREW_RANKS] as typeof CREW_RANKS; + const N = ladder.length; + + let currentIdx = 0; + for (let i = N - 1; i >= 0; i--) { + if (earnedXP >= ladder[i].xpRequired) { + currentIdx = i; + break; + } + } + + const current = ladder[currentIdx]; + const nextRank = ladder[currentIdx + 1] ?? null; + const progressToNext = nextRank + ? Math.min( + 1, + (earnedXP - current.xpRequired) / + (nextRank.xpRequired - current.xpRequired), + ) + : 1; + + // ── Geometry ──────────────────────────────────────────────────────────────── + // Nodes are evenly distributed via flex (each col = flex:1). + // The centre of node[i] sits at: leftInset + (i / (N-1)) * usableSpan + // where leftInset = 4% and usableSpan = 92% (100% - 4% left - 4% right). + // The baseline and progress line also start at 4% so everything aligns. + const LEFT_INSET_PCT = 4; // matches left: 4% on baseline/progress + const USABLE_PCT = 92; // 100 - 4 - 4 + + // Ship position as % of the inner container width + const nodePosPct = (i: number) => LEFT_INSET_PCT + (i / (N - 1)) * USABLE_PCT; + + const shipPct = nextRank + ? nodePosPct(currentIdx) + + (nodePosPct(currentIdx + 1) - nodePosPct(currentIdx)) * progressToNext + : nodePosPct(currentIdx); + + // Progress line width: distance from left inset to ship position + // expressed as % of the container (not of usable span) + const progressLinePct = shipPct - LEFT_INSET_PCT; + + const [animated, setAnimated] = useState(false); + useEffect(() => { + const id = requestAnimationFrame(() => + requestAnimationFrame(() => setAnimated(true)), + ); + return () => cancelAnimationFrame(id); + }, []); + + // Mouse-drag scroll for mobile + useEffect(() => { + const el = scrollRef.current; + if (!el) return; + let isDown = false, + startX = 0, + scrollLeft = 0; + const down = (e: MouseEvent) => { + isDown = true; + startX = e.pageX - el.offsetLeft; + scrollLeft = el.scrollLeft; + }; + const leave = () => (isDown = false); + const up = () => (isDown = false); + const move = (e: MouseEvent) => { + if (!isDown) return; + e.preventDefault(); + el.scrollLeft = scrollLeft - (e.pageX - el.offsetLeft - startX) * 1.2; + }; + el.addEventListener("mousedown", down); + el.addEventListener("mouseleave", leave); + el.addEventListener("mouseup", up); + el.addEventListener("mousemove", move); + return () => { + el.removeEventListener("mousedown", down); + el.removeEventListener("mouseleave", leave); + el.removeEventListener("mouseup", up); + el.removeEventListener("mousemove", move); + }; + }, []); + + const rankPct = nextRank ? Math.round(progressToNext * 100) : 100; + const nextLabel = nextRank + ? `${rankPct}% · ${nextRank.xpRequired - earnedXP} XP to ${nextRank.label}` + : "Maximum rank achieved"; + + return ( +
+
+ ⚓ Crew Rank + {earnedXP.toLocaleString()} XP +
+ +
+ + {current.emoji} {current.label} + + + {nextLabel} + +
+ +
+
+ {/* Baseline — left: 4%, right: 4% (set in CSS) */} +
+ + {/* Progress line — starts at left: 4%, width grows to ship position */} +
+ + {/* Ship — positioned as % of container */} +
+ + ⛵ + +
+
+ + {/* Nodes — evenly spaced via flex:1 on each col */} + {ladder.map((r, i) => { + const state = + i < currentIdx + ? "reached" + : i === currentIdx + ? "current" + : "locked"; + return ( +
+
{r.emoji}
+
+ + {r.label} + + + {r.xpRequired === 0 + ? "Start" + : `${r.xpRequired.toLocaleString()} XP`} + +
+
+ ); + })} +
+
+
+ ); +}; + +// ─── Props ──────────────────────────────────────────────────────────────────── +type Mode = "DEFAULT" | "LEVEL" | "QUEST_COMPACT" | "QUEST_EXTENDED"; +interface Props { + onViewAll?: () => void; + mode?: Mode; +} + +// ─── Main component ─────────────────────────────────────────────────────────── +export const InfoHeader = ({ onViewAll, mode = "DEFAULT" }: Props) => { + const navigate = useNavigate(); + const user = useAuthStore((s) => s.user); + + const arcs = useQuestStore((s) => s.arcs); + const earnedXP = user?.total_xp ?? 0; + const earnedTitles = useQuestStore((s) => s.earnedTitles); + const claimNode = useQuestStore((s) => s.claimNode); + + const summary = getQuestSummary(arcs, earnedXP, earnedTitles); + const rank = getCrewRank(earnedXP); + const activeQuests = getActiveQuests(arcs); + + const u = user as any; + const level = u?.current_level ?? 1; + const totalXP = u?.total_xp ?? 5; + const levelStart = u?.current_level_start ?? u?.level_min_xp ?? 0; + const levelEnd = + u?.next_level_threshold ?? u?.level_max_xp ?? levelStart + 1000; + const streak = u?.streak ?? u?.current_streak ?? 0; + const firstName = user?.name?.split(" ")[0] || "there"; + const roleLabel = + u?.role === "ADMIN" + ? "Admin" + : u?.role === "TEACHER" + ? "Teacher" + : "Student"; + const hour = new Date().getHours(); + const timeLabel = hour < 12 ? "morning" : hour < 17 ? "afternoon" : "evening"; + + const levelRange = Math.max(levelEnd - levelStart, 1); + const xpIntoLevel = Math.max(totalXP - levelStart, 0); + const rawPct = Math.min(Math.round((xpIntoLevel / levelRange) * 100), 100); + const xpToGo = Math.max(levelEnd - totalXP, 0); + + const [barPct, setBarPct] = useState(0); + useEffect(() => { + const id = requestAnimationFrame(() => + requestAnimationFrame(() => setBarPct(rawPct)), + ); + return () => cancelAnimationFrame(id); + }, [rawPct]); + + const [open, setOpen] = useState(false); + const [claimingNode, setClaimingNode] = useState<{ + node: QuestNode; + arcId: string; + } | null>(null); + const [claimResult, setClaimResult] = useState( + null, + ); + + const handleViewAll = () => { + if (onViewAll) onViewAll(); + else navigate("/student/quests"); + }; + + const handleClaim = (node: QuestNode, arcId: string) => { + setClaimResult(null); + setClaimingNode({ node, arcId }); + }; + + const handleChestClose = () => { + if (!claimingNode) return; + claimNode( + claimingNode.arcId, + claimingNode.node.node_id, + claimResult?.xp_awarded ?? 0, + claimResult?.title_unlocked.map((t) => t.name) ?? [], + ); + setClaimingNode(null); + setClaimResult(null); + }; + + const rankProgress = Math.round(rank.progressToNext * 100); + const nextLabel = rank.next + ? `${rankProgress}% to ${rank.next.label}` + : "Max rank"; + + const showIdentity = mode === "DEFAULT"; + const showLevel = mode === "DEFAULT" || mode === "LEVEL"; + const showQuestCompact = mode === "DEFAULT" || mode === "QUEST_COMPACT"; + const showQuestExtended = mode === "QUEST_EXTENDED"; + + if (showQuestExtended) { + return ( + <> + + + {claimingNode && ( + + )} + + ); + } + + return ( + <> + + +
+ {showIdentity && ( + <> +
+
+
+ + + + {user?.name?.slice(0, 1)} + + +
{level}
+
+
+

+ Good {timeLabel}, {firstName} 👋 +

+

{roleLabel}

+
+
+ {/* @ts-ignore */} + + + + + + + + + +
+
+ + )} + + {showLevel && ( +
+ Lv {level} +
+
+
+
+
+ {totalXP.toLocaleString()} XP + {xpToGo.toLocaleString()} to go +
+
+
+ )} + + {showQuestCompact && ( + <> +
setOpen((o) => !o)}> + {rank.emoji} +
+

{rank.label}

+

{nextLabel}

+
+
+ {streak > 0 && ( + 🔥 {streak} + )} + {summary.claimableNodes > 0 && ( + + 📦 {summary.claimableNodes} + + )} + +
+
+ +
+
+ {activeQuests.length === 0 ? ( +

⚓ All caught up — keep sailing!

+ ) : ( + activeQuests.map(({ node, arc }) => { + const pct = Math.min( + 100, + Math.round((node.current_value / node.req_target) * 100), + ); + const isClaimable = node.status === "claimable"; + const accentColor = generateArcTheme(arc).accent; + const nodeEmoji = REQ_EMOJI[node.req_type] ?? "🏝️"; + const reqLabel = REQ_LABEL[node.req_type] ?? node.req_type; + return ( +
!isClaimable && handleViewAll()} + > +
+ {isClaimable ? "📦" : nodeEmoji} +
+
+

{node.name ?? "—"}

+ {isClaimable ? ( +

✨ Ready to claim!

+ ) : ( +

+ {node.current_value}/{node.req_target} {reqLabel}{" "} + · {pct}% +

+ )} +
+ {isClaimable ? ( + + ) : ( + + )} +
+ ); + }) + )} +
+
+ View quest map +
+
+ + )} +
+ + {claimingNode && ( + + )} + + ); +}; diff --git a/src/components/InventoryButton.tsx b/src/components/InventoryButton.tsx new file mode 100644 index 0000000..4c2f584 --- /dev/null +++ b/src/components/InventoryButton.tsx @@ -0,0 +1,216 @@ +import { useState } from "react"; +import { + useInventoryStore, + getLiveEffects, + formatTimeLeft, +} from "../stores/useInventoryStore"; +import { InventoryModal } from "./InventoryModal"; + +// ─── Styles ─────────────────────────────────────────────────────────────────── +const BTN_STYLES = ` + @import url('https://fonts.googleapis.com/css2?family=Nunito:wght@800;900&family=Cinzel:wght@700&display=swap'); + + /* ── Inventory trigger button ── */ + .inv-btn { + position: relative; + display: inline-flex; align-items: center; gap: 0.38rem; + padding: 0.48rem 0.85rem; + background: rgba(255,255,255,0.05); + border: 1.5px solid rgba(255,255,255,0.1); + border-radius: 100px; + cursor: pointer; + font-family: 'Nunito', sans-serif; + font-size: 0.72rem; font-weight: 900; + color: rgba(255,255,255,0.7); + transition: all 0.18s ease; + outline: none; + white-space: nowrap; + } + .inv-btn:hover { + background: rgba(255,255,255,0.09); + border-color: rgba(255,255,255,0.2); + color: white; + transform: translateY(-1px); + box-shadow: 0 4px 16px rgba(0,0,0,0.25); + } + .inv-btn:active { transform: translateY(0) scale(0.97); } + + /* When active effects are running — gold glow */ + .inv-btn.has-active { + border-color: rgba(251,191,36,0.45); + color: #fbbf24; + background: rgba(251,191,36,0.08); + animation: invBtnGlow 2.6s ease-in-out infinite; + } + @keyframes invBtnGlow { + 0%,100% { box-shadow: 0 0 0 0 rgba(251,191,36,0); } + 50% { box-shadow: 0 0 14px 3px rgba(251,191,36,0.2); } + } + .inv-btn.has-active:hover { + border-color: rgba(251,191,36,0.7); + background: rgba(251,191,36,0.14); + } + + /* Badge dot */ + .inv-btn-badge { + position: absolute; top: -4px; right: -4px; + width: 14px; height: 14px; border-radius: 50%; + background: #fbbf24; + border: 2px solid transparent; /* will be set to match parent bg via CSS var */ + display: flex; align-items: center; justify-content: center; + font-family: 'Nunito', sans-serif; + font-size: 0.45rem; font-weight: 900; color: #1a0800; + animation: invBadgePop 1.8s ease-in-out infinite; + } + @keyframes invBadgePop { + 0%,100%{ transform: scale(1); } + 50% { transform: scale(1.15); } + } + + /* ── Active Effect Banner (shown on other screens, e.g. pretest) ── */ + .aeb-wrap { + display: flex; gap: 0.5rem; flex-wrap: wrap; + } + .aeb-pill { + display: inline-flex; align-items: center; gap: 0.4rem; + padding: 0.38rem 0.85rem; + border-radius: 100px; + font-family: 'Nunito', sans-serif; + font-size: 0.72rem; font-weight: 900; + animation: aebPillIn 0.35s cubic-bezier(0.34,1.56,0.64,1) both; + animation-delay: var(--aeb-delay, 0s); + } + @keyframes aebPillIn { + from { opacity:0; transform: scale(0.8) translateY(6px); } + to { opacity:1; transform: scale(1) translateY(0); } + } + + /* Color variants per effect type */ + .aeb-pill.xp_boost { + background: rgba(251,191,36,0.12); + border: 1.5px solid rgba(251,191,36,0.4); + color: #fbbf24; + } + .aeb-pill.streak_shield { + background: rgba(96,165,250,0.1); + border: 1.5px solid rgba(96,165,250,0.35); + color: #60a5fa; + } + .aeb-pill.coin_boost { + background: rgba(167,243,208,0.08); + border: 1.5px solid rgba(52,211,153,0.35); + color: #34d399; + } + .aeb-pill.default { + background: rgba(255,255,255,0.06); + border: 1.5px solid rgba(255,255,255,0.15); + color: rgba(255,255,255,0.7); + } + .aeb-pill-icon { font-size: 0.9rem; line-height:1; } + .aeb-pill-label { line-height:1; } + .aeb-pill-time { + font-family: 'Nunito Sans', sans-serif; + font-size: 0.58rem; font-weight: 700; + opacity: 0.55; margin-left: 0.1rem; + } +`; + +const ITEM_ICON: Record = { + xp_boost: "⚡", + streak_shield: "🛡️", + title: "🏴‍☠️", + coin_boost: "🪙", +}; +function itemIcon(effectType: string): string { + return ITEM_ICON[effectType] ?? "📦"; +} + +// ─── InventoryButton ────────────────────────────────────────────────────────── +/** + * Drop-in trigger button. Can be placed in any nav bar, header, or screen. + * Shows a gold glow + badge count when active effects are running. + * + * Usage: + * + * + */ +export const InventoryButton = ({}: {}) => { + const [open, setOpen] = useState(false); + const activeEffects = useInventoryStore((s) => s.activeEffects); + const liveEffects = getLiveEffects(activeEffects); + const hasActive = liveEffects.length > 0; + + return ( + <> + + + + + {open && setOpen(false)} />} + + ); +}; + +// ─── ActiveEffectBanner ─────────────────────────────────────────────────────── +/** + * Shows pills for each currently-active effect. + * Place wherever you want a contextual reminder (pretest screen, dashboard, etc.) + * + * Usage: + * + * ← only show a specific effect + * + * Example output on Pretest screen: + * ⚡ XP Boost ×2 · 1h 42m 🛡️ Streak Shield · 23m + */ +export const ActiveEffectBanner = ({ + filter, + className, +}: { + filter?: string; + className?: string; +}) => { + const activeEffects = useInventoryStore((s) => s.activeEffects); + const live = getLiveEffects(activeEffects).filter( + (e) => !filter || e.item.effect_type === filter, + ); + + if (live.length === 0) return null; + + return ( + <> + +
+ {live.map((e, i) => ( +
+ + {itemIcon(e.item.effect_type)} + + + {e.item.name} + {e.item.effect_type === "xp_boost" && e.item.effect_value + ? ` ×${e.item.effect_value}` + : ""} + + + {formatTimeLeft(e.expires_at)} + +
+ ))} +
+ + ); +}; diff --git a/src/components/InventoryModal.tsx b/src/components/InventoryModal.tsx new file mode 100644 index 0000000..9ac80fe --- /dev/null +++ b/src/components/InventoryModal.tsx @@ -0,0 +1,615 @@ +import { useEffect, useRef, useState, useCallback } from "react"; +import { createPortal } from "react-dom"; +import { X } from "lucide-react"; +import type { InventoryItem, ActiveEffect } from "../types/quest"; +import { + useInventoryStore, + getLiveEffects, + formatTimeLeft, +} from "../stores/useInventoryStore"; +import { useAuthStore } from "../stores/authStore"; +import { api } from "../utils/api"; + +// ─── Styles ─────────────────────────────────────────────────────────────────── +const STYLES = ` + @import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@600;700;900&family=Nunito:wght@700;800;900&family=Nunito+Sans:wght@400;600;700&display=swap'); + + /* ══ OVERLAY ══ */ + .inv-overlay { + position: fixed; inset: 0; z-index: 60; + background: rgba(2,5,15,0.78); + backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); + display: flex; align-items: flex-end; justify-content: center; + animation: invFadeIn 0.2s ease both; + } + @keyframes invFadeIn { from{opacity:0} to{opacity:1} } + + /* ══ SHEET ══ */ + .inv-sheet { + width: 100%; max-width: 540px; + background: linear-gradient(180deg, #08111f 0%, #050d1a 100%); + border-radius: 28px 28px 0 0; + border-top: 1.5px solid rgba(251,191,36,0.25); + box-shadow: + 0 -16px 60px rgba(0,0,0,0.7), + inset 0 1px 0 rgba(255,255,255,0.06); + overflow: hidden; + display: flex; flex-direction: column; + max-height: 88vh; + animation: invSlideUp 0.38s cubic-bezier(0.34,1.56,0.64,1) both; + position: relative; + } + + @media (min-width: 1024px) { + .inv-sheet { + max-width: 1000px; + } + } + @keyframes invSlideUp { + from { transform: translateY(100%); opacity:0; } + to { transform: translateY(0); opacity:1; } + } + + .inv-sheet::before { + content: ''; + position: absolute; inset: 0; pointer-events: none; z-index: 0; + background: + repeating-linear-gradient(110deg, transparent 60%, rgba(56,189,248,0.015) 61%, transparent 62%), + repeating-linear-gradient(70deg, transparent 72%, rgba(56,189,248,0.01) 73%, transparent 74%); + background-size: 300% 300%, 240% 240%; + animation: invSeaSway 16s ease-in-out infinite alternate; + } + @keyframes invSeaSway { + 0% { background-position: 0% 0%, 100% 0%; } + 100% { background-position: 100% 100%, 0% 100%; } + } + + .inv-sheet::after { + content: ''; + position: absolute; top: -60px; right: -40px; z-index: 0; + width: 220px; height: 220px; border-radius: 50%; + background: radial-gradient(circle, rgba(251,191,36,0.07), transparent 68%); + pointer-events: none; + } + + .inv-handle-row { + display: flex; justify-content: center; + padding: 0.75rem 0 0; flex-shrink: 0; position: relative; z-index: 2; + } + .inv-handle { + width: 40px; height: 4px; border-radius: 100px; + background: rgba(255,255,255,0.1); + } + + .inv-header { + position: relative; z-index: 2; + display: flex; align-items: center; justify-content: space-between; + padding: 0.85rem 1.3rem 0; + } + .inv-header-left { display: flex; flex-direction: column; gap: 0.1rem; } + .inv-eyebrow { + font-family: 'Cinzel', serif; + font-size: 0.5rem; font-weight: 700; letter-spacing: 0.22em; + text-transform: uppercase; color: rgba(251,191,36,0.55); + } + .inv-title { + font-family: 'Cinzel', serif; + font-size: 1.28rem; font-weight: 900; color: #fff; + letter-spacing: 0.03em; + text-shadow: 0 0 24px rgba(251,191,36,0.3); + } + .inv-close { + width: 32px; height: 32px; border-radius: 50%; + border: 1.5px solid rgba(255,255,255,0.1); + background: rgba(255,255,255,0.05); + display: flex; align-items: center; justify-content: center; + cursor: pointer; transition: all 0.15s; + flex-shrink: 0; + } + .inv-close:hover { + border-color: rgba(251,191,36,0.5); + background: rgba(251,191,36,0.1); + } + + .inv-active-bar { + position: relative; z-index: 2; + display: flex; gap: 0.5rem; overflow-x: auto; scrollbar-width: none; + padding: 0.75rem 1.3rem 0; + } + .inv-active-bar::-webkit-scrollbar { display: none; } + .inv-active-pill { + display: flex; align-items: center; gap: 0.4rem; + flex-shrink: 0; + padding: 0.35rem 0.75rem; + border-radius: 100px; + border: 1.5px solid rgba(251,191,36,0.35); + background: rgba(251,191,36,0.08); + animation: invPillGlow 2.4s ease-in-out infinite; + } + @keyframes invPillGlow { + 0%,100% { box-shadow: 0 0 0 0 rgba(251,191,36,0); } + 50% { box-shadow: 0 0 12px 2px rgba(251,191,36,0.18); } + } + .inv-active-pill-icon { font-size: 0.9rem; } + .inv-active-pill-name { + font-family: 'Nunito', sans-serif; + font-size: 0.72rem; font-weight: 900; color: #fbbf24; + } + .inv-active-pill-time { + font-family: 'Nunito Sans', sans-serif; + font-size: 0.6rem; font-weight: 700; + color: rgba(251,191,36,0.5); + margin-left: 0.1rem; + } + + .inv-divider { + position: relative; z-index: 2; + height: 1px; margin: 0.85rem 1.3rem 0; + background: rgba(255,255,255,0.06); + } + .inv-section-label { + position: relative; z-index: 2; + padding: 0.7rem 1.3rem 0.35rem; + font-family: 'Cinzel', serif; + font-size: 0.48rem; font-weight: 700; letter-spacing: 0.2em; + text-transform: uppercase; color: rgba(255,255,255,0.25); + } + + .inv-scroll { + position: relative; z-index: 2; + flex: 1; overflow-y: auto; scrollbar-width: none; + padding: 0 1.1rem calc(1.5rem + env(safe-area-inset-bottom)); + } + .inv-scroll::-webkit-scrollbar { display: none; } + + .inv-empty { + display: flex; flex-direction: column; align-items: center; + justify-content: center; gap: 0.6rem; + padding: 3rem 1rem; + font-family: 'Nunito', sans-serif; + font-size: 0.85rem; font-weight: 800; + color: rgba(255,255,255,0.25); + } + .inv-empty-icon { font-size: 2.5rem; opacity: 0.4; } + + .inv-skeleton-grid { + display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; + } + .inv-skeleton-card { + height: 140px; border-radius: 20px; + background: rgba(255,255,255,0.04); + animation: invSkel 1.6s ease-in-out infinite; + } + @keyframes invSkel { + 0%,100% { opacity: 0.6; } + 50% { opacity: 1; } + } + + .inv-grid { + display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; + } + + .inv-card { + border-radius: 20px; padding: 1rem; + border: 1.5px solid rgba(255,255,255,0.07); + background: rgba(255,255,255,0.03); + display: flex; flex-direction: column; gap: 0.6rem; + cursor: pointer; position: relative; overflow: hidden; + transition: border-color 0.2s, background 0.2s, transform 0.15s; + animation: invCardIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both; + animation-delay: var(--ci-delay, 0s); + } + @keyframes invCardIn { + from { opacity:0; transform: translateY(14px) scale(0.95); } + to { opacity:1; transform: translateY(0) scale(1); } + } + .inv-card:hover { + border-color: rgba(255,255,255,0.14); + background: rgba(255,255,255,0.06); + transform: translateY(-2px); + } + .inv-card:active { transform: translateY(0) scale(0.98); } + .inv-card.is-active { + border-color: rgba(251,191,36,0.4); + background: rgba(251,191,36,0.06); + } + .inv-card.is-active:hover { + border-color: rgba(251,191,36,0.6); + background: rgba(251,191,36,0.09); + } + @keyframes invActivateFlash { + 0% { background: rgba(251,191,36,0.25); border-color: rgba(251,191,36,0.8); } + 100%{ background: rgba(251,191,36,0.06); border-color: rgba(251,191,36,0.4); } + } + .inv-card.just-activated { animation: invActivateFlash 0.9s ease forwards; } + .inv-card-sheen { + position: absolute; inset: 0; pointer-events: none; + background: linear-gradient(135deg, transparent 30%, rgba(255,255,255,0.04) 50%, transparent 70%); + transform: translateX(-100%); transition: transform 0.5s ease; + } + .inv-card:hover .inv-card-sheen { transform: translateX(100%); } + .inv-card-icon-wrap { + width: 44px; height: 44px; border-radius: 14px; + display: flex; align-items: center; justify-content: center; + font-size: 1.4rem; + background: rgba(255,255,255,0.06); + border: 1px solid rgba(255,255,255,0.08); + flex-shrink: 0; position: relative; + } + .inv-card.is-active .inv-card-icon-wrap { + background: rgba(251,191,36,0.12); + border-color: rgba(251,191,36,0.3); + } + .inv-card-active-dot { + position: absolute; top: -3px; right: -3px; + width: 10px; height: 10px; border-radius: 50%; + background: #fbbf24; border: 2px solid #08111f; + animation: invDotPulse 2s ease-in-out infinite; + } + @keyframes invDotPulse { + 0%,100% { box-shadow: 0 0 0 0 rgba(251,191,36,0.6); } + 50% { box-shadow: 0 0 0 5px rgba(251,191,36,0); } + } + .inv-card-name { + font-family: 'Nunito', sans-serif; + font-size: 0.82rem; font-weight: 900; color: #fff; line-height: 1.2; + } + .inv-card.is-active .inv-card-name { color: #fbbf24; } + .inv-card-desc { + font-family: 'Nunito Sans', sans-serif; + font-size: 0.63rem; font-weight: 600; + color: rgba(255,255,255,0.38); line-height: 1.4; flex: 1; + } + .inv-card-meta { + display: flex; align-items: center; justify-content: space-between; + gap: 0.4rem; margin-top: auto; + } + .inv-card-qty { + font-family: 'Nunito', sans-serif; + font-size: 0.65rem; font-weight: 900; + color: rgba(255,255,255,0.3); + background: rgba(255,255,255,0.05); + border-radius: 100px; padding: 0.15rem 0.45rem; + } + .inv-card-type { + font-family: 'Nunito Sans', sans-serif; + font-size: 0.56rem; font-weight: 700; + letter-spacing: 0.1em; text-transform: uppercase; + color: rgba(255,255,255,0.22); + } + .inv-activate-btn { + width: 100%; padding: 0.48rem; + border-radius: 10px; border: none; cursor: pointer; + font-family: 'Nunito', sans-serif; + font-size: 0.7rem; font-weight: 900; + transition: all 0.15s ease; + display: flex; align-items: center; justify-content: center; gap: 0.3rem; + } + .inv-activate-btn.idle { + background: rgba(255,255,255,0.07); + border: 1px solid rgba(255,255,255,0.1); + color: rgba(255,255,255,0.6); + } + .inv-activate-btn.idle:hover { background: rgba(255,255,255,0.12); color: white; } + .inv-activate-btn.activating { + background: rgba(251,191,36,0.1); + border: 1px solid rgba(251,191,36,0.25); + color: rgba(251,191,36,0.6); + cursor: not-allowed; + animation: invSpinLabel 0.4s ease infinite alternate; + } + @keyframes invSpinLabel { from{opacity:0.5} to{opacity:1} } + .inv-activate-btn.active-state { + background: rgba(251,191,36,0.12); + border: 1px solid rgba(251,191,36,0.3); + color: #fbbf24; cursor: default; + } + .inv-activate-btn.success-flash { + background: rgba(74,222,128,0.18); + border: 1px solid rgba(74,222,128,0.4); + color: #4ade80; + animation: invSuccessScale 0.35s cubic-bezier(0.34,1.56,0.64,1) both; + } + @keyframes invSuccessScale { from{transform:scale(0.94)} to{transform:scale(1)} } + .inv-activate-btn:disabled { pointer-events: none; } + .inv-active-time { + font-family: 'Nunito Sans', sans-serif; + font-size: 0.55rem; font-weight: 700; color: rgba(251,191,36,0.5); + } + + .inv-toast { + position: fixed; bottom: calc(1.5rem + env(safe-area-inset-bottom)); + left: 50%; transform: translateX(-50%); + z-index: 9999; + display: flex; align-items: center; gap: 0.55rem; + padding: 0.7rem 1.2rem; + background: linear-gradient(135deg, #1a3a1a, #0d2010); + border: 1.5px solid rgba(74,222,128,0.45); + border-radius: 100px; + box-shadow: 0 4px 24px rgba(0,0,0,0.5), 0 0 20px rgba(74,222,128,0.12); + font-family: 'Nunito', sans-serif; + font-size: 0.8rem; font-weight: 900; color: #4ade80; + white-space: nowrap; + animation: invToastIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both, + invToastOut 0.3s 2.7s ease forwards; + } + @keyframes invToastIn { from{opacity:0; transform:translateX(-50%) translateY(20px) scale(0.9)} to{opacity:1; transform:translateX(-50%) translateY(0) scale(1)} } + @keyframes invToastOut { from{opacity:1} to{opacity:0; transform:translateX(-50%) translateY(8px)} } +`; + +// ─── Item metadata ───────────────────────────────────────────────────────────── +const ITEM_ICON: Record = { + xp_boost: "⚡", + streak_shield: "🛡️", + title: "🏴‍☠️", + coin_boost: "🪙", +}; + +function itemIcon(effectType: string): string { + return ITEM_ICON[effectType] ?? "📦"; +} + +function isItemActive( + item: InventoryItem, + activeEffects: ActiveEffect[], +): ActiveEffect | null { + const now = Date.now(); + return ( + activeEffects.find( + (e) => + e.item.id === item.item.id && new Date(e.expires_at).getTime() > now, + ) ?? null + ); +} + +// ─── Item card ──────────────────────────────────────────────────────────────── +const ItemCard = ({ + inv, + activeEffects, + activatingId, + lastActivatedId, + onActivate, + index, +}: { + inv: InventoryItem; + activeEffects: ActiveEffect[]; + activatingId: string | null; + lastActivatedId: string | null; + onActivate: (id: string) => void; + index: number; +}) => { + const activeEffect = isItemActive(inv, activeEffects); + const isActive = !!activeEffect; + const isActivating = activatingId === inv.id; + const justActivated = lastActivatedId === inv.id; + + let btnState: "idle" | "activating" | "active-state" | "success-flash" = + "idle"; + if (justActivated) btnState = "success-flash"; + else if (isActivating) btnState = "activating"; + else if (isActive) btnState = "active-state"; + + let btnLabel = "Use Item"; + if (btnState === "activating") btnLabel = "Activating…"; + else if (btnState === "success-flash") btnLabel = "✓ Activated!"; + else if (btnState === "active-state") btnLabel = "✓ Active"; + + return ( +
+
+
+ {itemIcon(inv.item.effect_type)} + {isActive &&
} +
+

{inv.item.name}

+

{inv.item.description}

+
+ ×{inv.quantity} + + {inv.item.type.replace(/_/g, " ")} + +
+ {isActive && activeEffect && ( +
+ {formatTimeLeft(activeEffect.expires_at)} remaining +
+ )} + +
+ ); +}; + +// ─── Main component ─────────────────────────────────────────────────────────── +interface Props { + onClose: () => void; +} + +export const InventoryModal = ({ onClose }: Props) => { + const token = useAuthStore((s) => s.token); + + const items = useInventoryStore((s) => s.items); + const activeEffects = useInventoryStore((s) => s.activeEffects); + const loading = useInventoryStore((s) => s.loading); + const activatingId = useInventoryStore((s) => s.activatingId); + const lastActivatedId = useInventoryStore((s) => s.lastActivatedId); + const error = useInventoryStore((s) => s.error); + + const syncFromAPI = useInventoryStore((s) => s.syncFromAPI); + const setLoading = useInventoryStore((s) => s.setLoading); + const activateItemOptimistic = useInventoryStore( + (s) => s.activateItemOptimistic, + ); + const activateItemSuccess = useInventoryStore((s) => s.activateItemSuccess); + const activateItemError = useInventoryStore((s) => s.activateItemError); + const clearLastActivated = useInventoryStore((s) => s.clearLastActivated); + + const [showToast, setShowToast] = useState(false); + const [toastMsg, setToastMsg] = useState(""); + const toastTimer = useRef | null>(null); + + useEffect(() => { + if (!token) return; + let cancelled = false; + const fetchInv = async () => { + setLoading(true); + try { + const inv = await api.fetchUserInventory(token); + if (!cancelled) syncFromAPI(inv); + } catch (e) { + // Silently fail — cached data stays visible + } finally { + if (!cancelled) setLoading(false); + } + }; + fetchInv(); + return () => { + cancelled = true; + }; + }, [token]); + + const handleActivate = useCallback( + async (itemId: string) => { + if (!token) return; + activateItemOptimistic(itemId); + try { + const updatedInv = await api.activateItem(token, itemId); + activateItemSuccess(updatedInv, itemId); + const name = items.find((i) => i.id === itemId)?.item.name ?? "Item"; + setToastMsg( + `${itemIcon(items.find((i) => i.id === itemId)?.item.effect_type ?? "")} ${name} activated!`, + ); + setShowToast(true); + if (toastTimer.current) clearTimeout(toastTimer.current); + toastTimer.current = setTimeout(() => { + setShowToast(false); + clearLastActivated(); + }, 3000); + } catch (e) { + activateItemError( + itemId, + e instanceof Error ? e.message : "Failed to activate", + ); + } + }, + [token, items], + ); + + useEffect( + () => () => { + if (toastTimer.current) clearTimeout(toastTimer.current); + }, + [], + ); + + const liveEffects = getLiveEffects(activeEffects); + + // Portal the entire modal to document.body so it always + // renders at the top of the DOM tree, escaping any parent + // stacking context, overflow:hidden, or z-index constraints. + return createPortal( + <> + + +
+
e.stopPropagation()}> +
+
+
+ +
+
+ ⚓ Pirate's Hold +

Inventory

+
+ +
+ + {liveEffects.length > 0 && ( +
+ {liveEffects.map((e) => ( +
+ + {itemIcon(e.item.effect_type)} + + {e.item.name} + + {formatTimeLeft(e.expires_at)} + +
+ ))} +
+ )} + +
+

+ {items.length > 0 + ? `${items.length} item${items.length !== 1 ? "s" : ""} in your hold` + : "Your hold"} +

+ +
+ {loading && items.length === 0 ? ( +
+ {[0, 1, 2, 3].map((i) => ( +
+ ))} +
+ ) : items.length === 0 ? ( +
+ 🏴‍☠️ +

Your hold is empty — claim quests to earn items!

+
+ ) : ( +
+ {items.map((inv, i) => ( + + ))} +
+ )} + + {error && ( +

+ ⚠️ {error} +

+ )} +
+
+
+ + {showToast &&
{toastMsg}
} + , + document.body, + ); +}; diff --git a/src/components/Island3D.tsx b/src/components/Island3D.tsx new file mode 100644 index 0000000..fe87f54 --- /dev/null +++ b/src/components/Island3D.tsx @@ -0,0 +1,1047 @@ +// Island3D.tsx +import { useRef, useState, useMemo } from "react"; +import { useFrame } from "@react-three/fiber"; +import { Float, Text, Html, Sparkles, Billboard } from "@react-three/drei"; +import * as THREE from "three"; +import type { QuestNode } from "../types/quest"; + +export interface Island3DProps { + node: QuestNode; + position: [number, number, number]; + accent: string; + terrain: { l: string; m: string; d: string; s: string }; + onTap: (node: QuestNode) => void; + onClaim: (node: QuestNode) => void; + index: number; + isCurrent?: boolean; + modalOpen?: boolean; +} + +// ─── Seeded RNG ─────────────────────────────────────────────────────────────── +const makeRng = (seed: number) => { + let s = ((seed + 1) * 1664525 + 1013904223) >>> 0; + return () => { + s ^= s << 13; + s ^= s >>> 17; + s ^= s << 5; + return (s >>> 0) / 4294967296; + }; +}; + +// ─── Island shape ───────────────────────────────────────────────────────────── +const makeIslandShape = (seed: number, radiusBase = 1.0): THREE.Shape => { + const rng = makeRng(seed); + const sides = 8 + Math.floor(rng() * 5); + const pts: THREE.Vector2[] = []; + for (let i = 0; i < sides; i++) { + const angle = (i / sides) * Math.PI * 2 - Math.PI / 2; + const radius = radiusBase * (0.78 + rng() * 0.48); + pts.push( + new THREE.Vector2(Math.cos(angle) * radius, Math.sin(angle) * radius), + ); + } + return new THREE.Shape(pts); +}; + +// ─── Status palette ─────────────────────────────────────────────────────────── +const PALETTE = { + LOCKED: { top: "#778fa0", side: "#526070", emissive: "#000000", ei: 0 }, + ACTIVE: { top: "", side: "", emissive: "#ffffff", ei: 0 }, + CLAIMABLE: { top: "#f59e0b", side: "#d97706", emissive: "#fde68a", ei: 0.3 }, + COMPLETED: { top: "#d4a843", side: "#a07830", emissive: "#ffe8a0", ei: 0.15 }, +}; + +// ─── Card scale ─────────────────────────────────────────────────────────────── +const CARD_SCALE = 0.8; +const C = { + width: 175 * CARD_SCALE, + borderRadius: 13 * CARD_SCALE, + padV: 10 * CARD_SCALE, + padH: 12 * CARD_SCALE, + padVb: 9 * CARD_SCALE, + nameSize: 12.5 * CARD_SCALE, + xpSize: 11 * CARD_SCALE, + statusSize: 10 * CARD_SCALE, + xpPadV: 2 * CARD_SCALE, + xpPadH: 8 * CARD_SCALE, + xpRadius: 100 * CARD_SCALE, + gapRow: 6 * CARD_SCALE, + nameMb: 7 * CARD_SCALE, + barMt: 8 * CARD_SCALE, + barH: 4 * CARD_SCALE, + btnMt: 9 * CARD_SCALE, + btnPadV: 6 * CARD_SCALE, + btnSize: 11 * CARD_SCALE, + btnRadius: 9 * CARD_SCALE, + posX: 2.1 * CARD_SCALE, +}; + +const REQ_EMOJI: Record = { + questions: "❓", + accuracy: "🎯", + streak: "🔥", + sessions: "📚", + topics: "🗺️", + xp: "⚡", + leaderboard: "🏆", +}; + +// ─── Palm tree ──────────────────────────────────────────────────────────────── +const PalmTree = ({ + position, + scale, + seed, +}: { + position: [number, number, number]; + scale: number; + seed: number; +}) => { + const rng = makeRng(seed * 91 + 3); + const trunkLean = (rng() - 0.5) * 0.35; + const trunkHeight = 0.55 + rng() * 0.25; + const frondCount = 5 + Math.floor(rng() * 3); + + const trunkGeo = useMemo( + () => new THREE.CylinderGeometry(0.028, 0.045, trunkHeight, 6), + [trunkHeight], + ); + const frondGeo = useMemo(() => new THREE.ConeGeometry(0.22, 0.18, 4), []); + + return ( + + + + + {Array.from({ length: frondCount }, (_, i) => { + const angle = (i / frondCount) * Math.PI * 2; + const tilt = 0.5 + rng() * 0.3; + const r = 0.18 + rng() * 0.06; + return ( + + + + ); + })} + {rng() > 0.4 && ( + + + + + )} + + ); +}; + +// ─── Pine / jungle tree ─────────────────────────────────────────────────────── +const PineTree = ({ + position, + scale, + seed, +}: { + position: [number, number, number]; + scale: number; + seed: number; +}) => { + const rng = makeRng(seed * 37 + 11); + const layers = 2 + Math.floor(rng() * 2); + const hue = 110 + Math.floor(rng() * 40); + return ( + + + + + + {Array.from({ length: layers }, (_, i) => ( + + + + + ))} + + ); +}; + +// ─── Rock cluster ───────────────────────────────────────────────────────────── +const RockCluster = ({ + position, + scale, + seed, +}: { + position: [number, number, number]; + scale: number; + seed: number; +}) => { + const rng = makeRng(seed * 53 + 7); + const count = 2 + Math.floor(rng() * 3); + return ( + + {Array.from({ length: count }, (_, i) => { + const angle = rng() * Math.PI * 2; + const r = rng() * 0.12; + const s = 0.06 + rng() * 0.1; + const grey = Math.floor(90 + rng() * 80); + return ( + + + + + ); + })} + + ); +}; + +// ─── Mountain ───────────────────────────────────────────────────────────────── +const Mountain = ({ + position, + scale, + seed, + hasSnow, +}: { + position: [number, number, number]; + scale: number; + seed: number; + hasSnow: boolean; +}) => { + const rng = makeRng(seed * 17 + 5); + const peakH = 0.55 + rng() * 0.35; + const baseR = 0.38 + rng() * 0.18; + const sides = 5 + Math.floor(rng() * 3); + const rockH = Math.floor(20 + rng() * 30); + + const bodyGeo = useMemo( + () => new THREE.ConeGeometry(baseR, peakH, sides), + [baseR, peakH, sides], + ); + const capGeo = useMemo( + () => new THREE.ConeGeometry(baseR * 0.28, peakH * 0.28, sides), + [baseR, peakH, sides], + ); + + return ( + + + + + {hasSnow && ( + + + + )} + {/* Lava glow for volcanic */} + {!hasSnow && rng() > 0.55 && ( + + + + + )} + + ); +}; + +// ─── Beach strip ───────────────────────────────────────────────────────────── +const BeachStrip = ({ seed, radius }: { seed: number; radius: number }) => { + const rng = makeRng(seed * 29 + 13); + const arcStart = rng() * Math.PI * 2; + const arcLen = 0.6 + rng() * 1.2; + const segments = 18; + + const geo = useMemo(() => { + const shape = new THREE.Shape(); + const r0 = radius * 0.78; + const r1 = radius * 1.0; + shape.moveTo(Math.cos(arcStart) * r0, Math.sin(arcStart) * r0); + for (let i = 0; i <= segments; i++) { + const a = arcStart + (i / segments) * arcLen; + const jitter = 0.92 + Math.sin(i * 7.3) * 0.08; + shape.lineTo(Math.cos(a) * r1 * jitter, Math.sin(a) * r1 * jitter); + } + for (let i = segments; i >= 0; i--) { + const a = arcStart + (i / segments) * arcLen; + shape.lineTo(Math.cos(a) * r0, Math.sin(a) * r0); + } + shape.closePath(); + const g = new THREE.ExtrudeGeometry(shape, { + depth: 0.06, + bevelEnabled: false, + }); + g.rotateX(-Math.PI / 2); + g.translate(0, 0.02, 0); + return g; + }, [seed, radius]); + + return ( + + + + ); +}; + +// ─── Lagoon ─────────────────────────────────────────────────────────────────── +const Lagoon = ({ seed }: { seed: number }) => { + const rng = makeRng(seed * 61 + 19); + const r = 0.22 + rng() * 0.18; + const ox = (rng() - 0.5) * 0.5; + const oz = (rng() - 0.5) * 0.5; + // Compute the ellipse y-radius using the RNG (mirrors previous ellipseGeometry usage) + const ry = r * (0.7 + rng() * 0.3); + const meshRef = useRef(null!); + + useFrame(({ clock }) => { + if (meshRef.current) { + ( + meshRef.current.material as THREE.MeshStandardMaterial + ).emissiveIntensity = 0.18 + Math.sin(clock.elapsedTime * 1.1) * 0.06; + } + }); + return ( + + + + + ); +}; + +// ─── Flower patch ───────────────────────────────────────────────────────────── +const FlowerPatch = ({ + position, + seed, +}: { + position: [number, number, number]; + seed: number; +}) => { + const rng = makeRng(seed * 43 + 17); + const count = 3 + Math.floor(rng() * 4); + const COLORS = [ + "#ff6b9d", + "#ffd93d", + "#ff8c42", + "#c77dff", + "#ff4d6d", + "#ff9f1c", + ]; + return ( + + {Array.from({ length: count }, (_, i) => { + const angle = rng() * Math.PI * 2; + const r = rng() * 0.18; + const color = COLORS[Math.floor(rng() * COLORS.length)]; + return ( + + + + + + + + + + + ); + })} + + ); +}; + +// ─── Island hut ─────────────────────────────────────────────────────────────── +const IslandHut = ({ + position, + scale, + seed, +}: { + position: [number, number, number]; + scale: number; + seed: number; +}) => { + const rng = makeRng(seed * 73 + 23); + const roofColor = rng() > 0.5 ? "#c17f3a" : "#8b5e3c"; + return ( + + + + + + + + + + + + + + + ); +}; + +// ─── Terrain orchestrator ───────────────────────────────────────────────────── +const IslandTerrain = ({ + seed, + isLocked, +}: { + seed: number; + isLocked: boolean; +}) => { + const rng = makeRng(seed * 1000 + 42); + + // Six archetypes: 0=tropical 1=volcanic 2=snowy 3=savanna 4=jungle 5=desert + const archetype = Math.floor(rng() * 6); + const hasMountain = archetype === 1 || archetype === 2 || rng() > 0.55; + const hasSnow = archetype === 2; + const palmCount = + archetype === 0 || archetype === 3 + ? 2 + Math.floor(rng() * 3) + : Math.floor(rng() * 2); + const pineCount = + archetype === 4 ? 2 + Math.floor(rng() * 3) : Math.floor(rng() * 2); + const rockCount = 1 + Math.floor(rng() * 3); + const hasBeach = archetype !== 2 && rng() > 0.3; + const hasLagoon = rng() > 0.6; + const flowerCount = + archetype === 4 || archetype === 0 + ? 2 + Math.floor(rng() * 3) + : Math.floor(rng() * 2); + const hasHut = rng() > 0.65; + + if (isLocked) return null; + + // Each call advances rng to a stable position for that feature + const spot = (spread = 0.65): [number, number, number] => { + const a = rng() * Math.PI * 2; + const r = rng() * spread; + return [Math.sin(a) * r, 0, Math.cos(a) * r]; + }; + + return ( + + {hasBeach && } + {hasLagoon && } + + {hasMountain && ( + + )} + + {Array.from({ length: palmCount }, (_, i) => ( + + ))} + {Array.from({ length: pineCount }, (_, i) => ( + + ))} + {Array.from({ length: rockCount }, (_, i) => ( + + ))} + {Array.from({ length: flowerCount }, (_, i) => ( + + ))} + {hasHut && ( + + )} + + ); +}; + +// ─── Current island marker ──────────────────────────────────────────────────── +const CurrentMarker = ({ accent }: { accent: string }) => { + const groupRef = useRef(null!); + const innerRef = useRef(null!); + const ringRef = useRef(null!); + const beamRef = useRef(null!); + + const accentColor = useMemo(() => new THREE.Color(accent), [accent]); + const goldColor = useMemo(() => new THREE.Color("#fbbf24"), []); + const torusGeo = useMemo( + () => new THREE.TorusGeometry(0.38, 0.045, 12, 48), + [], + ); + const spokeGeo = useMemo( + () => new THREE.CylinderGeometry(0.022, 0.022, 0.6, 8), + [], + ); + const orbGeo = useMemo(() => new THREE.SphereGeometry(0.1, 16, 16), []); + const beamGeo = useMemo( + () => new THREE.CylinderGeometry(0.018, 0.05, 1.6, 8, 1, true), + [], + ); + const haloGeo = useMemo(() => new THREE.CircleGeometry(0.55, 40), []); + + useFrame(({ clock }) => { + const t = clock.elapsedTime; + if (groupRef.current) + groupRef.current.position.y = 2.1 + Math.sin(t * 1.4) * 0.18; + if (innerRef.current) innerRef.current.rotation.y = t * 0.55; + if (ringRef.current) + ( + ringRef.current.material as THREE.MeshStandardMaterial + ).emissiveIntensity = 0.6 + Math.sin(t * 2.2) * 0.35; + if (beamRef.current) + (beamRef.current.material as THREE.MeshStandardMaterial).opacity = + 0.18 + Math.sin(t * 1.8 + 1) * 0.1; + }); + + return ( + + + + + + + + + + + + {[0, Math.PI / 2, Math.PI, (3 * Math.PI) / 2].map((angle, i) => ( + + + + ))} + {[ + { pos: [0, 0.38, 0] as [number, number, number], scale: 1.0 }, + { pos: [0, -0.38, 0] as [number, number, number], scale: 0.7 }, + { pos: [0.38, 0, 0] as [number, number, number], scale: 0.7 }, + { pos: [-0.38, 0, 0] as [number, number, number], scale: 0.7 }, + ].map(({ pos, scale }, i) => ( + + + + + ))} + + + + + + + YOU ARE HERE + + + + ); +}; + +// ─── Island3D ───────────────────────────────────────────────────────────────── +export const Island3D = ({ + node, + position, + accent, + terrain, + onTap, + onClaim, + index, + isCurrent = false, + modalOpen = false, +}: Island3DProps) => { + const topMeshRef = useRef(null!); + const [hovered, setHovered] = useState(false); + + const status = (node.status?.toUpperCase() ?? + "LOCKED") as keyof typeof PALETTE; + const isLocked = status === "LOCKED"; + const isClaimable = status === "CLAIMABLE"; + const isActive = status === "ACTIVE"; + const isCompleted = status === "COMPLETED"; + const seed = index * 13 + 7; + + const { topGeo, cliffGeo } = useMemo(() => { + const topShape = makeIslandShape(seed, 1.0); + const topGeo = new THREE.ExtrudeGeometry(topShape, { + depth: 0.32, + bevelEnabled: true, + bevelThickness: 0.12, + bevelSize: 0.08, + bevelSegments: 5, + }); + topGeo.rotateX(-Math.PI / 2); + + const cliffShape = makeIslandShape(seed, 1.14); + const cliffGeo = new THREE.ExtrudeGeometry(cliffShape, { + depth: 0.58, + bevelEnabled: true, + bevelThickness: 0.06, + bevelSize: 0.04, + bevelSegments: 2, + }); + cliffGeo.rotateX(-Math.PI / 2); + cliffGeo.translate(0, -0.3, 0); + return { topGeo, cliffGeo }; + }, [seed]); + + const pal = PALETTE[status]; + const topColor = isActive + ? terrain.l + : isCompleted + ? PALETTE.COMPLETED.top + : pal.top; + const sideColor = isActive + ? terrain.m + : isCompleted + ? PALETTE.COMPLETED.side + : pal.side; + + useFrame((_, dt) => { + if (!topMeshRef.current) return; + const target = hovered && !isLocked ? 1.07 : 1.0; + const curr = topMeshRef.current.scale.x; + topMeshRef.current.scale.setScalar( + curr + (target - curr) * (1 - Math.exp(-14 * dt)), + ); + }); + + const emoji = isLocked + ? "🔒" + : isClaimable + ? "📦" + : isCompleted + ? "✅" + : (REQ_EMOJI[node.req_type] ?? "🏝️"); + const pct = + node.req_target > 0 + ? Math.min(100, Math.round((node.current_value / node.req_target) * 100)) + : 0; + const ringColor = isClaimable ? "#fbbf24" : isCompleted ? "#4ade80" : accent; + + return ( + + { + e.stopPropagation(); + if (!isLocked) setHovered(true); + }} + onPointerLeave={(e) => { + e.stopPropagation(); + setHovered(false); + }} + onClick={(e) => { + e.stopPropagation(); + if (!isLocked) onTap(node); + }} + > + {/* Top plateau */} + + + + + {/* Cliff */} + + + + + {/* Procedural terrain */} + + + {/* Water-level glow ring */} + {!isLocked && ( + + + + + )} + + {/* Claimable sparkles */} + {isClaimable && ( + <> + + + + + + + )} + + {/* Hover ring */} + {hovered && !isLocked && ( + + + + + )} + + {/* Emoji */} + + + {emoji} + + + + {/* Current marker */} + {isCurrent && } + + {/* Info card */} + +
{ + e.stopPropagation(); + if (!isLocked) onTap(node); + }} + style={{ + width: C.width, + background: isClaimable + ? "rgba(28,18,4,0.96)" + : isLocked + ? "rgba(12,18,28,0.72)" + : "rgba(5,12,24,0.93)", + border: `1px solid ${ + isClaimable + ? "rgba(251,191,36,0.65)" + : isCompleted + ? "rgba(74,222,128,0.45)" + : isActive + ? `${accent}55` + : "rgba(255,255,255,0.1)" + }`, + borderLeft: `3px solid ${ + isClaimable + ? "#fbbf24" + : isCompleted + ? "#4ade80" + : isActive + ? accent + : "rgba(255,255,255,0.2)" + }`, + borderRadius: C.borderRadius, + padding: `${C.padV}px ${C.padH}px ${C.padVb}px`, + backdropFilter: "blur(16px)", + WebkitBackdropFilter: "blur(16px)", + boxShadow: isClaimable + ? "0 0 24px rgba(251,191,36,0.28), 0 6px 20px rgba(0,0,0,0.6)" + : "0 6px 20px rgba(0,0,0,0.55)", + opacity: isLocked ? 0.5 : 1, + cursor: isLocked ? "default" : "pointer", + userSelect: "none", + fontFamily: "'Nunito', 'Nunito Sans', sans-serif", + }} + > +
+ {node.name ?? "—"} +
+ +
+ + ⚡ {node.reward_xp} XP + + + {isClaimable + ? "✨ Claim!" + : isCompleted + ? "Done" + : isLocked + ? "Locked" + : `${pct}%`} + +
+ + {isActive && node.req_target > 0 && ( +
+
+
+ )} + + {isClaimable && ( + + )} +
+ + + + ); +}; diff --git a/src/components/LessonModal.tsx b/src/components/LessonModal.tsx index 24955f7..f720daa 100644 --- a/src/components/LessonModal.tsx +++ b/src/components/LessonModal.tsx @@ -1,87 +1,344 @@ -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState, Suspense } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, - DialogDescription, } from "../components/ui/dialog"; import { api } from "../utils/api"; import { useAuthStore } from "../stores/authStore"; +import { Loader, X } from "lucide-react"; +import { LESSON_COMPONENT_MAP } from "./FetchLessonPage"; +import type { LessonId } from "./FetchLessonPage"; +import type { LessonDetails } from "../types/lesson"; interface LessonModalProps { - lessonId: string | null; + selectedLessonData: { id: string | null; name: string | null }; open: boolean; onOpenChange: (open: boolean) => void; } +// UUIDs are video lessons; local lessons use readable keys like "ebrw-main-idea" +const UUID_REGEX = + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; +const isVideoLesson = (id: string) => UUID_REGEX.test(id); + +const STYLES = ` + @import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;800;900&family=Nunito+Sans:wght@400;600;700&display=swap'); + + .lm-content { + font-family: 'Nunito', sans-serif; + background: #fffbf4; + border: 2.5px solid #f3f4f6; + border-radius: 28px !important; + padding: 0; + overflow: hidden; + max-width: 680px; + width: calc(100vw - 2rem); + box-shadow: 0 20px 60px rgba(0,0,0,0.12); + max-height: 90vh; + display: flex; + flex-direction: column; + } + + @media (min-width: 1024px) { + .lm-content { + max-width: 1000px; + } + } + .lm-dialog-header-hidden { + position: absolute; width: 1px; height: 1px; + padding: 0; margin: -1px; overflow: hidden; + clip: rect(0,0,0,0); white-space: nowrap; border: 0; + } + .lm-header { + display: flex; align-items: flex-start; justify-content: space-between; + padding: 1.25rem 1.5rem 0; flex-shrink: 0; gap: 1rem; + } + .lm-title-wrap { display:flex; flex-direction:column; gap:0.2rem; flex:1; } + .lm-eyebrow { + font-size: 0.62rem; font-weight: 800; letter-spacing: 0.16em; + text-transform: uppercase; color: #a855f7; + } + .lm-title { + font-size: 1.2rem; font-weight: 900; color: #1e1b4b; + letter-spacing: -0.01em; line-height: 1.25; + } + .lm-close-btn { + width: 34px; height: 34px; flex-shrink: 0; + border-radius: 50%; border: 2.5px solid #f3f4f6; + background: white; cursor: pointer; + display: flex; align-items: center; justify-content: center; + box-shadow: 0 2px 8px rgba(0,0,0,0.06); transition: all 0.15s ease; + } + .lm-close-btn:hover { border-color: #fecdd3; background: #fff1f2; } + .lm-body { + overflow-y: auto; flex: 1; + padding: 1rem 1.5rem 1.5rem; + display: flex; flex-direction: column; gap: 1rem; + -webkit-overflow-scrolling: touch; + } + .lm-video { + width: 100%; border-radius: 18px; + aspect-ratio: 16/9; background: #1e1b4b; display: block; + } + .lm-topic-chip { + display: inline-flex; align-items: center; gap: 0.4rem; + background: #f3e8ff; border: 2px solid #e9d5ff; + border-radius: 100px; padding: 0.3rem 0.8rem; + font-size: 0.7rem; font-weight: 800; letter-spacing: 0.08em; + text-transform: uppercase; color: #9333ea; width: fit-content; + } + .lm-card { + background: white; border: 2.5px solid #f3f4f6; + border-radius: 18px; padding: 1rem 1.1rem; + box-shadow: 0 3px 10px rgba(0,0,0,0.04); + } + .lm-card-label { + font-size: 0.62rem; font-weight: 800; letter-spacing: 0.14em; + text-transform: uppercase; color: #9ca3af; margin-bottom: 0.4rem; + } + .lm-card-text { + font-family: 'Nunito Sans', sans-serif; + font-size: 0.88rem; font-weight: 600; color: #374151; line-height: 1.6; + } + .lm-loading { + display: flex; flex-direction: column; align-items: center; + justify-content: center; gap: 0.75rem; padding: 3rem 1.5rem; flex: 1; + } + .lm-loading-spinner { animation: lmSpin 0.8s linear infinite; } + @keyframes lmSpin { to { transform: rotate(360deg); } } + .lm-loading-text { font-size: 0.85rem; font-weight: 700; color: #9ca3af; } + .lm-error { + display: flex; flex-direction: column; align-items: center; + justify-content: center; gap: 0.5rem; + padding: 3rem 1.5rem; text-align: center; flex: 1; + } + .lm-error-emoji { font-size: 2rem; } + .lm-error-text { font-size: 0.85rem; font-weight: 700; color: #9ca3af; } + + /* Resources list */ + .lm-resources { display: flex; flex-direction: column; gap: 0.5rem; } + .lm-resource-link { + display: flex; align-items: center; gap: 0.6rem; + padding: 0.6rem 0.8rem; border-radius: 12px; + background: #f5f3ff; border: 1.5px solid #e9d5ff; + color: #7c3aed; font-size: 0.8rem; font-weight: 700; + text-decoration: none; transition: background 0.15s ease; + } + .lm-resource-link:hover { background: #ede9fe; } + + /* Creator badge */ + .lm-creator { + display: flex; align-items: center; gap: 0.5rem; + font-family: 'Nunito Sans', sans-serif; + font-size: 0.75rem; font-weight: 600; color: #9ca3af; + } + .lm-creator-avatar { + width: 24px; height: 24px; border-radius: 50%; + background: linear-gradient(135deg, #a855f7, #3b82f6); + display: flex; align-items: center; justify-content: center; + font-size: 0.65rem; font-weight: 900; color: white; flex-shrink: 0; + } +`; + +const LoadingSpinner = () => ( +
+ +

Loading lesson...

+
+); + export const LessonModal = ({ - lessonId, + selectedLessonData, open, + onOpenChange, }: LessonModalProps) => { const user = useAuthStore((state) => state.user); + const [loading, setLoading] = useState(false); - const [lesson, setLesson] = useState(null); + const [lesson, setLesson] = useState(null); + const [error, setError] = useState(false); + const fetchingForId = useRef(null); + const lessonId = selectedLessonData.id; + + const LocalLessonComponent = + lessonId && !isVideoLesson(lessonId) + ? LESSON_COMPONENT_MAP[lessonId as LessonId] + : null; + + // const modalTitle = LocalLessonComponent + // ? getLocalLessonTitle(lessonId!) + // : loading + // ? "Loading..." + // : (lesson?.title ?? "Lesson"); + + const modalTitle = + selectedLessonData.name || selectedLessonData.id || "Lesson"; useEffect(() => { - if (!open || !lessonId || !user) return; + if (!open) { + setLesson(null); + setLoading(false); + setError(false); + fetchingForId.current = null; + return; + } + + if (!lessonId || !user || LocalLessonComponent) return; + if (fetchingForId.current === lessonId) return; const fetchLesson = async () => { + fetchingForId.current = lessonId; + setLesson(null); + setError(false); + setLoading(true); + try { - setLoading(true); - const authStorage = localStorage.getItem("auth-storage"); - if (!authStorage) return; + if (!authStorage) throw new Error("No auth storage"); + const { + // @ts-ignore + state: { token }, + } = JSON.parse(authStorage) as { state?: { token?: string } }; + if (!token) throw new Error("No token"); - const parsed = JSON.parse(authStorage) as { - state?: { token?: string }; - }; + // @ts-ignore + const response: LessonDetails = await api.fetchLessonById( + token, + lessonId, + ); - const token = parsed.state?.token; - if (!token) return; - - const response = await api.fetchLessonById(token, lessonId); + if (fetchingForId.current !== lessonId) return; setLesson(response); } catch (err) { console.error("Failed to fetch lesson", err); + if (fetchingForId.current === lessonId) setError(true); } finally { - setLoading(false); + if (fetchingForId.current === lessonId) setLoading(false); } }; fetchLesson(); - }, [open, lessonId, user]); + }, [open, lessonId, user, LocalLessonComponent]); + + // topic on LessonDetails is Topic[] — use the first entry + const topicName = Array.isArray(lesson?.topic) + ? lesson.topic[0]?.name + : ((lesson?.topic as any)?.name ?? null); return ( - - {loading && ( -
- Loading lesson... -
- )} - - {lesson ? lesson.title : "Lesson details"} + + + + {modalTitle} - {!loading && lesson && ( -
- {lesson.video_url && ( -