commit 5bb0c57c8e8e17a747a57cf9284f35e15ddc333a Author: ahmadafriadi Date: Tue Jul 21 15:44:23 2026 +0700 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/README.md b/README.md new file mode 100644 index 0000000..03ee3ff --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# web-anindhaloka + +## Requirements + +- **Node.js** `^20.19.0` atau `>=22.12.0` +- **npm** (terpasang bersama Node.js) + +## Instalasi + +1. Clone/masuk ke folder project: + ```bash + cd web-anindhaloka + ``` +2. Install dependencies: + ```bash + npm install + ``` +3. (Opsional) Buat file `.env` di root project untuk mengatur URL backend API: + ``` + VITE_API_URL=http://localhost:8000 + ``` + Jika tidak diset, default-nya `http://localhost:8000`. + +## Menjalankan di Local + +```bash +npm run dev +``` + +Buka `http://localhost:5173` di browser. + +## Perintah Lain + +| Perintah | Fungsi | +|---|---| +| `npm run dev` | Jalankan dev server | +| `npm run build` | Type-check + build produksi ke folder `dist/` | +| `npm run preview` | Preview hasil build produksi secara lokal | +| `npm run lint` | Jalankan ESLint | + +## Dependencies + +### Dependencies (runtime) + +| Package | Versi | +|---|---| +| `framer-motion` | ^12.42.2 | +| `lucide-react` | ^1.17.0 | +| `react` | ^19.2.6 | +| `react-dom` | ^19.2.6 | +| `react-router-dom` | ^7.16.0 | + +### devDependencies (build & tooling) + +| Package | Versi | +|---|---| +| `@eslint/js` | ^10.0.1 | +| `@types/node` | ^24.12.3 | +| `@types/react` | ^19.2.14 | +| `@types/react-dom` | ^19.2.3 | +| `@vitejs/plugin-react` | ^6.0.1 | +| `eslint` | ^10.3.0 | +| `eslint-plugin-react-hooks` | ^7.1.1 | +| `eslint-plugin-react-refresh` | ^0.5.2 | +| `globals` | ^17.6.0 | +| `typescript` | ~6.0.2 | +| `typescript-eslint` | ^8.59.2 | +| `vite` | ^8.0.12 | diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..ef614d2 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,22 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + globals: globals.browser, + }, + }, +]) diff --git a/index.html b/index.html new file mode 100644 index 0000000..c1c465e --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Anindhaloka — Rumah Gotong Royong + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..55c2f4e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2847 @@ +{ + "name": "web-anindhaloka", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "web-anindhaloka", + "version": "0.0.0", + "dependencies": { + "framer-motion": "^12.42.2", + "lucide-react": "^1.17.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "react-router-dom": "^7.16.0" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^24.12.3", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.6.0", + "typescript": "~6.0.2", + "typescript-eslint": "^8.59.2", + "vite": "^8.0.12" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "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", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "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", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", + "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "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", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "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", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.16", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.16.tgz", + "integrity": "sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz", + "integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/type-utils": "8.60.1", + "@typescript-eslint/utils": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.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.60.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz", + "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "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 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", + "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.60.1", + "@typescript-eslint/types": "^8.60.1", + "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.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", + "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1" + }, + "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.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", + "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", + "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.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz", + "integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/utils": "8.60.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.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 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", + "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", + "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.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", + "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.60.1", + "@typescript-eslint/tsconfig-utils": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.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.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", + "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1" + }, + "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 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", + "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", + "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "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/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "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.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "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/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.366", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.366.tgz", + "integrity": "sha512-OlRuhb688YTCzzU3gXPLn6nGyd+F+53INE1qaKKlu6kETErE8FYsyDh0XqXEU+uBRn0MpCzz2vfNwORhkap8qg==", + "dev": true, + "license": "ISC" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.1.tgz", + "integrity": "sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.6.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.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", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "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 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz", + "integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "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", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/framer-motion": { + "version": "12.42.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.42.2.tgz", + "integrity": "sha512-5XY9luDiu0oHfHBjpDthFMh0ES+122w6p/papSJBweMkO8Sn+PW2QaEgRblQBpWFnuvZS5qvarpt/hO2pjGmnw==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.42.2", + "motion-utils": "^12.39.0", + "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==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.17.0.tgz", + "integrity": "sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/motion-dom": { + "version": "12.42.2", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.42.2.tgz", + "integrity": "sha512-5gIMWLp/PycBtJRJWRgjxke5n8dlvkSn2DrYW+tr3XcqAZY1xZh6BJyooJXCM8wdfM7wfMjkBJNLge1CKPUIRA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "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", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "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", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, + "node_modules/react-router": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.16.0.tgz", + "integrity": "sha512-wArC8lVyJb3+jM9OpDyW6hLCizACWkvQR/sSGqSs+o5uEXEtGlqdZ4v8hENR3Jad6i+LRkK93q/+bQAcvl6V1A==", + "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.16.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.16.0.tgz", + "integrity": "sha512-kMUAbimWB5FVbF4Bce4bJsiKJWLIUHq/mEG8+CFDnCSgltptBiG5nguducmsJeGKytlCvQud9Qhzpn49iduTlA==", + "license": "MIT", + "dependencies": { + "react-router": "7.16.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz", + "integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.60.1", + "@typescript-eslint/parser": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/utils": "8.60.1" + }, + "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 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "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", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" + }, + "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", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.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 + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "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/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..c40df29 --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "web-anindhaloka", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "framer-motion": "^12.42.2", + "lucide-react": "^1.17.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "react-router-dom": "^7.16.0" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^24.12.3", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.6.0", + "typescript": "~6.0.2", + "typescript-eslint": "^8.59.2", + "vite": "^8.0.12" + } +} diff --git a/public/assets/images/Anindhaloka.jpg b/public/assets/images/Anindhaloka.jpg new file mode 100644 index 0000000..fe3afa3 Binary files /dev/null and b/public/assets/images/Anindhaloka.jpg differ diff --git a/public/assets/logo/anindhaloka-icon.png b/public/assets/logo/anindhaloka-icon.png new file mode 100644 index 0000000..a50c94b Binary files /dev/null and b/public/assets/logo/anindhaloka-icon.png differ diff --git a/public/assets/logo/anindhaloka-logo-original.png b/public/assets/logo/anindhaloka-logo-original.png new file mode 100644 index 0000000..0322732 Binary files /dev/null and b/public/assets/logo/anindhaloka-logo-original.png differ diff --git a/public/assets/logo/anindhaloka-wordmark.png b/public/assets/logo/anindhaloka-wordmark.png new file mode 100644 index 0000000..e0c7388 Binary files /dev/null and b/public/assets/logo/anindhaloka-wordmark.png differ diff --git a/public/assets/logo/ekosistem/bhumi-anindha/logo-bhumi-color.png b/public/assets/logo/ekosistem/bhumi-anindha/logo-bhumi-color.png new file mode 100644 index 0000000..e3deba1 Binary files /dev/null and b/public/assets/logo/ekosistem/bhumi-anindha/logo-bhumi-color.png differ diff --git a/public/assets/logo/ekosistem/bhumi-anindha/mark.png b/public/assets/logo/ekosistem/bhumi-anindha/mark.png new file mode 100644 index 0000000..c672d02 Binary files /dev/null and b/public/assets/logo/ekosistem/bhumi-anindha/mark.png differ diff --git a/public/assets/logo/ekosistem/learnin/LearnNIN_Logo_Icon_Orange.png b/public/assets/logo/ekosistem/learnin/LearnNIN_Logo_Icon_Orange.png new file mode 100644 index 0000000..a3e8fdc Binary files /dev/null and b/public/assets/logo/ekosistem/learnin/LearnNIN_Logo_Icon_Orange.png differ diff --git a/public/assets/logo/ekosistem/learnin/mark.png b/public/assets/logo/ekosistem/learnin/mark.png new file mode 100644 index 0000000..9dd8a3b Binary files /dev/null and b/public/assets/logo/ekosistem/learnin/mark.png differ diff --git a/public/assets/logo/ekosistem/paon/logo Paon 3 - red.png b/public/assets/logo/ekosistem/paon/logo Paon 3 - red.png new file mode 100644 index 0000000..e9183c1 Binary files /dev/null and b/public/assets/logo/ekosistem/paon/logo Paon 3 - red.png differ diff --git a/public/assets/logo/ekosistem/paon/mark.png b/public/assets/logo/ekosistem/paon/mark.png new file mode 100644 index 0000000..8735e95 Binary files /dev/null and b/public/assets/logo/ekosistem/paon/mark.png differ diff --git a/public/assets/logo/ekosistem/pasar-bahagia/Logo Pasar Bahagia.png b/public/assets/logo/ekosistem/pasar-bahagia/Logo Pasar Bahagia.png new file mode 100644 index 0000000..798a0fe Binary files /dev/null and b/public/assets/logo/ekosistem/pasar-bahagia/Logo Pasar Bahagia.png differ diff --git a/public/assets/logo/ekosistem/pasar-bahagia/mark.png b/public/assets/logo/ekosistem/pasar-bahagia/mark.png new file mode 100644 index 0000000..90baa68 Binary files /dev/null and b/public/assets/logo/ekosistem/pasar-bahagia/mark.png differ diff --git a/public/icons.svg b/public/icons.svg new file mode 100644 index 0000000..e952219 --- /dev/null +++ b/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..f90339d --- /dev/null +++ b/src/App.css @@ -0,0 +1,184 @@ +.counter { + font-size: 16px; + padding: 5px 10px; + border-radius: 5px; + color: var(--accent); + background: var(--accent-bg); + border: 2px solid transparent; + transition: border-color 0.3s; + margin-bottom: 24px; + + &:hover { + border-color: var(--accent-border); + } + &:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + } +} + +.hero { + position: relative; + + .base, + .framework, + .vite { + inset-inline: 0; + margin: 0 auto; + } + + .base { + width: 170px; + position: relative; + z-index: 0; + } + + .framework, + .vite { + position: absolute; + } + + .framework { + z-index: 1; + top: 34px; + height: 28px; + transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) + scale(1.4); + } + + .vite { + z-index: 0; + top: 107px; + height: 26px; + width: auto; + transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) + scale(0.8); + } +} + +#center { + display: flex; + flex-direction: column; + gap: 25px; + place-content: center; + place-items: center; + flex-grow: 1; + + @media (max-width: 1024px) { + padding: 32px 20px 24px; + gap: 18px; + } +} + +#next-steps { + display: flex; + border-top: 1px solid var(--border); + text-align: left; + + & > div { + flex: 1 1 0; + padding: 32px; + @media (max-width: 1024px) { + padding: 24px 20px; + } + } + + .icon { + margin-bottom: 16px; + width: 22px; + height: 22px; + } + + @media (max-width: 1024px) { + flex-direction: column; + text-align: center; + } +} + +#docs { + border-right: 1px solid var(--border); + + @media (max-width: 1024px) { + border-right: none; + border-bottom: 1px solid var(--border); + } +} + +#next-steps ul { + list-style: none; + padding: 0; + display: flex; + gap: 8px; + margin: 32px 0 0; + + .logo { + height: 18px; + } + + a { + color: var(--text-h); + font-size: 16px; + border-radius: 6px; + background: var(--social-bg); + display: flex; + padding: 6px 12px; + align-items: center; + gap: 8px; + text-decoration: none; + transition: box-shadow 0.3s; + + &:hover { + box-shadow: var(--shadow); + } + .button-icon { + height: 18px; + width: 18px; + } + } + + @media (max-width: 1024px) { + margin-top: 20px; + flex-wrap: wrap; + justify-content: center; + + li { + flex: 1 1 calc(50% - 8px); + } + + a { + width: 100%; + justify-content: center; + box-sizing: border-box; + } + } +} + +#spacer { + height: 88px; + border-top: 1px solid var(--border); + @media (max-width: 1024px) { + height: 48px; + } +} + +.ticks { + position: relative; + width: 100%; + + &::before, + &::after { + content: ''; + position: absolute; + top: -4.5px; + border: 5px solid transparent; + } + + &::before { + left: 0; + border-left-color: var(--border); + } + &::after { + right: 0; + border-right-color: var(--border); + } +} diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..bb02624 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,89 @@ +import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom'; +import { useEffect } from 'react'; +import { MotionConfig } from 'framer-motion'; +import Navbar from './components/Navbar'; +import Footer from './components/Footer'; +import PageTransition from './components/PageTransition'; +import Home from './pages/Home'; +import BhumiAnindha from './pages/BhumiAnindha'; +import PAON from './pages/PAON'; +import KaIND from './pages/KaIND'; +import CittaRahayu from './pages/CittaRahayu'; +import PasarBahagia from './pages/PasarBahagia'; +import LearnNIN from './pages/LearnNIN'; +import LokaNIN from './pages/LokaNIN'; +import PesanRuang from './pages/PesanRuang'; +import TemanNIN from './pages/TemanNIN'; +import Bergabung from './pages/Bergabung'; +import Tentang from './pages/Tentang'; +import Kontak from './pages/Kontak'; +import AdminLogin from './pages/admin/AdminLogin'; +import AdminDashboard from './pages/admin/AdminDashboard'; +import AdminContent from './pages/admin/AdminContent'; +import AdminMedia from './pages/admin/AdminMedia'; +import AdminSettings from './pages/admin/AdminSettings'; +import './index.css'; + +function ScrollToTop() { + const { pathname } = useLocation(); + useEffect(() => { window.scrollTo(0, 0); }, [pathname]); + return null; +} + +function AppContent() { + const { pathname } = useLocation(); + const isAdmin = pathname.startsWith('/admin'); + + if (isAdmin) { + return ( + <> + + + } /> + } /> + } /> + } /> + } /> + + + ); + } + + return ( +
+ + + +
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+
+
+ ); +} + +function App() { + return ( + + + + + + ); +} + +export default App; diff --git a/src/assets/hero.png b/src/assets/hero.png new file mode 100644 index 0000000..02251f4 Binary files /dev/null and b/src/assets/hero.png differ diff --git a/src/assets/react.svg b/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/vite.svg b/src/assets/vite.svg new file mode 100644 index 0000000..5101b67 --- /dev/null +++ b/src/assets/vite.svg @@ -0,0 +1 @@ +Vite diff --git a/src/components/ArcDivider.tsx b/src/components/ArcDivider.tsx new file mode 100644 index 0000000..5c0b2a6 --- /dev/null +++ b/src/components/ArcDivider.tsx @@ -0,0 +1,50 @@ +interface ArcDividerProps { + /** Warna section berikutnya — bagian di bawah lengkung diisi warna ini. */ + fill: string; + flip?: boolean; + height?: number; + /** Garis aksen tipis menyusuri lengkungan — dipakai supaya lengkung tetap terlihat jelas + * meski warna section sebelum & sesudahnya sama-sama gelap/mirip. */ + stroke?: string; + strokeWidth?: number; +} + +/** Divider lengkung lembut antar-section, menggantikan sambungan garis lurus. + * Overlap negatif ke section sebelumnya bawaan, supaya bagian transparan di atas lengkung + * menampilkan warna/gradient section sebelumnya, dan bagian terisi menyatu ke section berikutnya. */ +export default function ArcDivider({ fill, flip = false, height = 64, stroke, strokeWidth = 2 }: ArcDividerProps) { + return ( + + ); +} diff --git a/src/components/CountUp.tsx b/src/components/CountUp.tsx new file mode 100644 index 0000000..be5273a --- /dev/null +++ b/src/components/CountUp.tsx @@ -0,0 +1,34 @@ +import { useEffect, useRef, useState } from 'react'; +import { animate, useInView, useReducedMotion } from 'framer-motion'; + +interface CountUpProps { + to: number; + duration?: number; + prefix?: string; + suffix?: string; + className?: string; +} + +/** Animasi angka dari 0 saat masuk viewport (dipakai untuk angka pencapaian). */ +export default function CountUp({ to, duration = 1.6, prefix = '', suffix = '', className }: CountUpProps) { + const ref = useRef(null); + const inView = useInView(ref, { once: true, margin: '-80px' }); + const prefersReduced = useReducedMotion(); + const [display, setDisplay] = useState(0); + + useEffect(() => { + if (!inView) return; + const controls = animate(0, to, { + duration: prefersReduced ? 0 : duration, + ease: [0.22, 1, 0.36, 1], + onUpdate: (v) => setDisplay(Math.round(v)), + }); + return () => controls.stop(); + }, [inView, to, duration, prefersReduced]); + + return ( + + {prefix}{display.toLocaleString('id-ID')}{suffix} + + ); +} diff --git a/src/components/EcosystemIcons.tsx b/src/components/EcosystemIcons.tsx new file mode 100644 index 0000000..4a899c0 --- /dev/null +++ b/src/components/EcosystemIcons.tsx @@ -0,0 +1,158 @@ +import type { ReactElement } from 'react'; +import modules from '../data/modules'; + +interface GlyphProps { + color: string; +} + +/* + * Tiap glyph berbagi bahasa visual yang sama dengan logo asli: lengkung tebal berujung + * bulat (bukan garis lurus/ikon linear) + aksen "matahari" mustard yang identik di semua ikon + * (dirender sekali di EcosystemIcon). Glyph di bawah ini hanya menggambar lengkung + satu + * aksen pembeda kecil per modul. + */ + +function BhumiAnindhaGlyph({ color }: GlyphProps) { + return ( + <> + + + + + ); +} + +function PaonGlyph({ color }: GlyphProps) { + return ( + <> + + + + + ); +} + +function KaindGlyph({ color }: GlyphProps) { + return ( + <> + + + + ); +} + +function CittaRahayuGlyph({ color }: GlyphProps) { + return ( + <> + + + + ); +} + +function PasarBahagiaGlyph({ color }: GlyphProps) { + return ( + <> + + + + ); +} + +function LearnninGlyph({ color }: GlyphProps) { + return ( + <> + + + + ); +} + +function LokaninGlyph({ color }: GlyphProps) { + return ( + <> + + + + ); +} + +function TemanninGlyph({ color }: GlyphProps) { + return ( + <> + + + + + + ); +} + +const GLYPHS: Record ReactElement> = { + 'bhumi-anindha': BhumiAnindhaGlyph, + paon: PaonGlyph, + kaind: KaindGlyph, + 'citta-rahayu': CittaRahayuGlyph, + 'pasar-bahagia': PasarBahagiaGlyph, + learnnin: LearnninGlyph, + lokanin: LokaninGlyph, + temannin: TemanninGlyph, +}; + +interface EcosystemIconProps { + id: string; + size?: number; + withBackdrop?: boolean; + className?: string; +} + +/** Ikon custom gaya bulat per modul ekosistem — satu keluarga visual dengan logo (lengkung + aksen matahari). */ +export default function EcosystemIcon({ id, size = 40, withBackdrop = true, className }: EcosystemIconProps) { + const m = modules.find(mod => mod.id === id); + const Glyph = GLYPHS[id]; + if (!m || !Glyph) return null; + + return ( + + {withBackdrop && } + + + + ); +} + +interface ModuleMarkProps { + id: string; + size?: number; + className?: string; + /** Bungkus dengan latar putih bulat — perlu untuk logo resmi (warnanya beragam, ada yang hitam) di atas permukaan gelap. */ + withBadge?: boolean; +} + +/** + * Penanda modul untuk slot kecil (dropdown nav, footer, dsb): pakai logo resmi bila sudah + * tersedia (dibatasi kotak size×size, object-fit contain supaya rasio logo tetap aman), + * jatuh ke EcosystemIcon custom bila belum ada logo untuk modul tersebut. + */ +export function ModuleMark({ id, size = 24, className, withBadge = false }: ModuleMarkProps) { + const m = modules.find(mod => mod.id === id); + if (!m) return null; + + if (m.logoImage) { + const badgeSize = withBadge ? size + 10 : size; + return ( + + {m.name} + + ); + } + + return ; +} diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..b255891 --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,94 @@ +import { Link } from 'react-router-dom'; +import modules from '../data/modules'; +import { ModuleMark } from './EcosystemIcons'; + +const half1 = modules.slice(0, 4); +const half2 = modules.slice(4); + +export default function Footer() { + return ( +
+
+
+
+ + Anindhaloka + anindhaloka + +

+ Ekosistem digital gaya hidup berkesadaran yang menghubungkan pangan, sandang, olah diri, dan komunitas dalam satu perjalanan yang bermakna. +

+
+ 📷 + 📘 + ▶️ + 💬 +
+
+ +
+

Ekosistem I

+
    + {half1.map(m => ( +
  • + + {m.name} + +
  • + ))} +
+
+ +
+

Ekosistem II

+
    + {half2.map(m => ( +
  • + + {m.name} + +
  • + ))} +
+
+ +
+

Informasi

+ +
+

Kontak

+

+ +62 815 7330 5808 (Welin Cakra)
+ @anindhaloka_id +

+
+
+
+ +
+ © 2025 Anindhaloka. Dibuat dengan cinta untuk bumi dan komunitas. + 🌿 Conscious Living Ecosystem +
+
+
+ ); +} diff --git a/src/components/IDGWheel.tsx b/src/components/IDGWheel.tsx new file mode 100644 index 0000000..0f65971 --- /dev/null +++ b/src/components/IDGWheel.tsx @@ -0,0 +1,271 @@ +import { useState } from 'react'; +import { motion, useReducedMotion, type Variants } from 'framer-motion'; + +const C = 300; +const MAIN_R = 148; +const SKILL_R = 252; +const CAT_CR = 64; +const SKL_CR = 33; + +interface Cat { + name: string[]; + sub: string[]; + fill: string; + stroke: string; + angle: number; + skills: string[][]; +} + +const cats: Cat[] = [ + { + name: ['Being'], sub: ['Relationships', 'to Self'], + fill: '#EDE4F8', stroke: '#7C5BAE', angle: 270, + skills: [ + ['Integrity &', 'authenticity'], ['Inner', 'compass'], + ['Openness &', 'learning'], ['Self-', 'awareness'], ['Presence'], + ], + }, + { + name: ['Thinking'], sub: ['Cognitive', 'Skills'], + fill: '#FDDEEE', stroke: '#C8426A', angle: 342, + skills: [ + ['Critical', 'thinking'], ['Complexity'], + ['Perspective', 'skills'], ['Sense-', 'making'], ['Long-term', 'vision'], + ], + }, + { + name: ['Relating'], sub: ['Caring for', 'Others & World'], + fill: '#D6F2EC', stroke: '#2A8E78', angle: 54, + skills: [ + ['Appreciation'], ['Connected-', 'ness'], + ['Empathy &', 'Compassion'], ['Humility'], + ], + }, + { + name: ['Collab-', 'orating'], sub: ['Social', 'Skills'], + fill: '#DFF2D0', stroke: '#4A8A28', angle: 126, + skills: [ + ['Communi-', 'cation'], ['Co-creation', 'skills'], + ['Inclusive', 'mindset'], ['Trust'], ['Mobilisation'], + ], + }, + { + name: ['Acting'], sub: ['Enabling', 'Change'], + fill: '#D8E8F8', stroke: '#2A6EBE', angle: 198, + skills: [ + ['Courage'], ['Creativity'], + ['Optimism'], ['Perseve-', 'rance'], + ], + }, +]; + +const toRad = (d: number) => (d * Math.PI) / 180; +const xy = (angle: number, r: number) => ({ + x: C + r * Math.cos(toRad(angle)), + y: C + r * Math.sin(toRad(angle)), +}); + +function skillAngles(catAngle: number, count: number) { + const spread = count <= 1 ? 0 : Math.min(38, (count - 1) * 19); + return Array.from({ length: count }, (_, i) => + count > 1 ? catAngle - spread + i * ((spread * 2) / (count - 1)) : catAngle + ); +} + +interface IDGWheelProps { + /** Aktifkan bila komponen ditaruh di atas latar gelap — label eyebrow/hint diganti warna terang. */ + light?: boolean; +} + +const wheelContainer: Variants = { + hidden: {}, + show: { transition: { staggerChildren: 0.09, delayChildren: 0.15 } }, +}; +const catVariants: Variants = { + hidden: { opacity: 0, scale: 0.3 }, + show: { opacity: 1, scale: 1, transition: { duration: 0.55, ease: [0.34, 1.56, 0.64, 1] } }, +}; + +export default function IDGWheel({ light = false }: IDGWheelProps) { + const [open, setOpen] = useState(null); + const prefersReduced = useReducedMotion(); + + function handleClick(i: number) { + setOpen(prev => (prev === i ? null : i)); + } + + return ( +
+

+ Inner Development Goals +

+

+ Klik kategori untuk melihat sub-keterampilan +

+ + + {/* Outer guide ring */} + + + {/* Inner background */} + + + {cats.map((cat, i) => { + const cp = xy(cat.angle, MAIN_R); + const isOpen = open === i; + const angles = skillAngles(cat.angle, cat.skills.length); + + /* vertical text positioning helpers */ + const nameLH = 15, subLH = 11; + const nameTH = (cat.name.length - 1) * nameLH; + const subTH = (cat.sub.length - 1) * subLH; + const blockH = nameTH + 6 + subTH; + const nameY0 = cp.y - blockH / 2; + const subY0 = nameY0 + nameTH + 6; + + return ( + + {/* ── Skills group – animated out from category center ── */} + + {angles.map((a, j) => { + const sp = xy(a, SKILL_R); + return ( + + ); + })} + + {cat.skills.map((lines, j) => { + const sp = xy(angles[j], SKILL_R); + const lh = 10.5; + const th = (lines.length - 1) * lh; + return ( + + + {lines.map((ln, li) => ( + + {ln} + + ))} + + ); + })} + + + {/* ── Category circle – always visible, clickable ── */} + handleClick(i)} + style={{ cursor: 'pointer', transformOrigin: `${cp.x}px ${cp.y}px` }} + role="button" + aria-expanded={isOpen} + whileHover={prefersReduced ? undefined : { scale: 1.06 }} + whileTap={prefersReduced ? undefined : { scale: 0.97 }} + transition={{ type: 'spring', stiffness: 350, damping: 20 }} + > + {/* glow ring */} + + {/* main circle */} + + + {/* category name */} + {cat.name.map((ln, ni) => ( + + {ln} + + ))} + {/* sub label */} + {cat.sub.map((ln, si) => ( + + {ln} + + ))} + + {/* open/close indicator dot */} + + + + ); + })} + + {/* ── Center emblem ── */} + + + + + + +
+ ); +} diff --git a/src/components/ModulePage.tsx b/src/components/ModulePage.tsx new file mode 100644 index 0000000..52d12e9 --- /dev/null +++ b/src/components/ModulePage.tsx @@ -0,0 +1,144 @@ +import { Link } from 'react-router-dom'; +import { ArrowRight, ChevronRight } from 'lucide-react'; +import type { Module } from '../data/modules'; +import EcosystemIcon from './EcosystemIcons'; + +interface Props { + module: Module; +} + +export default function ModulePage({ module: m }: Props) { + return ( + <> + {/* Hero */} +
+
+
+ +
+ + {m.tagline} +
+

{m.name}

+

{m.description}

+
+ + Lihat Program + + + Tanya Kami + +
+
+
+ + {/* About Module */} +
+
+
+

Tentang {m.name}

+

+ {m.tagline} +

+

+ {m.longDesc} +

+
+
+
+ + {/* Features */} +
+
+
+

Program & Layanan

+

Apa yang kami tawarkan

+

Temukan berbagai program dan layanan yang dirancang untuk mendukung perjalananmu.

+
+
+ {m.features.map((f, i) => ( +
+
+ {f.icon} +
+

{f.title}

+

{f.desc}

+
+ ))} +
+
+
+ + {/* CTA Banner */} +
+
+
+

Siap memulai perjalananmu?

+

+ Bergabunglah bersama komunitas {m.name} dan rasakan perbedaannya. +

+ {m.contact && ( +

+ {m.contact.join(' · ')} +

+ )} +
+
+ + Hubungi Kami + + + Daftar Sekarang + +
+
+
+ + {/* Other modules */} +
+
+
+

Ekosistem Anindhaloka

+

Jelajahi modul lainnya

+
+
+ {['/bhumi-anindha', '/paon', '/kaind', '/citta-rahayu', '/pasar-bahagia', '/learnnin', '/lokanin', '/temannin'] + .filter(p => p !== m.path) + .map(p => { + const mod = { '/bhumi-anindha': { icon: '🌱', name: 'Bhumi Anindha' }, '/paon': { icon: '🍽️', name: 'PAON' }, '/kaind': { icon: '🧵', name: 'KaIND' }, '/citta-rahayu': { icon: '🧘', name: 'Citta Rahayu' }, '/pasar-bahagia': { icon: '🏪', name: 'Pasar Bahagia' }, '/learnnin': { icon: '📚', name: 'LearnNIN' }, '/lokanin': { icon: '🏡', name: 'LokaNIN' }, '/temannin': { icon: '🤝', name: 'TemanNIN' } }[p]; + if (!mod) return null; + return ( + + {mod.icon} {mod.name} + + ); + })} +
+
+
+ + ); +} diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx new file mode 100644 index 0000000..6d58fbd --- /dev/null +++ b/src/components/Navbar.tsx @@ -0,0 +1,140 @@ +import { useState, useEffect, useRef } from 'react'; +import { Link, useLocation } from 'react-router-dom'; +import { Menu, X, ChevronDown, ArrowRight } from 'lucide-react'; +import modules from '../data/modules'; +import { ModuleMark } from './EcosystemIcons'; + +export default function Navbar() { + const [menuOpen, setMenuOpen] = useState(false); + const [scrolled, setScrolled] = useState(false); + const [dropOpen, setDropOpen] = useState(false); + const location = useLocation(); + const isHome = location.pathname === '/'; + const dropRef = useRef(null); + + useEffect(() => { + const onScroll = () => setScrolled(window.scrollY > 60); + window.addEventListener('scroll', onScroll); + return () => window.removeEventListener('scroll', onScroll); + }, []); + + useEffect(() => { + setMenuOpen(false); + setDropOpen(false); + }, [location.pathname]); + + useEffect(() => { + document.body.style.overflow = menuOpen ? 'hidden' : ''; + return () => { document.body.style.overflow = ''; }; + }, [menuOpen]); + + const transparent = isHome && !scrolled; + + return ( + + ); +} diff --git a/src/components/PageTransition.tsx b/src/components/PageTransition.tsx new file mode 100644 index 0000000..4df26db --- /dev/null +++ b/src/components/PageTransition.tsx @@ -0,0 +1,49 @@ +import { useEffect, useRef, useState } from 'react'; +import { useLocation } from 'react-router-dom'; +import { AnimatePresence, motion, useReducedMotion } from 'framer-motion'; + +/** Overlay transisi singkat saat pindah halaman — logo Anindhaloka muncul sekilas. */ +export default function PageTransition() { + const location = useLocation(); + const prefersReduced = useReducedMotion(); + const [show, setShow] = useState(false); + const firstRender = useRef(true); + + useEffect(() => { + if (firstRender.current) { + firstRender.current = false; + return; + } + setShow(true); + const t = setTimeout(() => setShow(false), prefersReduced ? 200 : 650); + return () => clearTimeout(t); + }, [location.pathname, prefersReduced]); + + return ( + + {show && ( + + + + )} + + ); +} diff --git a/src/components/Reveal.tsx b/src/components/Reveal.tsx new file mode 100644 index 0000000..626a4c2 --- /dev/null +++ b/src/components/Reveal.tsx @@ -0,0 +1,37 @@ +import { motion, useReducedMotion, type Variants } from 'framer-motion'; +import type { CSSProperties, ReactNode } from 'react'; + +interface RevealProps { + children: ReactNode; + delay?: number; + className?: string; + style?: CSSProperties; +} + +const variants: Variants = { + hidden: { opacity: 0, scale: 0.96, y: 24 }, + show: { opacity: 1, scale: 1, y: 0 }, +}; + +/** Wrapper scroll-reveal — elemen "tumbuh" (scale + translateY) saat masuk viewport. */ +export default function Reveal({ children, delay = 0, className, style }: RevealProps) { + const prefersReduced = useReducedMotion(); + + if (prefersReduced) { + return
{children}
; + } + + return ( + + {children} + + ); +} diff --git a/src/components/TiltCard.tsx b/src/components/TiltCard.tsx new file mode 100644 index 0000000..f87c921 --- /dev/null +++ b/src/components/TiltCard.tsx @@ -0,0 +1,55 @@ +import { useRef } from 'react'; +import type { CSSProperties, PointerEvent, ReactNode } from 'react'; +import { motion, useMotionValue, useReducedMotion, useSpring, useTransform } from 'framer-motion'; + +interface TiltCardProps { + children: ReactNode; + className?: string; + style?: CSSProperties; + max?: number; +} + +/** Tilt 3D lembut mengikuti posisi pointer + lift saat hover — dipakai untuk kartu inisiatif. */ +export default function TiltCard({ children, className, style, max = 6 }: TiltCardProps) { + const ref = useRef(null); + const prefersReduced = useReducedMotion(); + + const px = useMotionValue(0.5); + const py = useMotionValue(0.5); + const springConfig = { stiffness: 200, damping: 20, mass: 0.5 }; + const sx = useSpring(px, springConfig); + const sy = useSpring(py, springConfig); + + const rotateX = useTransform(sy, [0, 1], [max, -max]); + const rotateY = useTransform(sx, [0, 1], [-max, max]); + + function handleMove(e: PointerEvent) { + if (prefersReduced || !ref.current || e.pointerType === 'touch') return; + const rect = ref.current.getBoundingClientRect(); + px.set((e.clientX - rect.left) / rect.width); + py.set((e.clientY - rect.top) / rect.height); + } + + function handleLeave() { + px.set(0.5); + py.set(0.5); + } + + if (prefersReduced) { + return
{children}
; + } + + return ( + + {children} + + ); +} diff --git a/src/data/modules.ts b/src/data/modules.ts new file mode 100644 index 0000000..a553c51 --- /dev/null +++ b/src/data/modules.ts @@ -0,0 +1,186 @@ +export interface Module { + id: string; + path: string; + name: string; + tagline: string; + description: string; + longDesc: string; + icon: string; + color: string; + colorBg: string; + gradientFrom: string; + gradientTo: string; + features: { icon: string; title: string; desc: string }[]; + contact?: string[]; + /** Logo resmi modul (jika sudah tersedia) — dipakai di kartu ekosistem menggantikan ikon custom. */ + logoImage?: string; +} + +const modules: Module[] = [ + { + id: 'bhumi-anindha', + path: '/bhumi-anindha', + name: 'Bhumi Anindha', + tagline: 'Pangan Lestari', + description: 'Berkebun di Kota, Berbagi Kehidupan — akar dari meja makan lewat pertanian regeneratif perkotaan.', + longDesc: 'Bhumi Anindha adalah undangan untuk kembali, terhubung, dan tumbuh bersama bumi yang sama. Kami percaya kota bisa menjadi tempat yang menghidupkan, bukan menguras — lewat pertanian regeneratif yang menghormati keselarasan dengan alam, gotong royong, kedaulatan pangan, dan kesehatan holistik. Setiap kebun yang kami rawat, dari kebun dapur hingga hutan pangan, dibangun dengan satu prinsip: tidak ada yang terbuang, semua kembali.', + icon: '🌱', + color: '#4A7C59', + colorBg: '#E8F2E4', + gradientFrom: '#1A3A1F', + gradientTo: '#2D5016', + features: [ + { icon: '🌾', title: 'Kebun Lestari', desc: 'Kebun dapur, kebun produksi, hutan pangan, kolam ikan, dan dapur komunal — dengan satu prinsip: tidak ada yang terbuang, semua kembali.' }, + { icon: '📋', title: 'Program Bhumi', desc: 'Ruang Hidup Lestari, Belajar Lestari, Komunitas Lestari, Pasar Bahagia (CSA), dan Jasa Lestari — lima jalur program yang saling menopang.' }, + { icon: '🌿', title: 'Keselarasan dengan Alam', desc: 'Pertanian regeneratif yang menempatkan alam sebagai mitra, bukan sumber daya untuk dieksploitasi.' }, + { icon: '🤝', title: 'Gotong Royong & Kedaulatan Pangan', desc: 'Kebun sebagai ruang belajar bersama, dibangun atas inklusivitas dan keadilan pangan.' }, + { icon: '🙌', title: 'Cara Bergabung', desc: 'Jadi relawan, anggota CSA, peserta lokakarya, atau tamu berkebun akhir pekan — semua pintu terbuka.' }, + ], + contact: ['IG @bhumi.anindha', '+123-456-7890 (kontak sedang diperbarui)'], + logoImage: '/assets/logo/ekosistem/bhumi-anindha/mark.png', + }, + { + id: 'paon', + path: '/paon', + name: 'PAON', + tagline: 'Olah Rasa', + description: 'Good Food · Great Taste — dapur sebagai ruang penyatuan, gastronomi Nusantara dengan teknik global dan jiwa lokal.', + longDesc: 'PAON lahir dari keresahan nyata terhadap krisis pangan urban, dan menjawabnya dengan makanan yang lezat, bercerita, dan berpengalaman penuh makna. Kami berpijak pada tiga akar: Good Food yang baik untuk tubuh manusia dan bumi, Gastronomy Glocal dengan teknik global dan jiwa lokal, serta perpaduan gastronomi, sains, dan kearifan lokal. Lima makna Good Food kami hidupkan lewat setiap hidangan: healing cuisine, low carb by design, inclusive by default, wholesome & nourishing, dan responsible sourcing.', + icon: '🍽️', + color: '#C4693A', + colorBg: '#FAF0EA', + gradientFrom: '#5C2810', + gradientTo: '#8B3D1A', + features: [ + { icon: '🍲', title: 'Rasa', desc: 'All-Day Dining, 10.00–21.00 WIB, dengan 36 kursi (22 indoor + 14 outdoor).' }, + { icon: '🎪', title: 'Pasar Bahagia Pop-Up', desc: 'Partisipasi rutin di setiap penyelenggaraan Pasar Bahagia.' }, + { icon: '🛍️', title: 'Warung Lestari', desc: 'Curated retail store — produk fermentasi dan lokal, masing-masing dengan kartu cerita.' }, + { icon: '🧺', title: 'Piknik Bahagia', desc: 'Garden dining experience di ruang terbuka.' }, + { icon: '👨‍🍳', title: 'Olah Rasa', desc: 'Workshop & kelas memasak, 2–3 jam, maksimal 12 peserta.' }, + { icon: '🍷', title: 'Cerita Rasa', desc: 'Thematic dinner 5–7 course, maksimal 20 tamu, sebulan sekali.' }, + ], + logoImage: '/assets/logo/ekosistem/paon/mark.png', + }, + { + id: 'kaind', + path: '/kaind', + name: 'KaIND', + tagline: 'Sandang Berkesadaran', + description: 'Menghidupkan Serat, Menenun Masa Depan — pakaian sebagai pernyataan nilai, dari serat dan pewarna alami.', + longDesc: 'KaIND menenun perjalanan sandang dari ladang ke helai kain — bersama petani serat alam di Bali, Tuban, Wonosobo, dan Subang, ditenun oleh perajin ATBM di Pasuruan, Bali, dan Pekalongan. Warna-warna kami lahir dari bumi: indigo, mengkudu, kulit kayu, dan rempah lokal. Ini adalah ekosistem, bukan sekadar produk — melibatkan petani, pengrajin, perempuan pelaku produksi, dan konsumen yang sadar akan pilihannya.', + icon: '🧵', + color: '#5B6E8E', + colorBg: '#EEF1F7', + gradientFrom: '#1E2D40', + gradientTo: '#2E4560', + features: [ + { icon: '🌾', title: 'Kain Serat Alami', desc: 'Dari petani di Bali, Tuban, Wonosobo, dan Subang, ditenun ATBM oleh perajin di Pasuruan, Bali, dan Pekalongan.' }, + { icon: '👗', title: 'Fashion', desc: 'Pakaian yang bercerita, dibuat dari kain bernyawa.' }, + { icon: '👜', title: 'Aksesori', desc: 'Pelengkap yang menghidupkan setiap detail penampilan.' }, + { icon: '🏠', title: 'Interior & Home Living', desc: 'Sentuhan serat alami untuk ruang tinggal.' }, + { icon: '✂️', title: 'Made to Order', desc: 'Pesan pakaian yang dibuat khusus sesuai ukuran dan pilihan kain Anda.' }, + { icon: '🎨', title: 'Warna dari Bumi', desc: 'Pewarna alami dari indigo, mengkudu, kulit kayu, dan rempah lokal.' }, + ], + }, + { + id: 'citta-rahayu', + path: '/citta-rahayu', + name: 'Citta Rahayu', + tagline: 'Olah Diri Berkesadaran', + description: 'Ruang pulang ke diri sendiri — yoga, meditasi, singing bowl, dan ragam praktik olah diri lainnya.', + longDesc: 'Citta Rahayu merawat tiga dimensi kemanusiaan: Badan Kasar lewat gerak, sentuhan, dan napas; Badan Halus lewat meditasi, suara, dan keheningan; serta Badan Penyebab, kepenuhan yang paling mendasar dalam diri. Di sinilah setiap orang diundang untuk pulang ke dirinya sendiri, lewat ragam praktik yang menyeimbangkan tubuh, pikiran, dan jiwa.', + icon: '🧘', + color: '#7C5E9E', + colorBg: '#F2EEF7', + gradientFrom: '#2E1A45', + gradientTo: '#4A2E6B', + features: [ + { icon: '🧘', title: 'Ragam Praktik', desc: 'Yoga, Meditasi, Sound Bathing, Singing Bowl, Dance of Universal Peace, Tai Chi, Body Massage, dan Tuina.' }, + { icon: '🌤️', title: 'Singgah', desc: 'Kegiatan musiman untuk yang ingin mampir dan merasakan sejenak.' }, + { icon: '🌱', title: 'Rawat', desc: 'Praktik berkala untuk membangun kebiasaan merawat diri secara konsisten.' }, + { icon: '👥', title: 'Kumpul', desc: 'Pertemuan komunitas untuk berbagi dan tumbuh bersama.' }, + { icon: '🏔️', title: 'Pulang', desc: 'Retreat mendalam untuk pemulihan dan penyatuan diri yang utuh.' }, + ], + }, + { + id: 'pasar-bahagia', + path: '/pasar-bahagia', + name: 'Pasar Bahagia', + tagline: 'Ekosistem Kolaboratif', + description: 'Pasar lokal untuk membangun gaya hidup lestari berbasis komunitas, dalam spirit gotong royong.', + longDesc: 'Pasar Bahagia adalah perayaan gotong royong — ruang tempat produsen lokal, pengrajin, dan konsumen sadar bertemu dalam ekosistem yang adil dan menyenangkan. Kami percaya pada lima nilai: Lokal, Inklusif, Budaya Nusantara, Lestari, dan Rahayu. Digelar sejak 2023, Pasar Bahagia kini menjadi rumah bagi puluhan jenama lokal dan ribuan kunjungan komunitas.', + icon: '🏪', + color: '#C4803A', + colorBg: '#FAF2EA', + gradientFrom: '#3D2010', + gradientTo: '#6B3A15', + features: [ + { icon: '📅', title: 'Digelar Sejak 2023', desc: 'Dimulai dengan 37 jenama, kini rutin digelar dua bulan sekali.' }, + { icon: '🏪', title: '60+ Jenama Lokal', desc: 'Bagian dari Komunitas Kreator Bahagia yang terus bertumbuh.' }, + { icon: '🎓', title: '50+ Kegiatan Edukasi', desc: 'Workshop dan sesi belajar yang telah terselenggara bersama komunitas.' }, + { icon: '👣', title: '2.000+ Kunjungan TemanNIN', desc: 'Jejak komunitas yang terus hadir dan bertumbuh bersama Pasar Bahagia.' }, + { icon: '📣', title: 'Jadi Storyteller', desc: 'Bagikan cerita dan dokumentasikan perjalanan Pasar Bahagia.' }, + { icon: '🕸️', title: 'Perluas Jejaring', desc: 'Hubungkan Pasar Bahagia dengan komunitas dan mitra baru.' }, + { icon: '💰', title: 'Akses Pendanaan', desc: 'Dukung keberlanjutan program lewat kolaborasi pendanaan.' }, + ], + contact: ['+62 815 7330 5808 (Welin Cakra)', '@anindhaloka_id', '@kreasi.nin'], + logoImage: '/assets/logo/ekosistem/pasar-bahagia/mark.png', + }, + { + id: 'learnnin', + path: '/learnnin', + name: 'LearnNIN', + tagline: 'Ruang Belajar Berkesadaran', + description: 'Payung program riset, pembelajaran, dan kreativitas — pembelajaran sebagai perjalanan, bukan ujian.', + longDesc: 'LearnNIN adalah payung yang menaungi seluruh program pembelajaran Anindhaloka, dijalani dengan semangat riset, pencerahan, dan kreativitas. Setiap program adalah undangan untuk menjelajahi satu dimensi kehidupan: seni, alam, komunitas, dan transformasi diri — karena bagi kami, pembelajaran adalah perjalanan, bukan ujian.', + icon: '📚', + color: '#3A8B8B', + colorBg: '#E8F5F5', + gradientFrom: '#0F2E2E', + gradientTo: '#1C4D4D', + features: [ + { icon: '🌱', title: 'Ruang yang Sedang Tumbuh', desc: 'Daftar program LearnNIN sedang kami tumbuhkan bersama komunitas. Hubungi kami untuk info terbaru atau mengusulkan kolaborasi program.' }, + ], + logoImage: '/assets/logo/ekosistem/learnin/mark.png', + }, + { + id: 'lokanin', + path: '/lokanin', + name: 'LokaNIN', + tagline: 'Ruang Temu Komunitas', + description: 'Ruang fisik dan energetik tempat komunitas berakar — ruang yang hidup adalah ruang yang dihuni.', + longDesc: 'LokaNIN adalah ruang fisik sekaligus energetik yang dibuka untuk komunitas dan mitra menggelar kegiatan sendiri — diskusi, lokakarya, pameran, latihan rutin, hingga pertemuan. Kami percaya ruang yang hidup adalah ruang yang dihuni, tempat setiap pertemuan bisa menjadi awal dari sebuah gerakan.', + icon: '🏡', + color: '#9E5A4A', + colorBg: '#F7EEEC', + gradientFrom: '#2D1510', + gradientTo: '#5C2A20', + features: [ + { icon: '🏛️', title: 'Booking Ruang', desc: 'Pesan ruang untuk diskusi, lokakarya, pameran, latihan rutin, atau pertemuan komunitas.' }, + { icon: '🎪', title: 'Event Komunitas', desc: 'Kalender kegiatan yang digelar bersama komunitas dan mitra LokaNIN.' }, + { icon: '🤝', title: 'Ruang Kolaborasi', desc: 'Ruang yang terbuka bagi siapa saja yang ingin berkarya dan berjejaring bersama.' }, + { icon: '📸', title: 'Ruang yang Sedang Tumbuh', desc: 'Nama ruang, foto, dan contoh kegiatan sedang kami lengkapi bersama komunitas. Hubungi kami untuk info dan ketersediaan terkini.' }, + ], + contact: ['+62 815 7330 5808 (Welin Cakra)', '@anindhaloka_id', '@kreasi.nin'], + }, + { + id: 'temannin', + path: '/temannin', + name: 'TemanNIN', + tagline: 'Jejaring Anindhaloka', + description: 'Lingkaran anggota dan mitra yang terus melebar — individu, komunitas, usaha, pemerintah, LSM, dan media.', + longDesc: 'TemanNIN adalah jejaring anggota dan mitra Anindhaloka yang terus melebar — terbuka untuk individu, komunitas, usaha, pemerintah, LSM, dan media. Menjadi TemanNIN bukan soal mendaftar dan mendapatkan kartu anggota; ini soal memilih untuk terhubung dengan nilai, komunitas, dan gerakan yang sedang tumbuh.', + icon: '🤝', + color: '#8B7540', + colorBg: '#F5F0E0', + gradientFrom: '#2A2010', + gradientTo: '#4A3A1A', + features: [ + { icon: '🌱', title: 'Bukan Sekadar Kartu Anggota', desc: 'Menjadi TemanNIN berarti memilih untuk terhubung dengan nilai, komunitas, dan gerakan yang sedang tumbuh.' }, + { icon: '🔗', title: 'Lingkaran yang Melebar', desc: 'Jaringan anggota dan mitra terbuka yang terus berkembang bersama ekosistem Anindhaloka.' }, + { icon: '🌾', title: 'Terbuka untuk Semua', desc: 'Individu, komunitas, usaha, pemerintah, LSM, hingga media — semua punya tempat di TemanNIN.' }, + ], + }, +]; + +export default modules; diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..f7ef5f1 --- /dev/null +++ b/src/index.css @@ -0,0 +1,849 @@ +@import url('https://fonts.googleapis.com/css2?family=Baloo+2:wght@600;700;800&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@500;600&display=swap'); + +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +:root { + /* ── Brand Primary — Plum (dari logo asli) ── */ + --maroon-950: #1E1216; + --maroon-900: #2F1D24; + --maroon-800: #4A2E38; + --maroon-700: #5B3A46; + --maroon-600: #734B59; + --maroon-500: #916272; + --maroon-400: #B08492; + --maroon-300: #CCA8B2; + --maroon-200: #E3CCD2; + --maroon-100: #F3E5E8; + --maroon-50: #FAF2F4; + + /* ── Forest — Hijau Zaitun (hero gelap Tentang/Kontak/Bergabung) ── */ + --forest-950: #141C0E; + --forest-900: #1E2A16; + --forest-800: #2B3D20; + --forest-700: #3C5429; + --forest-600: #4F6B3A; + --forest-500: #6C8659; + --forest-400: #8FA57C; + --forest-300: #B2C2A0; + --forest-200: #D2DCC4; + --forest-100: #E9EEE0; + --forest-50: #F5F7F0; + + /* ── Logo Icon Accent Colors ── */ + --amber: #F0B429; + --amber-light: #FDE68A; + --coral: #D4552B; + --coral-light: #F2B49E; + --terracotta: #D4552B; + --sage: #4F6B3A; + --sage-light: #AEBE8E; + + /* ── Warm Earth / Neutral ── */ + --earth-800: #63351A; + --earth-700: #93583A; + --earth-600: #B37048; + --earth-500: #CC8C5E; + --earth-400: #D9A468; + --earth-300: #E4C48F; + --earth-200: #EDD9B5; + --earth-100: #F5EDD8; + --earth-50: #FDF9F3; + + --cream: #F2ECDD; + --warm-white: #FBF7EE; + + --text-900: #2A2520; + --text-700: #3A342E; + --text-500: #5A524A; + --text-300: #8A8076; + --text-100: #C0B8AE; + + --font-heading: 'Baloo 2', 'Poppins', system-ui, sans-serif; + --font-body: 'Inter', system-ui, sans-serif; + --font-mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace; + + --max-w: 1200px; + --nav-h: 72px; + + --r-sm: 6px; + --r-md: 12px; + --r-lg: 20px; + --r-xl: 32px; + --r-full: 9999px; + + --sh-sm: 0 1px 4px rgba(0,0,0,.06); + --sh-md: 0 4px 16px rgba(0,0,0,.08), 0 2px 4px rgba(0,0,0,.04); + --sh-lg: 0 12px 40px rgba(0,0,0,.10), 0 4px 8px rgba(0,0,0,.05); + --sh-xl: 0 24px 64px rgba(0,0,0,.12), 0 8px 16px rgba(0,0,0,.06); + + --ease: cubic-bezier(.4,0,.2,1); + --ease-organic: cubic-bezier(.22,1,.36,1); + --ease-bounce: cubic-bezier(.34,1.56,.64,1); + + font-family: var(--font-body); + font-size: 16px; + line-height: 1.65; + color: var(--text-500); + background: var(--warm-white); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { margin: 0; } +img, svg { display: block; max-width: 100%; } +a { text-decoration: none; color: inherit; } +button { cursor: pointer; font-family: inherit; } +ul { list-style: none; } + +#root { min-height: 100vh; display: flex; flex-direction: column; } + +/* ─── Typography ─────────────────────────────────────────── */ +h1, h2, h3, h4 { + font-family: var(--font-heading); + color: var(--text-900); + line-height: 1.15; + font-weight: 600; +} +h1 { font-size: clamp(2.4rem, 5vw, 4rem); } +h2 { font-size: clamp(1.8rem, 3.5vw, 2.8rem); } +h3 { font-size: clamp(1.3rem, 2.5vw, 1.8rem); } +h4 { font-size: 1.15rem; font-weight: 600; } + +.eyebrow { + font-family: var(--font-mono); + font-size: .72rem; + font-weight: 600; + letter-spacing: .14em; + text-transform: uppercase; + color: var(--maroon-600); +} +.eyebrow--light { color: rgba(255,255,255,.55); } +.eyebrow--amber { color: var(--amber); } + +/* ─── Layout ─────────────────────────────────────────────── */ +.container { width: 100%; max-width: var(--max-w); margin-inline: auto; padding-inline: 24px; } + +.section { padding-block: 80px; } +.section--lg { padding-block: 112px; } +.section--sm { padding-block: 48px; } + +.section__header { text-align: center; margin-bottom: 56px; } +.section__header p { margin-top: 16px; font-size: 1.05rem; color: var(--text-300); max-width: 540px; margin-inline: auto; } + +.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; } +.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; } +.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; } +.grid-auto { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 24px; +} +.grid-auto > * { + flex: 1 1 280px; + max-width: calc((100% - 48px) / 3); +} +@media (max-width: 1024px) { + .grid-auto > * { max-width: calc((100% - 24px) / 2); } +} +@media (max-width: 640px) { + .grid-auto > * { flex: 0 0 100%; max-width: 100%; } +} + +@media (max-width: 1024px) { + .grid-4 { grid-template-columns: repeat(2, 1fr); } + .grid-3 { grid-template-columns: repeat(2, 1fr); } +} +@media (max-width: 640px) { + .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } + .section { padding-block: 56px; } + .section--lg { padding-block: 72px; } +} + +/* ─── Buttons ─────────────────────────────────────────────── */ +.btn { + display: inline-flex; align-items: center; gap: 8px; + padding: 12px 28px; border-radius: var(--r-full); + font-weight: 700; font-size: .9rem; letter-spacing: .02em; + transition: transform .35s var(--ease-bounce), background-color .25s var(--ease), border-color .25s var(--ease), box-shadow .25s var(--ease), color .25s var(--ease); + border: 2px solid transparent; + white-space: nowrap; +} + +.btn--primary { + background: var(--terracotta); color: #fff; border-color: var(--terracotta); +} +.btn--primary:hover { + background: #B8461F; border-color: #B8461F; + transform: translateY(-2px) scale(1.02); + box-shadow: 0 8px 24px rgba(212,85,43,.4); +} + +.btn--outline { + background: transparent; color: var(--maroon-700); border-color: var(--maroon-700); +} +.btn--outline:hover { + background: var(--maroon-700); color: #fff; transform: translateY(-1px); +} + +.btn--outline-light { + background: transparent; color: #fff; border-color: rgba(255,255,255,.55); +} +.btn--outline-light:hover { + background: rgba(255,255,255,.14); border-color: #fff; +} + +.btn--amber { + background: var(--amber); color: var(--maroon-900); border-color: var(--amber); +} +.btn--amber:hover { + background: #D9961A; border-color: #D9961A; + transform: translateY(-1px); box-shadow: 0 8px 24px rgba(240,180,41,.4); +} + +.btn--earth { + background: var(--earth-700); color: #fff; border-color: var(--earth-700); +} +.btn--earth:hover { + background: var(--earth-800); border-color: var(--earth-800); + transform: translateY(-1px); box-shadow: 0 8px 24px rgba(139,94,60,.35); +} + +.btn--lg { padding: 16px 40px; font-size: 1rem; } +.btn--sm { padding: 8px 20px; font-size: .825rem; } + +/* ─── Navbar ─────────────────────────────────────────────── */ +.navbar { + position: fixed; top: 0; left: 0; right: 0; z-index: 100; + height: var(--nav-h); + transition: background .3s var(--ease), box-shadow .3s var(--ease); +} + +.navbar--solid { + background: rgba(253,250,245,.97); + backdrop-filter: blur(12px); + box-shadow: 0 1px 0 rgba(0,0,0,.07); +} + +.navbar__container { + max-width: var(--max-w); margin-inline: auto; padding-inline: 24px; + height: 100%; display: flex; align-items: center; gap: 40px; +} + +.navbar__logo { + flex-shrink: 0; display: flex; align-items: center; gap: 10px; +} + +.navbar__logo-text { + font-family: var(--font-body); + font-size: 1.35rem; + font-weight: 800; + letter-spacing: -.02em; + color: var(--maroon-800); +} + +.navbar__nav { + display: flex; align-items: center; gap: 4px; flex: 1; +} + +.navbar__link { + display: inline-flex; align-items: center; gap: 4px; + padding: 8px 12px; border-radius: var(--r-sm); + font-size: .875rem; font-weight: 600; + color: var(--text-700); background: none; border: none; + transition: color .2s, background .2s; +} +.navbar__link:hover { color: var(--maroon-700); background: var(--maroon-50); } + +.navbar__dropdown { position: relative; } + +.navbar__dropdown-menu { + position: absolute; top: calc(100% + 8px); left: 50%; + transform: translateX(-50%); + background: #fff; border-radius: var(--r-md); box-shadow: var(--sh-xl); + padding: 8px; min-width: 700px; + display: grid; grid-template-columns: 1fr 1fr; gap: 2px; + border: 1px solid var(--earth-100); +} + +.navbar__dropdown-item { + display: block; padding: 10px 14px; border-radius: var(--r-sm); + transition: background .2s; +} +.navbar__dropdown-item:hover { background: var(--maroon-50); } +.navbar__dropdown-name { display: block; font-weight: 700; font-size: .875rem; color: var(--text-900); } +.navbar__dropdown-desc { display: block; font-size: .75rem; color: var(--text-300); margin-top: 1px; } + +.navbar__cta { margin-left: auto; flex-shrink: 0; } + +.navbar__hamburger { + display: none; background: none; border: none; + color: var(--maroon-800); margin-left: auto; padding: 8px; +} + +.navbar__mobile { + position: fixed; inset: var(--nav-h) 0 0 0; + background: var(--warm-white); overflow-y: auto; + padding: 16px 0 32px; display: flex; flex-direction: column; +} + +.navbar__mobile-link { + display: block; padding: 12px 24px; font-weight: 600; + color: var(--text-700); border-bottom: 1px solid var(--earth-100); +} +.navbar__mobile-link--sub { + padding-left: 40px; font-size: .875rem; color: var(--text-500); font-weight: 500; +} + +.navbar__mobile-section-title { + display: block; padding: 12px 24px 8px; + font-size: .72rem; font-weight: 800; + text-transform: uppercase; letter-spacing: .12em; color: var(--maroon-600); +} + +@media (max-width: 900px) { + .navbar__nav, .navbar__cta { display: none; } + .navbar__hamburger { display: flex; } +} + +/* ─── Hero ───────────────────────────────────────────────── */ +.hero { + min-height: 100vh; + background: linear-gradient(160deg, var(--maroon-950) 0%, var(--maroon-900) 35%, #3A2430 65%, #46283A 100%); + display: flex; align-items: center; position: relative; overflow: hidden; +} + +.hero::before { + content: ''; + position: absolute; inset: 0; + background: + radial-gradient(ellipse 70% 60% at 75% 50%, rgba(212,85,43,.14) 0%, transparent 55%), + radial-gradient(ellipse 40% 50% at 20% 80%, rgba(240,180,41,.09) 0%, transparent 50%); +} + +.hero__decor { + position: absolute; right: -60px; top: 50%; transform: translateY(-50%); + width: 560px; height: 560px; border-radius: 50%; + border: 1px solid rgba(255,255,255,.05); +} +.hero__decor::before { + content: ''; position: absolute; inset: 60px; border-radius: 50%; + border: 1px solid rgba(255,255,255,.04); +} +.hero__decor::after { + content: ''; position: absolute; inset: 120px; border-radius: 50%; + border: 1px solid rgba(255,255,255,.03); +} + +.hero__content { position: relative; z-index: 1; padding-block: 120px 80px; } + +.hero__title { + font-size: clamp(2.8rem, 6vw, 5rem); + font-weight: 700; color: #fff; line-height: 1.1; + max-width: 680px; margin-bottom: 24px; +} +.hero__title em { font-style: italic; color: var(--amber-light); } + +.hero__subtitle { + font-size: 1.1rem; color: rgba(255,255,255,.68); + max-width: 500px; line-height: 1.8; margin-bottom: 40px; +} + +.hero__actions { display: flex; gap: 12px; flex-wrap: wrap; } + +.hero__scroll { + position: absolute; bottom: 40px; left: 50%; transform: translateX(-50%); + display: flex; flex-direction: column; align-items: center; gap: 8px; + color: rgba(255,255,255,.3); font-size: .7rem; letter-spacing: .12em; text-transform: uppercase; +} +.hero__scroll-line { + width: 1px; height: 40px; + background: linear-gradient(to bottom, rgba(255,255,255,.25), transparent); + animation: scrollLine 2s ease-in-out infinite; +} +@keyframes scrollLine { + 0%, 100% { transform: scaleY(1); opacity: .35; } + 50% { transform: scaleY(.65); opacity: .7; } +} + +/* ─── Module Hero (inner pages) ─────────────────────────── */ +.module-hero { + min-height: 56vh; display: flex; align-items: flex-end; + padding-top: var(--nav-h); position: relative; overflow: hidden; +} + +.module-hero__content { position: relative; z-index: 1; padding-block: 64px 72px; } +.module-hero__title { color: #fff; margin-bottom: 16px; } +.module-hero__tagline { color: rgba(255,255,255,.65); font-size: 1.05rem; max-width: 480px; margin-bottom: 32px; } + +.module-hero__tag { + display: inline-flex; align-items: center; gap: 6px; + background: rgba(255,255,255,.12); backdrop-filter: blur(8px); + border: 1px solid rgba(255,255,255,.18); border-radius: var(--r-full); + padding: 6px 14px; font-size: .75rem; font-weight: 800; + letter-spacing: .1em; text-transform: uppercase; + color: rgba(255,255,255,.85); margin-bottom: 20px; +} + +/* ─── Cards ──────────────────────────────────────────────── */ +.card { + background: #fff; border-radius: var(--r-lg); overflow: hidden; + box-shadow: var(--sh-sm); border: 1px solid var(--earth-100); + transition: transform .3s var(--ease), box-shadow .3s var(--ease); +} +.card:hover { transform: translateY(-6px); box-shadow: var(--sh-xl); } + +.card--module { display: flex; flex-direction: column; } + +/* ─── Ecosystem Mosaic Grid ──────────────────────────────── */ +.ecosystem-mosaic { + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-auto-rows: 1fr; + gap: 24px; +} +.ecosystem-mosaic__item--featured { grid-column: span 2; } +@media (max-width: 1024px) { + .ecosystem-mosaic { grid-template-columns: repeat(2, 1fr); } +} +@media (max-width: 640px) { + .ecosystem-mosaic { grid-template-columns: 1fr; } + .ecosystem-mosaic__item--featured { grid-column: span 1; } +} + +/* ─── Card Cover (replaces icon) ────────────────────────── */ +.card__cover { + height: 180px; + position: relative; + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; +} +.card__cover--tall { height: 244px; } + +/* Decorative organic blobs inside cover */ +.card__cover-blob { + position: absolute; + border-radius: 50%; + pointer-events: none; +} + +/* Icon at top-left */ +.card__cover-emoji { + font-size: 2.6rem; + position: absolute; + top: 16px; + left: 18px; + z-index: 2; + filter: drop-shadow(0 4px 10px rgba(0,0,0,.18)); + transition: transform .3s var(--ease); + line-height: 1; +} +.card:hover .card__cover-emoji { transform: scale(1.08); } + +/* Badge putih untuk logo resmi modul (kontras terjaga di atas cover gelap apa pun warnanya) */ +.card__cover-logo-badge { + position: relative; + z-index: 3; + background: #fff; + border-radius: var(--r-lg); + padding: 12px 18px; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 8px 24px rgba(0,0,0,.22); + max-width: 76%; + max-height: 68%; + transition: transform .3s var(--ease); +} +.card__cover-logo-badge img { display: block; max-width: 100%; object-fit: contain; } +.card:hover .card__cover-logo-badge { transform: scale(1.06); } + +/* Tag at bottom of cover */ +.card__cover-tag { + position: absolute; + bottom: 0; left: 0; right: 0; + padding: 8px 18px; + background: linear-gradient(to top, rgba(0,0,0,.35) 0%, transparent 100%); + font-size: .65rem; + font-weight: 800; + letter-spacing: .14em; + text-transform: uppercase; + color: rgba(255,255,255,.9); + z-index: 3; +} + +.card__body { padding: 20px 22px 20px; flex: 1; } +.card__title { font-size: 1.2rem; margin-bottom: 8px; } +.card__desc { font-size: .875rem; color: var(--text-300); line-height: 1.65; } + +.card__footer { + padding: 12px 22px 16px; + display: flex; align-items: center; justify-content: space-between; +} +.card__link { + font-size: .875rem; font-weight: 700; + display: flex; align-items: center; gap: 6px; transition: gap .2s; +} +.card:hover .card__link { gap: 10px; } + +/* ─── Feature Card ───────────────────────────────────────── */ +.feature-card { + padding: 28px 24px; border-radius: var(--r-lg); + background: #fff; border: 1px solid var(--earth-100); + transition: transform .3s var(--ease), box-shadow .3s var(--ease); +} +.feature-card:hover { transform: translateY(-3px); box-shadow: var(--sh-md); } +.feature-card__icon { + width: 48px; height: 48px; border-radius: var(--r-md); + display: flex; align-items: center; justify-content: center; + font-size: 1.35rem; margin-bottom: 16px; +} +.feature-card__title { font-size: 1.05rem; margin-bottom: 8px; } +.feature-card__desc { font-size: .875rem; color: var(--text-300); } + +/* ─── Value Card ─────────────────────────────────────────── */ +.value-card { text-align: center; padding: 28px 16px; } +.value-card__icon { font-size: 2.2rem; margin-bottom: 12px; } +.value-card__title { font-size: 1.05rem; color: #fff; margin-bottom: 8px; font-family: var(--font-heading); } +.value-card__desc { font-size: .82rem; color: rgba(255,255,255,.55); line-height: 1.55; } + +/* ─── About Split ────────────────────────────────────────── */ +.about-split { + display: grid; grid-template-columns: 1fr 1fr; gap: 80px; align-items: center; +} +.about-split__text h2 { margin-bottom: 20px; } +.about-split__text p { margin-bottom: 16px; font-size: 1.05rem; line-height: 1.85; color: var(--text-500); } +.about-split__visual { position: relative; display: flex; justify-content: center; } + +.about-orb { + width: 300px; height: 300px; border-radius: 50%; + background: linear-gradient(135deg, var(--maroon-200), var(--earth-300)); + opacity: .25; +} +.about-orb-inner { + position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); + width: 220px; height: 220px; border-radius: 50%; + background: linear-gradient(135deg, var(--amber-light), var(--coral-light)); + opacity: .2; +} + +.about-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; margin-top: 48px; } +.about-stat { + text-align: center; padding: 24px 16px; background: #fff; border-radius: var(--r-md); +} +.about-stat:first-child { border-radius: var(--r-md) 0 0 var(--r-md); } +.about-stat:last-child { border-radius: 0 var(--r-md) var(--r-md) 0; } +.about-stat__num { font-family: var(--font-mono); font-size: 2.2rem; font-weight: 600; color: var(--terracotta); display: block; } +.about-stat__label { font-size: .78rem; color: var(--text-300); margin-top: 4px; } + +@media (max-width: 768px) { + .about-split { grid-template-columns: 1fr; gap: 8px; } + .about-split__visual { order: -1; } +} + +/* ─── Sections ───────────────────────────────────────────── */ +.values-section { background: var(--maroon-900); } +.values-section .section__header h2 { color: rgba(255,255,255,.95); } +.values-section .section__header p { color: rgba(255,255,255,.45); } +.values-section .eyebrow { color: var(--amber); } + +.cta-section { + background: linear-gradient(135deg, var(--maroon-900) 0%, var(--maroon-800) 50%, #3A2430 100%); + text-align: center; position: relative; overflow: hidden; +} +.cta-section::before { + content: ''; position: absolute; inset: 0; + background: radial-gradient(ellipse 80% 80% at 50% 50%, rgba(240,180,41,.06) 0%, transparent 65%); +} +.cta-section__content { position: relative; z-index: 1; max-width: 600px; margin-inline: auto; } +.cta-section__title { color: #fff; margin-bottom: 16px; } +.cta-section__desc { color: rgba(255,255,255,.68); font-size: 1.05rem; margin-bottom: 40px; } +.cta-section__actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } + +/* ─── Footer ─────────────────────────────────────────────── */ +.footer { background: var(--maroon-950); color: rgba(255,255,255,.6); padding-top: 64px; } + +.footer__grid { + display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 48px; + padding-bottom: 48px; border-bottom: 1px solid rgba(255,255,255,.07); +} +.footer__brand-logo { + font-family: var(--font-body); font-size: 1.5rem; font-weight: 800; + color: #fff; margin-bottom: 12px; display: block; letter-spacing: -.01em; +} +.footer__brand-desc { font-size: .875rem; line-height: 1.75; max-width: 280px; } +.footer__heading { + font-size: .68rem; font-weight: 800; letter-spacing: .14em; + text-transform: uppercase; color: rgba(255,255,255,.35); margin-bottom: 16px; +} +.footer__links { display: flex; flex-direction: column; gap: 8px; } +.footer__link { font-size: .875rem; color: rgba(255,255,255,.55); transition: color .2s; } +.footer__link:hover { color: #fff; } +.footer__bottom { + padding: 20px 0; display: flex; align-items: center; justify-content: space-between; + font-size: .8rem; color: rgba(255,255,255,.3); +} +.footer__socials { display: flex; gap: 10px; } +.footer__social { + width: 34px; height: 34px; border-radius: var(--r-full); + background: rgba(255,255,255,.07); + display: flex; align-items: center; justify-content: center; + font-size: .8rem; color: rgba(255,255,255,.55); transition: background .2s, color .2s; +} +.footer__social:hover { background: var(--maroon-600); color: #fff; } + +@media (max-width: 1024px) { .footer__grid { grid-template-columns: 1fr 1fr; } } +@media (max-width: 640px) { + .footer__grid { grid-template-columns: 1fr; gap: 32px; } + .footer__bottom { flex-direction: column; gap: 10px; text-align: center; } +} + +/* ─── Module Inner Page ──────────────────────────────────── */ +.breadcrumb { + display: flex; align-items: center; gap: 8px; + font-size: .78rem; color: rgba(255,255,255,.45); margin-bottom: 16px; +} +.breadcrumb a { color: rgba(255,255,255,.45); transition: color .2s; } +.breadcrumb a:hover { color: rgba(255,255,255,.85); } + +/* ─── Contact ────────────────────────────────────────────── */ +.contact-grid { display: grid; grid-template-columns: 1fr 1.6fr; gap: 48px; align-items: start; } +.contact-info__item { display: flex; gap: 16px; align-items: flex-start; margin-bottom: 24px; } +.contact-info__icon { + width: 44px; height: 44px; flex-shrink: 0; border-radius: var(--r-md); + background: var(--maroon-50); + display: flex; align-items: center; justify-content: center; font-size: 1.2rem; +} +.contact-info__label { font-size: .72rem; font-weight: 800; text-transform: uppercase; letter-spacing: .08em; color: var(--text-300); margin-bottom: 2px; } +.contact-info__value { font-size: .95rem; color: var(--text-700); } + +.contact-form { background: #fff; padding: 36px; border-radius: var(--r-xl); border: 1px solid var(--earth-100); box-shadow: var(--sh-md); } +.form-group { margin-bottom: 20px; } +.form-label { display: block; font-size: .875rem; font-weight: 700; color: var(--text-700); margin-bottom: 6px; } +.form-input, .form-select, .form-textarea { + width: 100%; padding: 12px 16px; border: 1.5px solid var(--earth-200); + border-radius: var(--r-md); font-family: inherit; font-size: .9rem; + color: var(--text-700); background: var(--warm-white); + transition: border-color .2s, box-shadow .2s; outline: none; +} +.form-input:focus, .form-select:focus, .form-textarea:focus { + border-color: var(--maroon-400); box-shadow: 0 0 0 3px rgba(92,26,26,.1); +} +.form-textarea { resize: vertical; min-height: 120px; } +.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } + +@media (max-width: 768px) { + .contact-grid { grid-template-columns: 1fr; } + .contact-form { padding: 24px; } + .form-row { grid-template-columns: 1fr; } +} + +/* ─── Space Booking ──────────────────────────────────────── */ +.spaces-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 24px; +} + +.space-card { + background: #fff; + border-radius: var(--r-lg); + overflow: hidden; + border: 1px solid var(--earth-100); + box-shadow: var(--sh-sm); + display: flex; + flex-direction: column; + transition: transform .3s var(--ease), box-shadow .3s var(--ease); +} +.space-card:hover { transform: translateY(-4px); box-shadow: var(--sh-lg); } + +.space-card__cover { + height: 160px; + position: relative; + display: flex; + align-items: flex-start; + justify-content: flex-start; + padding: 16px; + overflow: hidden; +} + +.space-card__icon { + font-size: 2.4rem; + position: relative; + z-index: 2; + filter: drop-shadow(0 4px 10px rgba(0,0,0,.25)); +} + +.space-card__cover-tag { + position: absolute; + bottom: 12px; right: 14px; + font-size: .7rem; font-weight: 700; + letter-spacing: .06em; + color: #fff; + background: rgba(0,0,0,.3); + backdrop-filter: blur(6px); + padding: 4px 10px; + border-radius: var(--r-full); + border: 1px solid rgba(255,255,255,.2); +} + +.space-card__body { padding: 20px 20px 12px; flex: 1; } +.space-card__name { font-size: 1.15rem; margin-bottom: 6px; } +.space-card__desc { font-size: .85rem; color: var(--text-300); line-height: 1.6; margin-bottom: 14px; } + +.space-card__meta { + display: flex; gap: 14px; flex-wrap: wrap; + font-size: .78rem; color: var(--text-300); + margin-bottom: 14px; +} +.space-card__meta span { + display: flex; align-items: center; gap: 4px; +} + +.space-card__facilities { display: flex; flex-wrap: wrap; gap: 6px; } +.space-facility-tag { + font-size: .68rem; font-weight: 700; + padding: 3px 9px; border-radius: var(--r-full); + background: var(--maroon-50); color: var(--maroon-700); +} +.space-facility-tag--more { + background: var(--earth-100); color: var(--earth-700); +} + +.space-card__footer { + padding: 14px 20px; + border-top: 1px solid var(--earth-100); + display: flex; align-items: center; justify-content: space-between; +} +.space-card__price { font-family: var(--font-heading); font-size: 1.2rem; font-weight: 700; color: var(--maroon-700); } +.space-card__price-unit { font-size: .78rem; color: var(--text-300); } + +/* ─── Modal ──────────────────────────────────────────────── */ +.modal-overlay { + position: fixed; inset: 0; z-index: 200; + background: rgba(30,10,10,.55); + backdrop-filter: blur(6px); + display: flex; align-items: center; justify-content: center; + padding: 24px; + overflow-y: auto; +} + +.modal { + background: var(--warm-white); + border-radius: var(--r-xl); + width: 100%; max-width: 580px; + max-height: 90vh; + overflow-y: auto; + box-shadow: var(--sh-xl); + display: flex; flex-direction: column; +} + +.modal__header { + display: flex; align-items: flex-start; justify-content: space-between; + padding: 24px 28px 0; + gap: 16px; +} + +.modal__close { + background: none; border: none; + color: var(--text-300); padding: 4px; + border-radius: var(--r-sm); + transition: color .2s, background .2s; + flex-shrink: 0; +} +.modal__close:hover { color: var(--text-900); background: var(--earth-100); } + +.modal__steps { + display: flex; gap: 0; padding: 20px 28px 0; +} +.modal__step { + display: flex; align-items: center; gap: 8px; + flex: 1; + font-size: .78rem; font-weight: 600; color: var(--text-100); + position: relative; +} +.modal__step::after { + content: ''; + position: absolute; right: 0; top: 12px; + width: calc(100% - 80px); height: 1px; + background: var(--earth-200); +} +.modal__step:last-child::after { display: none; } + +.modal__step--active { color: var(--maroon-700); } +.modal__step--done { color: var(--sage); } + +.modal__step-num { + width: 24px; height: 24px; flex-shrink: 0; + border-radius: 50%; + background: var(--earth-100); + display: flex; align-items: center; justify-content: center; + font-size: .72rem; font-weight: 800; +} +.modal__step--active .modal__step-num { background: var(--maroon-700); color: #fff; } +.modal__step--done .modal__step-num { background: var(--sage); color: #fff; } + +.modal__body { padding: 24px 28px 28px; } + +/* Booking summary block */ +.booking-summary { + background: var(--cream); + border-radius: var(--r-md); + padding: 16px 20px; + margin-top: 16px; + border: 1px solid var(--earth-200); +} +.booking-summary__row { + display: flex; justify-content: space-between; gap: 12px; + font-size: .85rem; padding: 6px 0; + border-bottom: 1px solid var(--earth-100); + color: var(--text-500); +} +.booking-summary__row:last-child { border-bottom: none; } +.booking-summary__row span:first-child { color: var(--text-300); } +.booking-summary__row--total { + font-weight: 700; color: var(--maroon-700) !important; + font-size: .95rem; padding-top: 10px; margin-top: 4px; +} +.booking-summary__row--total span { color: var(--maroon-700) !important; } + +/* ─── Misc ───────────────────────────────────────────────── */ +.page-top-pad { padding-top: var(--nav-h); } + +.team-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 20px; } +.team-card { text-align: center; padding: 24px 16px; background: #fff; border-radius: var(--r-lg); border: 1px solid var(--earth-100); } +.team-card__avatar { + width: 76px; height: 76px; border-radius: 50%; + background: linear-gradient(135deg, var(--maroon-200), var(--amber-light)); + display: flex; align-items: center; justify-content: center; + font-size: 1.8rem; margin: 0 auto 12px; +} +.team-card__name { font-size: 1rem; margin-bottom: 4px; } +.team-card__role { font-size: .8rem; color: var(--text-300); } + +.badge { display: inline-flex; align-items: center; gap: 5px; padding: 5px 12px; border-radius: var(--r-full); font-size: .75rem; font-weight: 700; } +.badge--maroon { background: var(--maroon-100); color: var(--maroon-800); } +.badge--earth { background: var(--earth-100); color: var(--earth-800); } + +html { scroll-behavior: smooth; scroll-padding-top: var(--nav-h); } + +@keyframes fadeUp { + from { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); } +} +.animate-up { animation: fadeUp .65s var(--ease) both; } +.delay-1 { animation-delay: .1s; } +.delay-2 { animation-delay: .2s; } +.delay-3 { animation-delay: .3s; } + +/* ─── Motion safety net ──────────────────────────────────── */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: .01ms !important; + animation-iteration-count: 1 !important; + transition-duration: .01ms !important; + scroll-behavior: auto !important; + } +} diff --git a/src/lib/api.ts b/src/lib/api.ts new file mode 100644 index 0000000..312ba10 --- /dev/null +++ b/src/lib/api.ts @@ -0,0 +1,147 @@ +const BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'; + +function getToken(): string | null { + return localStorage.getItem('admin_token'); +} + +function authHeaders(): Record { + const token = getToken(); + return token ? { Authorization: `Bearer ${token}` } : {}; +} + +async function request(path: string, options: RequestInit = {}): Promise { + const res = await fetch(`${BASE_URL}${path}`, { + ...options, + headers: { + 'Content-Type': 'application/json', + ...authHeaders(), + ...(options.headers || {}), + }, + }); + if (!res.ok) { + const err = await res.json().catch(() => ({ detail: res.statusText })); + throw new Error(err.detail || 'Request gagal'); + } + return res.json(); +} + +export interface ContentBlock { + id: number; + page: string; + section: string; + key: string; + value: string | null; + content_type: string; + created_at: string; + updated_at: string; +} + +export interface MediaFile { + id: number; + filename: string; + original_name: string; + file_url: string; + file_type: string | null; + purpose: string | null; + created_at: string; +} + +export interface AdminUser { + id: number; + username: string; + is_active: boolean; + created_at: string; +} + +export const api = { + async login(username: string, password: string): Promise { + const data = await request<{ access_token: string }>('/api/auth/login', { + method: 'POST', + body: JSON.stringify({ username, password }), + }); + localStorage.setItem('admin_token', data.access_token); + return data.access_token; + }, + + logout() { + localStorage.removeItem('admin_token'); + }, + + isLoggedIn(): boolean { + return !!getToken(); + }, + + async getContent(page?: string): Promise { + const qs = page ? `?page=${page}` : ''; + return request(`/api/content/${qs}`); + }, + + async upsertContent(data: Omit): Promise { + return request('/api/content/', { + method: 'PUT', + body: JSON.stringify(data), + }); + }, + + async updateContent(id: number, value: string): Promise { + return request(`/api/content/${id}`, { + method: 'PATCH', + body: JSON.stringify({ value }), + }); + }, + + async getMedia(): Promise { + return request('/api/media/'); + }, + + async uploadMedia(file: File, purpose?: string): Promise { + const formData = new FormData(); + formData.append('file', file); + if (purpose) formData.append('purpose', purpose); + const res = await fetch(`${BASE_URL}/api/media/upload`, { + method: 'POST', + headers: authHeaders(), + body: formData, + }); + if (!res.ok) { + const err = await res.json().catch(() => ({ detail: res.statusText })); + throw new Error(err.detail || 'Upload gagal'); + } + return res.json(); + }, + + async deleteMedia(id: number): Promise { + await request(`/api/media/${id}`, { method: 'DELETE' }); + }, + + mediaUrl(path: string): string { + if (path.startsWith('http')) return path; + return `${BASE_URL}${path}`; + }, + + async getUsers(): Promise { + return request('/api/users/'); + }, + + async createUser(username: string, password: string): Promise { + return request('/api/users/', { + method: 'POST', + body: JSON.stringify({ username, password }), + }); + }, + + async deleteUser(id: number): Promise { + await request(`/api/users/${id}`, { method: 'DELETE' }); + }, + + async toggleUser(id: number): Promise { + return request(`/api/users/${id}/toggle`, { method: 'PATCH' }); + }, + + async changePassword(current_password: string, new_password: string): Promise { + await request('/api/users/change-password', { + method: 'POST', + body: JSON.stringify({ current_password, new_password }), + }); + }, +}; diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..bef5202 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/src/pages/Bergabung.tsx b/src/pages/Bergabung.tsx new file mode 100644 index 0000000..077f896 --- /dev/null +++ b/src/pages/Bergabung.tsx @@ -0,0 +1,99 @@ +import { Link } from 'react-router-dom'; +import { ArrowRight, Check } from 'lucide-react'; + +const jalanList = [ + { + icon: '🌾', + title: 'Jalan Komunitas', + color: 'var(--forest-600)', + desc: 'Untuk siapa pun yang ingin hadir, belajar, dan tumbuh bersama — petani, pemelajar, praktisi pangan, pegiat sandang berkelanjutan.', + points: ['Ngobrol santai', 'Belajar bersama', 'Workshop', 'Praktik lapangan', 'Partisipasi Pasar Bahagia', 'Riset'], + cta: 'Daftarkan Diri Anda', + }, + { + icon: '🤝', + title: 'Jalan Kemitraan', + color: 'var(--maroon-600)', + desc: 'Untuk organisasi, lembaga, dan individu yang ingin mendukung ekosistem secara struktural.', + points: ['Kemitraan Program', 'Kemitraan Pendanaan', 'Kemitraan Kelembagaan'], + cta: 'Mulai Perbincangan Kemitraan', + }, + { + icon: '✨', + title: 'Jalan Berkarya', + color: 'var(--earth-700)', + desc: 'Untuk individu, kelompok, atau organisasi dengan gagasan/inisiatif selaras misi Anindhaloka.', + points: ['Co-program', 'Co-event', 'Inisiatif bersama komunitas lokal'], + cta: 'Ceritakan Gagasan Anda', + }, +]; + +export default function Bergabung() { + return ( +
+ {/* Hero */} +
+
+
+

Bergabung & Berkolaborasi

+

Rumah gotong royong,
terbuka bagi siapa saja

+

+ Tidak ada satu cara tunggal untuk menjadi bagian — yang penting ada keselarasan nilai, niat, dan cara memandang masa depan. +

+
+
+ + {/* Three paths */} +
+
+
+ {jalanList.map((j, i) => ( +
+
{j.icon}
+

{j.title}

+

{j.desc}

+
    + {j.points.map((p, k) => ( +
  • + {p} +
  • + ))} +
+ + {j.cta} + +
+ ))} +
+
+
+ + {/* Closing invitation */} +
+
+ 🌾 +
+ "Kami tidak mengundang Anda untuk mendukung sebuah organisasi. Kami mengundang Anda untuk ikut merawat sesuatu yang kita semua butuhkan — cara hidup yang lebih selaras dengan bumi, lebih jujur pada sesama, dan lebih sadar pada setiap pilihan yang kita buat sehari-hari." +
+

+ Dari mana pun Anda datang dan apa pun yang Anda bawa — selamat datang di rumah ini. +

+ + Hubungi Kami + +
+
+
+ ); +} diff --git a/src/pages/BhumiAnindha.tsx b/src/pages/BhumiAnindha.tsx new file mode 100644 index 0000000..2586b6d --- /dev/null +++ b/src/pages/BhumiAnindha.tsx @@ -0,0 +1,8 @@ +import ModulePage from '../components/ModulePage'; +import modules from '../data/modules'; + +const module = modules.find(m => m.id === 'bhumi-anindha')!; + +export default function BhumiAnindha() { + return ; +} diff --git a/src/pages/CittaRahayu.tsx b/src/pages/CittaRahayu.tsx new file mode 100644 index 0000000..0ac32b7 --- /dev/null +++ b/src/pages/CittaRahayu.tsx @@ -0,0 +1,8 @@ +import ModulePage from '../components/ModulePage'; +import modules from '../data/modules'; + +const module = modules.find(m => m.id === 'citta-rahayu')!; + +export default function CittaRahayu() { + return ; +} diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx new file mode 100644 index 0000000..a13a098 --- /dev/null +++ b/src/pages/Home.tsx @@ -0,0 +1,368 @@ +import { Link } from 'react-router-dom'; +import { ArrowRight, ArrowDown } from 'lucide-react'; +import { motion } from 'framer-motion'; +import modules from '../data/modules'; +import IDGWheel from '../components/IDGWheel'; +import EcosystemIcon from '../components/EcosystemIcons'; +import ArcDivider from '../components/ArcDivider'; +import Reveal from '../components/Reveal'; +import TiltCard from '../components/TiltCard'; +import CountUp from '../components/CountUp'; + +const EASE_ORGANIC = [0.22, 1, 0.36, 1] as const; + +const values = [ + { icon: '🧠', title: 'Kesadaran', desc: 'Setiap tindakan dilandasi kehadiran penuh dan niat yang jernih.' }, + { icon: '🌿', title: 'Hubungan dengan Alam', desc: 'Menghormati dan memulihkan hubungan kita dengan dunia alami.' }, + { icon: '🤲', title: 'Gotong Royong', desc: 'Kekuatan komunitas adalah fondasi dari setiap perubahan nyata.' }, + { icon: '♻️', title: 'Keberlanjutan', desc: 'Memilih jalan yang merawat, bukan menguras, sumber daya bumi.' }, + { icon: '🌱', title: 'Regeneratif', desc: 'Melampaui keberlanjutan—memulihkan dan menghidupkan kembali.' }, + { icon: '⚖️', title: 'Keadilan Sosial', desc: 'Ekonomi dan ekologi yang adil bagi semua makhluk hidup.' }, + { icon: '💚', title: 'Komunitas', desc: 'Bersama kita tumbuh lebih kuat, lebih bijak, lebih utuh.' }, + { icon: '✨', title: 'Keindahan', desc: 'Merayakan keindahan dalam kesederhanaan dan keaslian.' }, +]; + +const jalurList = [ + { + id: 'pangan', + icon: '🌾', + title: 'Pangan Berkesadaran', + subtitle: 'Merawat Tanah, Menumbuhkan Kehidupan', + color: '#4F6B3A', + steps: ['Budidaya', 'Panen & Pasca Panen', 'Gastronomi & Kuliner', 'Destinasi & Pengalaman'], + quote: 'Merawat tanah adalah merawat diri.', + }, + { + id: 'sandang', + icon: '🧵', + title: 'Sandang Berkesadaran', + subtitle: 'Menghidupkan Serat, Menenun Masa Depan', + color: '#D4552B', + steps: ['Serat', 'Benang & Kain', 'Pewarnaan', 'Produk Jadi'], + quote: 'Menenun masa depan adalah memilih dunia seperti apa yang ingin kita wariskan.', + }, + { + id: 'olah-diri', + icon: '🧘', + title: 'Olah-Diri Berkesadaran', + subtitle: 'Merawat Diri, Merawat Dunia', + color: '#93583A', + steps: ['Badan Kasar', 'Badan Halus', 'Badan Penyebab'], + quote: 'Manusia yang utuh adalah manusia yang mampu merawat dunia di sekitarnya.', + }, +]; + +const FEATURED_IDX = [0, 4]; + +const heroContainer = { + hidden: {}, + show: { transition: { staggerChildren: 0.14, delayChildren: 0.1 } }, +}; +const heroItem = { + hidden: { opacity: 0, y: 26 }, + show: { opacity: 1, y: 0, transition: { duration: 0.75, ease: EASE_ORGANIC } }, +}; + +export default function Home() { + return ( + <> + {/* Hero */} +
+
+ + + Rumah Gotong Royong + + + Anindha. Loka.
+ Dua kata, satu niat. +
+ + Ruang hidup gotong royong untuk menghadirkan kerahayuan dalam kehidupan sehari-hari — melalui pangan, sandang, dan olah diri yang berkesadaran. + + + + Jelajahi Ekosistem + + + Kenali Anindhaloka + + +
+
+
+ Gulir +
+
+ + {/* Definisi clip-path lengkung halus (bezier) untuk foto About — objectBoundingBox supaya tetap responsif */} + + + {/* About — foto sendiri yang bergelombang di atas, bukan divider warna terpisah */} +
+
+
+ +

Tentang Anindhaloka

+

Ruang yang mulia, dibangun dengan kesadaran

+

+ Anindhaloka adalah ruang yang mulia — bukan karena megah, tapi karena setiap sudutnya dibangun dengan kesadaran: bahwa cara kita hidup menentukan dunia yang kita wariskan. Lahir di jantung Jakarta, kami mengajak siapa saja untuk menjalani hidup dengan cara yang lebih selaras. +

+

+ Kami menghadirkan cara hidup yang menyatukan kembali manusia dengan alam, dengan sesama, dan dengan dirinya sendiri — di mana makanan tumbuh dari tanah yang dirawat, pakaian dibuat dengan tangan yang sadar, dan ketenangan batin menjadi hak setiap orang. +

+
+ + Kenali Kami + + + Bergabung + +
+
+ + + +
+
+
+ + Jenama Lokal Bergabung +
+
+ + Kegiatan Edukasi Terselenggara +
+
+ + Kunjungan TemanNIN +
+
+
+
+ + + {/* Tiga Jalan Bertumbuh Bersama */} +
+
+
+

Tiga Jalan Bertumbuh Bersama

+

Satu perjalanan, tiga laku berkesadaran

+

Pangan, sandang, dan olah diri — tiga jalur praktik yang saling menopang dalam kehidupan sehari-hari.

+
+ +
+ {jalurList.map((j, i) => ( + +
+
+ + 0{i + 1} + + + {j.icon} + +
+ +
+

{j.subtitle}

+

{j.title}

+
+ {j.steps.map((s, k) => ( + + + {s} + + {k < j.steps.length - 1 && } + + ))} +
+
+ “{j.quote}” +
+
+
+
+ ))} +
+
+
+ + + {/* Ecosystem Modules */} +
+
+
+

Ekosistem Kami

+

Delapan wahana, satu perjalanan

+

Setiap modul adalah dunia tersendiri, namun saling terjalin dalam satu visi: kehidupan yang lebih sadar, adil, dan indah.

+
+
+ {modules.map((m, i) => { + const featured = FEATURED_IDX.includes(i); + return ( + + + +
+ + {/* ── Cover ── */} +
+
+
+
+ + {m.logoImage ? ( +
+ {m.name} +
+ ) : ( + + + + )} + +
{m.tagline}
+
+ + {/* ── Content ── */} +
+

{m.name}

+

{m.description}

+
+
+ + Pelajari lebih + +
+ +
+ + + + ); + })} +
+
+
+ + + {/* Values */} +
+
+
+

Nilai-nilai Kami

+

Yang menghidupkan setiap langkah

+

Nilai bukan sekadar kata-kata. Ini adalah cara kami berpikir, berkarya, dan berhubungan dengan dunia.

+
+
+ {values.map((v, i) => ( + +
+
{v.icon}
+

{v.title}

+

{v.desc}

+
+
+ ))} +
+
+
+ + + {/* Community Quote */} +
+ + 🌾 +
+ "Kita tidak mewarisi bumi dari nenek moyang kita, kita meminjamnya dari anak cucu kita." +
+

— Pepatah bijak yang menginspirasi gerakan kami

+
+
+ + + {/* CTA */} +
+
+
+

Mulai Perjalananmu

+

Jadilah bagian dari komunitas perubahan

+

+ Bergabunglah dengan ratusan individu, pengrajin, dan pelaku perubahan yang bersama-sama membangun ekosistem hidup yang lebih bermakna. +

+
+ + Daftar Sekarang + + + Pelajari Lebih + +
+
+
+
+ + ); +} diff --git a/src/pages/KaIND.tsx b/src/pages/KaIND.tsx new file mode 100644 index 0000000..42d8283 --- /dev/null +++ b/src/pages/KaIND.tsx @@ -0,0 +1,8 @@ +import ModulePage from '../components/ModulePage'; +import modules from '../data/modules'; + +const module = modules.find(m => m.id === 'kaind')!; + +export default function KaIND() { + return ; +} diff --git a/src/pages/Kontak.tsx b/src/pages/Kontak.tsx new file mode 100644 index 0000000..df4e56a --- /dev/null +++ b/src/pages/Kontak.tsx @@ -0,0 +1,184 @@ +import { useState } from 'react'; +import { ArrowRight } from 'lucide-react'; + +export default function Kontak() { + const [sent, setSent] = useState(false); + + function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + setSent(true); + } + + return ( +
+ {/* Header */} +
+
+
+

Kontak Kami

+

Mari berbicara

+

+ Kami senang mendengar dari Anda. Apakah Anda ingin bergabung, berkolaborasi, atau sekadar ingin tahu lebih banyak—kami ada di sini. +

+
+
+ + {/* Contact Content */} +
+
+
+ {/* Info */} +
+

Informasi Kontak

+ +
+ Kontak umum Anindhaloka (kantor pusat) akan segera tersedia. Untuk saat ini, hubungi tim sesuai inisiatif yang relevan lewat kontak di bawah, atau kirim pesan lewat form — tim kami akan meneruskannya. +
+ +
+
📱
+
+

Pasar Bahagia & LokaNIN

+

+62 815 7330 5808 (Welin Cakra)

+
+
+ +
+
📷
+
+

Instagram

+

@anindhaloka_id · @kreasi.nin

+
+
+ +
+
🌱
+
+

Bhumi Anindha

+

IG @bhumi.anindha (kontak sedang diperbarui)

+
+
+ +
+

+ Ikuti Kami +

+
+ {['📷 Instagram', '📘 Facebook', '▶️ YouTube', '💬 WhatsApp'].map(s => ( + + {s} + + ))} +
+
+ + {/* Map placeholder */} +
+ 🗺️ +

Lokasi akan diinformasikan lebih lanjut

+
+
+ + {/* Form */} +
+ {sent ? ( +
+
🌿
+

Pesan terkirim!

+

+ Terima kasih telah menghubungi kami. Tim Anindhaloka akan merespons dalam 1–2 hari kerja. Sampai jumpa! 🙏 +

+ +
+ ) : ( + <> +

Kirim Pesan

+
+
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ +